将公钥/策略存储在 Lambda 中的 node.js 常量中是否安全

问题描述

我正在 node.js 中编写 AWS lambda 授权器。我们需要调用 Azure AD API 来获取公钥/安全策略以验证传入的访问令牌。

然而,为了优化性能,我决定将公钥/安全策略作为常量存储在 node.js 中(在 Lambda 运行或密钥的 TTL 到期之前,这将处于活动状态)。

问题:从安全角度来看是否安全?我想避免在 DynamoDB 中“缓存”它,因为对 DynamoDB 的调用也会产生额外的毫秒数。我们的应用程序是一个非常高流量的应用程序,我们希望尽可能节省任何毫秒以获得最佳性能。此外,任何最佳实践也受到高度赞赏

解决方法

通常,您不应在代码中硬编码此类内容。尽管这不是安全问题,但它使维护变得更加困难。

例如:当密钥被“轮换”或策略更改并且您在 Lambda 中对其进行了硬编码时,您将需要更新您的代码并进行另一次部署。这通常会导致问题,因为开发人员忘记了这一点等等。由于您的授权人不再工作而导致问题。如果 Lambda 从外部服务(如 S3、SSM 或直接 Azure AD)加载信息,则不需要其他部署。理论上,它应该根据您使用的服务以及您管理密钥的方式等自行解决。

我认为最好的方法是在 Lambda 的初始化阶段从外部服务加载密钥。这意味着当它第一次“启动”,然后在 Lambdas 生命周期(几分钟到几小时)期间缓存该值。

例如,您可以直接从 Azure、S3 或 SSM Parameter Store 加载公钥和策略。

以下代码使用未与 Lambda 运行时捆绑的 AWS SDK NodeJS v3。您也可以使用 SDK 的 v2。

const { SSMClient,GetParameterCommand } = require("@aws-sdk/client-ssm");

// This only happens once,when the Lambda is started for the first time:
const init = async () => {
    const config = {}

    try {
        // use whatever 'paramName' you defined,when you created the SSM parameter
        const paramName = "/azure/publickey"
        const command = new GetParameterCommand({Name: paramName});
        const ssm = new SSMClient();
        const data = await ssm.send(command);
        config["publickey"] = data.Parameter.Value;
    } catch (error) {
        return Promise.reject(new Error("unable to read SSM parameter '"+ paramName + "'."));
    }

    return new Promise((resolve,reject) => {
        resolve(config);
        reject(new Error("unable to create configuration. Unknown error."));
    });
};

const initPromise = init();

exports.handler = async (event) => {
    const config = await initPromise;

    console.log("My public key '%s'",config.key);

    return "Hello World";
};

此代码最重要的一点是 init “函数”,它只运行一次,创建一个“配置”,其中应包含您的 AWS 开发工具包客户端以及您在代码中需要的所有配置。这样,您就不必为 Lambda 正在处理的每个请求等获取策略。