如何在已部署的 Cloud Run Service(托管)中使用 Google Secret?

Posted

技术标签:

【中文标题】如何在已部署的 Cloud Run Service(托管)中使用 Google Secret?【英文标题】:How to use a Google Secret in a deployed Cloud Run Service (managed)? 【发布时间】:2021-04-27 16:05:45 【问题描述】:

我有一个正在运行的云运行服务user-service。出于测试目的,我通过环境变量将客户端机密作为纯文本传递。现在,由于一切正常,我想改用秘密。

在“编辑修订”选项的“变量”选项卡中,我可以声明环境变量,但我不知道如何传递秘密?我只需要在变量的值字段中传递像$my-secret-id 这样的秘密名称吗?此选项卡中没有关于如何使用机密的文档,只有顶部的提示:

Store and consume secrets using Secret Manager

在这种情况下这不是很有帮助。

【问题讨论】:

【参考方案1】:

Google 有您可以在 api 中使用的 Secret manager 客户端库的文档。

这应该可以帮助您做您想做的事 https://cloud.google.com/secret-manager/docs/reference/libraries

由于您没有指定语言,我有一个 nodejs 示例,说明如何使用您的项目 ID 和密码名称访问最新版本的密码。我添加这个的原因是因为文档对您需要作为名称提供的字符串不清楚。

 const [version] = await this.secretClient.accessSecretVersion(
        name: `projects/$process.env.project_id/secrets/$secretName/versions/latest`,
      );
 return version.payload.data.toString()

请务必在您的 IAM 设置中为您的 api 在 GCP 中使用的服务帐户允许秘密管理员访问。

【讨论】:

啊。好吧,我认为 Google 会将秘密值作为环境变量传递。因此,我认为我可以在 Cloud Console 中进行某种程度的连接,而不是通过代码获取它。 是的,据我所知。您必须在您的环境设置中自己提供秘密 name 并将其传递给您的秘密管理器 (SM) 客户端库,否则 GCP 将不知道您想要什么秘密。如果你只有一个秘密,你可以使用 SM 列出你所有的秘密,然后选择第一个。这意味着您不必担心环境变量。但是,如果您添加另一个密钥,这会带来维护问题。【参考方案2】:

2021 年更新:现在有一个 Cloud Run 预览,用于将机密加载到环境变量或卷中。 https://cloud.google.com/run/docs/configuring/secrets

问题现已得到解答,但是我在使用 Cloud Run with Java & Quarkus 以及使用 GraalVM 创建的本机映像时遇到了类似的问题。

虽然 Cloud Run 在撰写本文时是一项非常有趣的技术,但它缺乏通过 Cloud Run 配置加载机密的能力。在进行本地开发时,这无疑增加了我的应用程序的复杂性。

此外,Google 的文档确实很差。快速入门缺少一个明确的 Java 示例来获取一个秘密 [1] 而没有在相同的方法中设置它 - 我希望这是最常见的用例!

javadoc 本身似乎在很大程度上是使用 protobuf 语言自动生成的。有多种类似名称的方法,例如getSecretgetSecretVersionaccessSecretVersion

我真的很想看到 Google 在这方面做出一些改进。我认为对于专门的团队来说,为具有适当文档的通用语言制作库并没有太多要求。

这是我用来加载此信息的 sn-p。它需要 GCP Secret 库和 GCP Cloud Core 库来加载项目 ID。

public String getSecret(final String secretName) 
    LOGGER.info("Going to load secret ", secretName);

    // SecretManagerServiceClient should be closed after request
    try (SecretManagerServiceClient client = buildClient()) 
        // Latest is an alias to the latest version of a secret
        final SecretVersionName name = SecretVersionName.of(getProjectId(), secretName, "latest");
        return client.accessSecretVersion(name).getPayload().getData().toStringUtf8();
    


private String getProjectId() 

    if (projectId == null) 
        projectId = ServiceOptions.getDefaultProjectId();
    

    return projectId;


private SecretManagerServiceClient buildClient() 
    try 
        return SecretManagerServiceClient.create();
     catch(final IOException e) 
        throw new RuntimeException(e);
    

[1] - https://cloud.google.com/secret-manager/docs/reference/libraries

【讨论】:

+1 为了谷歌阅读这篇文章。但是,请准备好被版主的 SO 调查所摧毁 如果您不想更改您的代码,您可以配置您的应用程序以使用来自 dockerfile 本身的这些机密,如 amazing article 或使用云构建,如 this documentation 跨度> 【参考方案3】:

我找到了一种将秘密用作环境变量的方法。

以下文档 (https://cloud.google.com/sdk/gcloud/reference/run/deploy) 指出:

指定要挂载或作为环境变量提供的机密。钥匙 以正斜杠“/”开头的是挂载路径。所有其他键 对应环境变量。与每个相关的值 其中应采用 SECRET_NAME:KEY_IN_SECRET 的形式;你可以省略 密钥中的密钥,用于指定密钥中所有密钥的安装 秘密。例如: '--update-secrets=/my/path=mysecret,ENV=othersecret:key.json' 将 创建一个带有秘密“mysecret”的卷并将该卷安装在 '/我自己的路'。因为没有指定密钥,所以所有密钥都在 'mysecret' 将被包括在内。名为 ENV 的环境变量将 也被创建,其值是'key.json'的值 '其他秘密'。最多可以指定其中之一

【讨论】:

不幸的是,这似乎只适用于 Anthos:运行 gcloud run deploy --help 在类别下显示该选项:仅适用于连接到部署在 Google Cloud 上的 Cloud Run for Anthos 或部署在 VMware 上的 Cloud Run for Anthos .指定 --platform=gke 或 --platform=kubernetes 使用: Google 让访问这些秘密变得如此痛苦,这真是一种耻辱。提供gcloud run deploy 选项不会杀死他们,该选项只会使我的项目中的所有机密都可用作同名的环境变量。 从昨天开始,您现在也可以在托管(非 Anthos)Cloud Run 中将机密作为环境变量读取。在cloud.google.com/run/docs/configuring/secrets找到详细信息【参考方案4】:

这是获取 Cloud Run 项目所有机密的 Java 代码的 sn-p。它需要com.google.cloud/google-cloud-secretmanager 工件。

Map<String, String> secrets = new HashMap<>();          
String projectId;
String url = "http://metadata.google.internal/computeMetadata/v1/project/project-id";
HttpURLConnection conn = (HttpURLConnection)(new URL(url).openConnection());
conn.setRequestProperty("Metadata-Flavor", "Google");
try 
   InputStream in = conn.getInputStream();
   projectId = new String(in.readAllBytes(), StandardCharsets.UTF_8);
 finally 
   conn.disconnect();
               
Set<String> names = new HashSet<>();
try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) 
   ProjectName projectName = ProjectName.of(projectId);
   ListSecretsPagedResponse pagedResponse = client.listSecrets(projectName);
    
   pagedResponse
      .iterateAll()
      .forEach(secret ->  names.add(secret.getName()); );
   for (String secretName : names) 
      String name = secretName.substring(secretName.lastIndexOf("/") + 1);
      SecretVersionName nameParam = SecretVersionName.of(projectId, name, "latest");
      String secretValue = client.accessSecretVersion(nameParam).getPayload().getData().toStringUtf8();
      secrets.put(secretName, secretValue);
   


【讨论】:

结合 Spring 的 @DynamicPropertySource 使用还不错【参考方案5】:

您现在可以将 Secret Manager 中的密钥作为 Cloud Run 中的环境变量读取。这意味着您可以审核您的机密、设置每个机密的权限、版本机密等,并且您的代码不必更改。

您可以通过 Cloud Console GUI (console.cloud.google.com) 指向密钥,或者在从命令行部署 Cloud Run 服务时进行配置:

gcloud beta run deploy SERVICE --image IMAGE_URL --update-secrets=ENV_VAR_NAME=SECRET_NAME:VERSION

六分钟视频概览:https://youtu.be/JIE89dneaGo

详细文档:https://cloud.google.com/run/docs/configuring/secrets

【讨论】:

【参考方案6】:

Cloud Run 对引用 Secret Manager Secrets 的支持现已全面推出 (GA)。

https://cloud.google.com/run/docs/release-notes#November_09_2021

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review

以上是关于如何在已部署的 Cloud Run Service(托管)中使用 Google Secret?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取或生成Google Cloud Run服务的部署URL

使用 Google Cloud Run 时如何访问已装载的机密?

如何将 Google Cloud Run Container 连接到 Open***?

Cloud Run + Cloud Endpoints + Service Account Authentication – 在 curl 中有效,但在 JS 中使用 fetch API 时无效

如何为 Cloud Build 用于 Cloud Run 部署的 Cloud Storage 存储分区指定区域?

Terraform GCP:无需用户停机即可更新 Cloud Run 服务