在Node.JS中从AWS Secrets Manager设置机密

时间:2019-11-02 20:35:09

标签: javascript node.js amazon-web-services

在顶层等待变成事情之前,启动时从AWS Secrets Manager异步加载机密会有点麻烦。我想知道是否有人能提供比我目前更好的解决方案。

启动Node.JS服务器后,我将从AWS Secrets Manager加载所有机密,并将它们设置在配置文件中,这些文件中混合了硬编码的变量和机密。这是一个示例:

在aws.js中

import AWS from 'aws-sdk';
const region = "eu-north-1";

AWS.config.setPromisesDependency();

const client = new AWS.SecretsManager({
    region
});

export const getSecret = async(secretName) => {
    const data = await client.getSecretValue({SecretId: secretName}).promise();
    return data.SecretString;
}

然后在sendgridConfig.js中

import { getSecret } from "./aws";

export default async() => {
    const secret = JSON.parse(await getSecret("sendgridSecret"));
    return {
        APIKey: secret.sendgridKey,
        fromEmail: "some@email.com",
        toEmail: "some@email.com"
    }
}

然后在使用配置的某些文件中:

import { sendgridConfig } from "./sendgridConfig";

const myFunc = () => {
    const sendgridConf = await sendgridConfig();
    ... do stuff with config ...
}

这在异步函数中可以正常工作,但是如果我想在使用硬编码变量的非异步函数中使用相同的设置怎么办?然后这些秘密还没有被获取,我无法使用它们。另外,我必须始终等待秘密。 IMO将来的一个好的解决方案可能是顶级等待,在启动服务器时,服务器将等待AWS的机密,然后再继续操作。我想我可以找到一种方法来阻止主线程并设置机密,但这感觉有些hacker。

有人有更好的解决方案吗?

3 个答案:

答案 0 :(得分:0)

是的,我有同样的问题。从诺言开始后,所有依赖项都需要等待。

一种解决方案是等待所有下游代码运行之后再等待。需要稍微不同的软件体系结构。

例如

export const getSecretAndThenDoStuff = async(secretName) => {
    const data = await client.getSecretValue({SecretId: secretName}).promise();
    // instead of return data.SecretString;
    runYourCodeThatNeedsSecret(data);
}

答案 1 :(得分:0)

我倾向于使用的通用顶级解决方案:

async function main() {
  // Do whatever you want with await here
}

main();

干净简单。

答案 2 :(得分:0)

所以我结束了下面的工作。首先,我在导出的对象文字中设置非异步配置变量。然后,我将值分配给sendgridConfigAsync IIFE中的对象文字(不必是IFEE)。这样,我不必等待配置承诺。只要应用程序在启动时等待IIFE,就会在访问之前分配密钥。

在sendgridConfig.js中

import { getSecret } from "./aws";

export const sendgridConfig = {
    emailFrom: process.env.sendgridFromEmail,
    emailTo: process.env.sendgridToEmail
}

export const sendgridConfigAsync = (async() => {
    const secret = JSON.parse(await getSecret("Sendgrid-dev"));
    sendgridConfig.sendgridKey = secret.key;
})()

然后在主配置文件_index.js中导入所有配置文件。

import { sendgridConfigAsync } from "./sendgrid";
import { twilioConfigAsync } from "./twilio";
import { appConfigAsync } from "./app";

export const setAsyncConfig = async() => {
    await Promise.all([
        appConfigAsync,
        sendgridConfigAsync,
        twilioConfigAsync
    ]);
}

然后在主index.js文件中,我首先等待setAsyncConfig函数。我也确实对应用程序进行了一定程度的重建,以便控制所有功能调用并保证按所需顺序进行解析。

import { servicesConnect } from "../src/service/_index.js";
import { setAsyncConfig } from '$config';
import { asyncHandler } from "./middleware/async";
import { middleware } from "./middleware/_index";
import { initJobs } from "./jobs/_index"
import http from 'http';

async function startServer() {
    await setAsyncConfig();
    await servicesConnect();
    await initJobs();
    app.use(middleware);

    app.server = http.createServer(app);

    app.server.listen(appConfig.port);
    console.log(`Started on port ${app.server.address().port}`);
}

asyncHandler(startServer());