我使用 Google Source Repository 来存储我的 Google Cloud Functions。(基本上由谷歌托管的Git repo)
我的一个函数需要访问私人的Google表格文件,因此我创建了一个服务帐户。(权限太多,因为很难理解我们应该给服务帐户提供哪些确切的权利,而且以后很难更新,但我跑题了)
现在,出于显而易见的原因,显然不建议将服务帐户 JSON 文件存储在 git 存储库本身中。这是它的外观(从值中剥离)
{
"type": "service_account",
"project_id": "",
"private_key_id": "",
"private_key": "",
"client_email": "",
"client_id": "",
"auth_uri": "",
"token_uri": "",
"auth_provider_x509_cert_url": "",
"client_x509_cert_url": ""
}
我一直在查看环境变量以配置函数或类似的东西,但没有找到任何东西。跟踪密钥(因此可能会在多个存储库上复制该文件)听起来真的不是一个好主意。但我还没有找到任何"适当"的方法。由于Google Functions的工作方式,除了env变量之外,我想不出其他任何东西。
将云函数与服务帐户一起使用时,我的解决方案是:
- 使用云 KMS/保管库加密您的服务帐户凭据 json 文件,并将其上传到云存储。
-
从云存储获取服务帐户凭据 json 文件,并使用具有加密/解密权限的云 KMS 服务帐户对其进行解密。
-
在运行时解析服务帐户凭据 json 文件并获取
private_key
、client_email
和projectId
。 -
将这三个机密变量传递给客户端库
我们将配置变量存储为云功能的环境变量,它们是纯文本,但没关系。因为它们不是秘密的东西。
我们不能存储像纯文本这样的秘密东西,例如云函数环境变量。
您可以将服务帐户文件与函数一起上传,并在代码中使用它。 它将在那里保持安全。 大多数开发人员将使用 .gitignore 或等效机制来防止将该文件添加到源代码管理中。 下面是从 Firebase 示例加载服务帐号凭据的示例。 (如果您没有使用 Firebase SDK,则必须注意将函数定义转换为云样式。
您也可以使用 env var,但您必须特别注意引用和转义值,以确保它们正确到达您的函数。 这有点麻烦,但可行。
截至 2020 年 1 月,Google 发布了一个秘密管理器,其描述为:
机密管理器是一项新的 Google Cloud 服务,它提供了一种安全便捷的方法来存储 API 密钥、密码、证书和其他敏感数据。机密管理器提供了一个中心位置和单一事实来源,用于管理、访问和审核 Google Cloud 中的机密。
对于云函数,此处有一个教程,介绍如何创建密钥,然后从云函数中检索密钥。
在这里,您可以找到如何使用环境变量GOOGLE_APPLICATION_CREDENTIALS
向应用程序提供凭据。
这就是我解决这个问题的方式。首先在文件键中创建一个逻辑.js以确定您是在开发还是生产中(并创建相应的 ./dev.js 和 ./prod.js 文件,您应该在 .ignore 文件中包含 ./dev.js 以确保它不会上传到您的 GitHub 远程):
if (process.env.NODE_ENV === "production") {
module.exports = require("./prod");
} else {
module.exports = require("./dev");
}
其次,您需要上述逻辑所在的密钥.js文件,并根据从密钥接收的数据创建一个凭据对象.js:
const credentials = {
type: keys.googleType,
project_id: keys.googleProjectId,
private_key_id: keys.googlePrivateKeyId,
private_key: keys.googlePrivateKey,
client_email: keys.googleClientEmail,
client_id: keys.googleClientId,
auth_uri: keys.googleAuthUri,
token_uri: keys.googleTokenUri,
auth_provider_x509_cert_url: keys.googleAuthProviderX509CertUrl,
client_x509_cert_url: keys.googleClientX509CertUrl
};
现在,对于每个谷歌云服务,您可以使用以下示例模式:
const storage = new Storage({
project_id: credentials.project_id,
credentials
});
const client = new textToSpeech.TextToSpeechClient({
project_id: credentials.project_id,
credentials
});
...
etc.
我认为你真的不需要在你的代码中存储任何密钥文件。
您的函数使用指定的服务帐号(通常是"App Engine 默认服务帐号",但您可以在高级设置中进行更改)运行。 如果您有特定需求,则应创建特定于您的函数的服务帐户,并向其授予所需的所有权限。
在函数中,将使用应用程序默认凭据自动进行身份验证,因此您不必关心任何事情(忘记环境变量、密钥文件或任何内容)。 只要确保您使用的是适用于您的语言的 Google Cloud 客户端库,它们就会隐式为您处理所有事情。
特别是,我避免像@slideshowp2提出的创造性解决方案那样。 但我同意它们有其用途(例如,假设我需要在 GCP 范围之外存储外部系统的凭据。 在这种情况下,他的解决方案可能是一种方式),但要只消费 Google 服务,让我们保持简单。