繁体   English   中英

确保在应用程序启动时将 Azure 密钥库机密加载到配置 (node-config)

[英]Ensuring Azure keyvault secrets are loaded to config (node-config) at application startup

我有一个 NodeJS 应用程序,它使用 Node-Config ( https://www.npmjs.com/package/config ) 来加载应用程序配置。 我要做的是在启动期间将机密从 Azure Keyvault 加载到配置中,并确保这些机密在需要之前可用(例如连接到数据库等)。

我可以毫无问题地连接到 Keyvault 并从中检索值,但我正在为 JS 的非阻塞特性而苦苦挣扎。 在配置值完成(异步)加载到配置之前,应用程序启动过程将继续进行。

  • 一种策略可能是延迟应用程序启动以等待密钥库秘密加载如何在节点启动期间主要等待?
  • 另一种方法是不在 Config 中加载它们,而是在任何地方修改代码,以通过 Promise 异步加载这些秘密

看起来这将是一个常见问题,所以我希望这里有人可以提供示例或设计模式,以确保在启动期间加载远程 keyvault 机密的最佳方式。

提前感谢您的建议。

我现在已经成功解决了这个问题。

需要注意的一个关键点是设置 process.env['ALLOW_CONFIG_MUTATIONS']=true; 默认情况下,配置是不可变的(初始设置后无法更改)。 由于 async 稍后会解决这些问题,因此调整此设置至关重要。 否则,您将看到异步配置从密钥库中获取正确的值,但是当您使用 config.get 检查时,它们不会被设置。 这确实应该添加到https://github.com/node-config/node-config/wiki/Asynchronous-Configurations的文档中

我的解决方案:首先,让我们为 Azure 密钥库客户端创建一个模块 - azure-keyvault.mjs :

import { DefaultAzureCredential } from '@azure/identity';
import { SecretClient } from '@azure/keyvault-secrets';

// https://docs.microsoft.com/en-us/azure/developer/javascript/how-to/with-web-app/use-secret-environment-variables
if (
  !process.env.AZURE_TENANT_ID ||
  !process.env.AZURE_CLIENT_ID ||
  !process.env.AZURE_CLIENT_SECRET ||
  !process.env.KEY_VAULT_NAME
) {
  throw Error('azure-keyvault - required environment vars not configured');
}

const credential = new DefaultAzureCredential();

// Build the URL to reach your key vault
const url = `https://${process.env.KEY_VAULT_NAME}.vault.azure.net`;

// Create client to connect to service
const client = new SecretClient(url, credential);

export default client;

在配置(使用@node-config)文件中:

process.env['ALLOW_CONFIG_MUTATIONS']=true;
const asyncConfig = require('config/async').asyncConfig;
const defer = require('config/defer').deferConfig;
const debug = require('debug')('app:config:default');
// example usage debug(`\`CASSANDRA_HOSTS\` environment variable is ${databaseHosts}`);

async function getSecret(secretName) {
  const client = await (await (import('../azure/azure-keyvault.mjs'))).default;
  const secret = await client.getSecret(secretName);
  // dev: debug(`Get Async config: ${secretName} : ${secret.value}`);
  return secret.value
}

module.exports = {
  //note: defer just calculates this config at the end of config generation 
  isProduction: defer(cfg => cfg.env === 'production'),

  database: {
    // use asyncConfig to obtain promise for secret
    username: asyncConfig(getSecret('DATABASE-USERNAME')), 
    password: asyncConfig(getSecret('DATABASE-PASSWORD')) 
  },
...
}

最后修改应用程序启动以在调用 config.get 之前解决异步会议

服务器.js

const { resolveAsyncConfigs } = require('config/async');
const config = require('config');
const P = require('bluebird');

...
function initServer() {
  return resolveAsyncConfigs(config).then(() => {
    // if you want to confirm the async configs have loaded
    // try outputting one of them to the console at this point
    console.log('db username: ' + config.get("database.username"));
    // now proceed with any operations that will require configs
    const client = require('./init/database.js');
    // continue with bootstrapping (whatever you code is)
    // in our case let's proceed once the db is ready
    return client.promiseToBeReady().then(function () {
      return new P.Promise(_pBootstrap);
    });
  });
}

我希望这可以帮助其他希望将 config/async 与 Azure 等远程密钥库一起使用的人。 欢迎对以上内容提出意见或改进。

〜棒

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM