如何从一个函数中设置 process.env?

3

如果有更好的“最佳实践”方法,我很乐意学习,但我有一些偶尔需要编辑数据库的脚本,因此我需要传递这些脚本的DB密码。我通过调用一个调用Google云秘密管理器的函数来获取密码,并且我无法将其添加到process.env中。

例如,如果我将以下内容放在我的脚本文件顶部:

process.env.DB_HOST='127.0.0.1';
process.env.DB_USER='michael';
process.env.DB_NAME='staging-db';
process.env.DB_PORT=1234;
process.env.DB_PASS= await accessSecret('projects/myproject-123/secrets/DB_PASS/versions/latest');

当上述代码运行时,我得到以下错误:
SyntaxError: await is only valid in async functions and the top level bodies of modules 但是,如果我将process.env.DB_PASS设置放在我的async main()函数内部,则它具有该主函数的局部作用域。由此脚本中由函数调用的其他文件将process.env.DB_PASS视为未定义(但确实可以看到在文件顶部全局设置的任何process.env变量的值)。
我如何拉入并设置该秘密而不实际将字面秘密粘贴到代码中?
为了表示作用域问题,这里是一个重现该问题的可工作代码。这是我正在运行的脚本文件:
process.env.DB_HOST='127.0.0.1';
process.env.DB_USER='michael';
process.env.DB_NAME='staging-db';
process.env.DB_PORT=1234;
const db = require('../../src/database/process_pull_test');


const main = async () => {
  process.env.SCOPED_KEY = "helloimscoped"
  db.hello();
}

main().catch((e) => {console.error(e)});

这里是 process_pull_test 文件

console.log("SCOPED KEY", process.env.SCOPED_KEY);
const dbHost = process.env.DB_HOST;
const dbUser = process.env.DB_USER;
const dbName = process.env.DB_NAME;
const dbPort = process.env.DB_PORT;
const scopedKey = process.env.SCOPED_KEY;

async function hello() {
  console.log(dbHost);
  console.log(dbUser);
  console.log(dbName);
  console.log(dbPort);
  console.log(scopedKey);
  return console.log("Hello Secrets");
}


module.exports = {
  hello: hello
}

这里是输出结果

SCOPED KEY undefined
127.0.0.1
michael
staging-db
1234
undefined
Hello Secrets
2个回答

2
但是,如果我将process.env.DB_PASS设置移动到我的async main()函数内部,则它具有该主函数的局部作用域。由此脚本中的其他被函数调用的文件将process.env.DB_PASS视为未定义(但确实可以看到在文件顶部全局设置的任何process.env变量值)。
这是不正确的,它将被设置为全局变量。很可能只是您的其他文件在main()运行之前执行。
通常的解决方案是确保在main()中设置环境变量之后,调用所有其他逻辑。这意味着所有逻辑都应在函数中。

1
是的,主文件首先被加载,但是在调用第一个函数之前,所需的模块会在 require 时间运行模块函数之外的代码。 - kevintechie
1
@singmotor,非常好的例子,非常有帮助,并且完美地展示了问题。您正在将常量分配到hello()函数之外。此代码在main()之前运行。尝试将const db*语句移动到hello()函数内部。 - Evert
1
@singmotor 不要依赖这些文件级别的定义,而是使用函数。我认为问题的一部分是你在真正的代码中使用了 export const 这些值。更好的方法是只导出函数并返回所有其他文件需要的数据。 - Evert
1
另一种选择是使用 let,而不是立即创建这些变量,而是从某种 init() 函数中创建它们,然后从您的 main() 中调用该函数。在这种情况下, 需要确保在任何其他内容需要这些值之前实际使用此函数。不过,最安全的方法是直接使用该函数。 - Evert
1
不看你的全部代码,很难说明确的常量/变量应该放在哪里。通常,配置应该从中央位置进行管理并在本地访问。全局常量也是如此,但它们不应该在全局范围内 -- 将它们引入并在本地访问。仅在本地使用的常量可以留在本地文件中。 - kevintechie
显示剩余11条评论

1
通常,您需要使用一些配置工具,例如 dotenvconfig 来管理应用程序设置和密码。请确保不要将密码文件保存在源代码控制中。
要获取数据库密码,您需要异步调用 Google 并在尝试读取需要该数据的任何变量之前获取响应。
我假设您只是从命令行运行此操作。
首先,您需要一个异步 IIFE 来执行主函数:
(async () => {
    // you could put your main code here.
    await main();
})();

接下来,将您的Google秘钥管理器添加到require中。它可以放在任何地方,但您应该确保只调用一次才能访问它。最好在主文件中完成此操作。

const gcsm = require('./secretManager');

然后在主程序中调用你的Google secrets manager。(我是编造API)并设置你的环境变量。当你实际上将异步代码放入其中时,你还需要等待调用db.hello()。在技术上,根据编写的代码,你不需要这样做。

const main = async () => {
  const dbPassword = await gcsm.getSecret('some config location');
  process.env.DB_PASS = dbPassword;
  process.env.SCOPED_KEY = "helloimscoped"
  await db.hello();
}

在 process_pull_test 中的 hello() 函数中,读取环境变量。

async function hello() {
  console.log(process.env.DB_PASS);
  console.log(dbHost);
  console.log(dbUser);
  console.log(dbName);
  console.log(dbPort);
  console.log(scopedKey);
  // note the following line doesn't return anything because
  // console.log returns undefined. You probably want to return a 
  // string value to test for now.
  return console.log("Hello Secrets");
}   

这应该可以帮助您开始。

附加评论:

  • 当您首次在 process_pull_test 中记录 SCOPED_KEY 时,它并没有作用域,只是在 require 时间记录,并且仍然未定义。
  • 当您在 hello() 中记录 scopedKey 时,它仍然未定义,因为您在 process_pull_test 的顶部设置了它。
  • 当您在 main() 中设置 SCOPED_KEY 时,为时已晚,您已经将其保存为 undefined。如果您在记录之前在 hello() 中将 scopedKey 设置为 process.env.SCOPED_KEY,则会看到更新的值。

是的,但这里的要求是我不保存本地机密。我需要从Google Cloud Secrets中提取它。 - singmotor
1
@singmotor 根据你的更新,我更新了我的答案。 - kevintechie
我跟随了你的代码。你的主文件需要数据库。 - kevintechie
所以你是在第一个异步代码块之外导入了db吗?如果是的话,我会遵循你的结构并尝试一下,谢谢! - singmotor
1
通常你需要先进行所有的导入 / 引用。然后是任何你想要在引用时设置的内容(只有依赖于静态操作的代码)。接下来,定义模块功能并将其导出(除了从主文件中导出)。 - kevintechie
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接