0

我有一些 JSON 存储在 SSM 参数存储中,我想在我的无服务器框架 lambda 函数中使用它们(包含有关 Terraform 之前生成的基础设施的一些详细信息)。我可以调用 SSM 以在运行时获取数据,但 Parameter Store 的吞吐量限制非常低(默认为 40tps),因此我可能几乎立即超过该限制,即使更高的限制仍然太低而无法执行此操作在生产中。

更一般地说,我想避免调用外部服务来检索此信息的开销,因为它将在自定义 lambda 授权器中使用,因此我希望它快速且尽可能不依赖任何外部依赖项。

当我执行serverless deploy. 我很高兴在它们发生变化时必须重新部署我的后端。

我可以使用环境变量,但是所有环境变量的最大大小是 4kb,所以我不能把 JSON 放在那里。

我正在使用Serverless Webpack Plugin,我认为这可能是关键,但我是 Webpack 新手,不知道从哪里开始!

4

1 回答 1

1

也许有更好的方法,但我设法通过编写自定义 webpack loader来实现它。这个答案专门针对我需要将多个 cognito 池的详细信息导出到单个文件以在自定义 lambda 授权程序中使用的情况,但该模式应该适用于任何场景,也不一定与 SSM 相关(你可以使用任何方法生成文件,因为加载器只是普通的 Javascript)。它使我的 Lambda 执行时间从约 40 毫秒(使用 SSM)下降到约 2 毫秒。

模板文件和用法

首先,我创建了一个示例模板 .json 文件,其结构与我存储在 SSM 中的数据相匹配。这可能在任何地方,但我把它放在generated/cognitoConfig.json. 这对于使用点的文档和代码辅助很有用。

{
    "pools": [
        {
            "_note_": "This is just an example. This file gets totally replaced with the real pool config by cognitoConfigLoader on deploy",
            "clientId":"example-client",
            "name":"example",
            "poolArn":"arn:aws:cognito-idp:eu-west-2:account-id:userpool/example-pool",
            "poolEndpoint":"cognito-idp.eu-west-2.amazonaws.com/example-pool",
            "poolId":"example-pool",
            "poolKeysUrl":"https://cognito-idp.eu-west-2.amazonaws.com/example-pool/.well-known/jwks.json",
            "region":"eu-west-2"
        }
    ]
}

然后可以在 lambda 代码 (ES6) 中导入和使用它。例如:

import * as cognitoData from '../../generated/cognitoConfig.json';

function getPoolConfig(name) {
    const poolConfig = cognitoData.pools.filter(pool => pool.name === name)[0]
}

Webpack 加载器

我配置了一个针对此模板文件运行的自定义 webpack 加载器:

const path = require('path');

module.exports = {
    //...other webpack config

    module: {
        // These execute from bottom to top
        rules: [
            // ...other rules (e.g. babel)

            // Retrieve cognito pool information from SSM and store
            {
                test: /cognitoConfig\.json$/,
                include: path.resolve(__dirname, "generated"),
                loader: path.resolve(__dirname, "webpack-loaders/cognitoConfigLoader.js"),
            },
        ]
    }
}

然后我编写了一个 webpack 加载器,用于搜索所有匹配的 SSM 参数,并将内容写入 JSON 文件。无服务器 webpack 插件提供对底层无服务器对象的访问,因此可以访问当前的 AWS 凭证。

对于奖励积分,我还下载了签名密钥,但我没有在此处包含它,因为我不想弄乱答案:

const slsw = require("serverless-webpack");
const { SSMClient, GetParametersByPathCommand } = require("@aws-sdk/client-ssm")
const { fromIni } = require("@aws-sdk/credential-provider-ini")

module.exports = function () {
    const callback = this.async()

    buildPoolsJson().then(
        poolsJson => callback(undefined, poolsJson),
        error => callback(error)
    )
}

async function buildPoolsJson() {
    const poolsParameters= await loadPoolsParameters()
    return JSON.stringify({
        pools: poolsParameters
    })
}

async function loadPoolsParameters() {
    const awsProvider = slsw.lib.serverless.service.provider
    const ssmClient = new SSMClient({
        credentials: fromIni({ profile: awsProvider.profile }),
        region: awsProvider.region,
    })

    const poolParamsResponse = await ssmClient.send(new GetParametersByPathCommand({
        Path: "/terraform/cognito-pools",
    }))

    return poolParamsResponse.Parameters.map(parameter => {
        return JSON.parse(parameter.Value);
    })
}
于 2021-04-02T21:52:27.327 回答