Google Cloud Functions - 使用 Google Source Repository 时如何安全地存储服务帐户私钥?
Google Cloud Functions - How to securely store service account private key when using Google Source Repository?
我使用 Google 源存储库来存储我的 Google 云函数。 (Git 回购由 Google 托管,基本上)
我的一个功能需要访问私人 Google Sheet 文件,因此我创建了一个服务帐户。 (权限太多,因为很难理解我们应该赋予服务帐户哪些确切权限,而且以后很难更新,但我离题了)
现在,显然不建议将服务帐户 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": ""
}
我一直在寻找环境变量来配置函数或类似的东西,但没有找到任何东西。跟踪密钥(因此可能会在多个存储库中复制该文件)听起来确实不是一个好主意。但我还没有找到任何 "proper" 方法来做到这一点。由于 Google 函数的工作方式,除了 env 变量我想不出别的。
您可以将服务帐户文件与您的函数一起上传,并在您的代码中使用它。它将在那里保持安全。大多数开发人员将使用 .gitignore 或等效机制来防止该文件被添加到源代码管理中。有一个从 Firebase samples 加载服务帐户凭据的示例。 (如果您不使用 Firebase SDK,则必须注意将函数定义转换为 Cloud 样式。
您也可以使用环境变量,但在引用和转义值时必须特别小心,以确保它们正确地到达您的函数。这有点麻烦,但可行。
Here 您可以找到如何使用环境变量 GOOGLE_APPLICATION_CREDENTIALS
.
为您的应用程序提供凭据
我就是这样解决这个问题的。首先在文件keys.js中创建一个逻辑来判断你是在开发还是生产(并创建相应的./dev.js和./prod.js文件,其中你应该包含./dev.js in .ignore 文件以确保它没有上传到你的 github 远程):
if (process.env.NODE_ENV === "production") {
module.exports = require("./prod");
} else {
module.exports = require("./dev");
}
其次,您需要上述逻辑所在的 keys.js 文件,并根据从 keys.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
};
现在,对于每个 google 云服务,您都可以使用以下示例模式:
const storage = new Storage({
project_id: credentials.project_id,
credentials
});
const client = new textToSpeech.TextToSpeechClient({
project_id: credentials.project_id,
credentials
});
...
etc.
我将云功能与服务帐户一起使用时的解决方案是:
- 使用 Cloud KMS/vault 加密您的服务帐户凭据 json 文件,并将其上传到 Cloud Storage。
从 Cloud Storage 获取服务帐户凭据 json 文件,并使用具有 encrypt/decrypt 权限的 Cloud KMS 服务帐户对其进行解密。
在运行时解析服务帐户凭据 json 文件并获取 private_key
、client_email
和 projectId
.
将这三个秘密变量传递给客户端库
我们将配置变量存储为云功能的环境变量,它们是纯文本,但没关系。因为它们不是秘密的东西。
我们不能存储明文之类的机密内容,例如云函数环境变量。
我认为您真的不需要在代码中存储任何密钥文件。
您的函数使用指定的服务帐户(通常是“App Engine 默认服务帐户”,但您可以在“高级设置”中更改)运行。如果您有特定需求,您应该创建一个特定于您的功能的服务帐户,并授予它所需的所有权限。
在您的函数中,身份验证将使用 Application Default Credentials 自动进行,因此您不必关心任何事情(忘记环境变量、密钥文件或任何东西)。只需确保您使用的是适用于您的语言的 Google 云客户端库,它们会隐式地为您处理所有事情。
特别是,我避免使用 @slideshowp2 提出的创造性解决方案。但我同意它们有其用途(例如,假设我需要存储外部系统的凭据,超出 GCP 范围。在这种情况下,他的解决方案可能是一种可行的方法),但仅使用 Google 服务, 让我们保持简单。
截至 2020 年 1 月,Google 已发布 Secret Manager, which is described as:
Secret Manager is a new Google Cloud service that provides a secure and convenient method for storing API keys, passwords, certificates, and other sensitive data. Secret Manager provides a central place and single source of truth to manage, access, and audit secrets across Google Cloud.
对于 Cloud Functions,有一个教程 here 介绍如何创建机密然后从 Cloud Function 检索它。
我使用 Google 源存储库来存储我的 Google 云函数。 (Git 回购由 Google 托管,基本上)
我的一个功能需要访问私人 Google Sheet 文件,因此我创建了一个服务帐户。 (权限太多,因为很难理解我们应该赋予服务帐户哪些确切权限,而且以后很难更新,但我离题了)
现在,显然不建议将服务帐户 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": ""
}
我一直在寻找环境变量来配置函数或类似的东西,但没有找到任何东西。跟踪密钥(因此可能会在多个存储库中复制该文件)听起来确实不是一个好主意。但我还没有找到任何 "proper" 方法来做到这一点。由于 Google 函数的工作方式,除了 env 变量我想不出别的。
您可以将服务帐户文件与您的函数一起上传,并在您的代码中使用它。它将在那里保持安全。大多数开发人员将使用 .gitignore 或等效机制来防止该文件被添加到源代码管理中。有一个从 Firebase samples 加载服务帐户凭据的示例。 (如果您不使用 Firebase SDK,则必须注意将函数定义转换为 Cloud 样式。
您也可以使用环境变量,但在引用和转义值时必须特别小心,以确保它们正确地到达您的函数。这有点麻烦,但可行。
Here 您可以找到如何使用环境变量 GOOGLE_APPLICATION_CREDENTIALS
.
我就是这样解决这个问题的。首先在文件keys.js中创建一个逻辑来判断你是在开发还是生产(并创建相应的./dev.js和./prod.js文件,其中你应该包含./dev.js in .ignore 文件以确保它没有上传到你的 github 远程):
if (process.env.NODE_ENV === "production") {
module.exports = require("./prod");
} else {
module.exports = require("./dev");
}
其次,您需要上述逻辑所在的 keys.js 文件,并根据从 keys.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
};
现在,对于每个 google 云服务,您都可以使用以下示例模式:
const storage = new Storage({
project_id: credentials.project_id,
credentials
});
const client = new textToSpeech.TextToSpeechClient({
project_id: credentials.project_id,
credentials
});
...
etc.
我将云功能与服务帐户一起使用时的解决方案是:
- 使用 Cloud KMS/vault 加密您的服务帐户凭据 json 文件,并将其上传到 Cloud Storage。
从 Cloud Storage 获取服务帐户凭据 json 文件,并使用具有 encrypt/decrypt 权限的 Cloud KMS 服务帐户对其进行解密。
在运行时解析服务帐户凭据 json 文件并获取
private_key
、client_email
和projectId
.将这三个秘密变量传递给客户端库
我们将配置变量存储为云功能的环境变量,它们是纯文本,但没关系。因为它们不是秘密的东西。
我们不能存储明文之类的机密内容,例如云函数环境变量。
我认为您真的不需要在代码中存储任何密钥文件。
您的函数使用指定的服务帐户(通常是“App Engine 默认服务帐户”,但您可以在“高级设置”中更改)运行。如果您有特定需求,您应该创建一个特定于您的功能的服务帐户,并授予它所需的所有权限。
在您的函数中,身份验证将使用 Application Default Credentials 自动进行,因此您不必关心任何事情(忘记环境变量、密钥文件或任何东西)。只需确保您使用的是适用于您的语言的 Google 云客户端库,它们会隐式地为您处理所有事情。
特别是,我避免使用 @slideshowp2 提出的创造性解决方案。但我同意它们有其用途(例如,假设我需要存储外部系统的凭据,超出 GCP 范围。在这种情况下,他的解决方案可能是一种可行的方法),但仅使用 Google 服务, 让我们保持简单。
截至 2020 年 1 月,Google 已发布 Secret Manager, which is described as:
Secret Manager is a new Google Cloud service that provides a secure and convenient method for storing API keys, passwords, certificates, and other sensitive data. Secret Manager provides a central place and single source of truth to manage, access, and audit secrets across Google Cloud.
对于 Cloud Functions,有一个教程 here 介绍如何创建机密然后从 Cloud Function 检索它。