也许有更好的方法,但我设法通过编写自定义 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);
})
}