配置 Secret

您的服务可能需要具有需要 API 密钥、密码或其他敏感信息的依赖项。对于 Cloud Run,Google 建议您将此类敏感信息存储在 Secret Manager 中创建的 Secret 中。

您可以通过以下两种方式之一为您的容器提供 Secret:

  • 将每个 Secret 作为卷装载,使 Secret 可供文件以容器形式提供给容器。读取卷始终从 Secret Manager 中提取 Secret 值,因此可以与最新版本配合使用。此方法还非常适合 Secret 轮替。
  • 使用环境变量传递 Secret。环境变量在实例启动时解析,因此,如果您使用此方法,Google 建议您将 Secret 固定到特定版本,而不是使用最新版本

如需了解详情,请参阅 Secret Manager 最佳做法文档。

如何在部署和运行时检查 Secret

在部署服务期间,系统会检查使用的所有 Secret(无论是作为环境变量还是作为卷装载),以确保用于运行容器的服务账号有权访问它们。如果任何检查失败,则服务部署会失败。

在运行期间,当实例启动时:

  • 如果 Secret 是环境变量,则系统在启动实例之前会检索 Secret 的值,因此如果 Secret 检索失败,则实例不会启动。
  • 如果 Secret 作为卷装载,则在实例启动期间不执行检查。但是,在运行期间,如果 Secret 无法访问,则读取已装载的卷的尝试将失败。

卷所有权因执行环境和部署类型而异

装载 Secret 卷时,拥有文件和目录的身份因工作负载的执行环境以及部署是否包含一个或多个容器而有所不同。

在要部署单个容器的第一代执行环境中,Secret 卷归容器使用的身份所有。在所有其他情况下,卷归 root 用户所有。其中包括:

  • 在其中部署多个容器的第一代执行环境
  • 第二代环境

准备工作

  1. Enable the Secret Manager API.

    Enable the API

  2. 使用现有 Secret,或按照创建 Secret 中的说明在 Secret Manager 中创建 Secret。

所需的角色

如需获得配置 Secret 所需的权限,请让管理员向您授予以下 IAM 角色:

如需允许 Cloud Run 访问 Secret,服务身份必须拥有以下角色:

如需了解如何将服务身份主账号添加到 Secret Manager Secret Accessor 角色,请参阅管理对 Secret 的访问权限

如需查看与 Cloud Run 关联的 IAM 角色和权限的列表,请参阅 Cloud Run IAM 角色Cloud Run IAM 权限。如果您的 Cloud Run 服务与 Google Cloud API(例如 Cloud 客户端库)进行交互,请参阅服务身份配置指南。如需详细了解如何授予角色,请参阅部署权限管理访问权限

将 Secret 设为可供 Cloud Run 访问

任何配置更改都会导致新修订版本的创建。后续修订版本也将自动采用此配置设置,除非您进行了明确更新。

您可以在部署新服务或更新现有服务并部署修订版本时,使用 Google Cloud 控制台、Google Cloud CLI 或 YAML 文件将 Secret 设为可供服务访问。点击您要查看的标签页:

控制台

  1. 在 Google Cloud 控制台中,前往 Cloud Run:

    转到 Cloud Run

  2. 点击部署容器,然后选择服务以配置新服务。填写初始服务设置页面,然后点击容器、卷、网络、安全性以展开服务配置页面。

  3. 如果您要配置现有服务,请点击该服务,然后点击修改和部署新的修订版本

  4. 按照相应步骤将 Secret 作为卷装载,或将 Secret 作为环境变量公开。

    • 如需将 Secret 装载为卷,请执行以下操作:

      1. 点击标签页,然后选择添加卷
      2. 卷类型列表中,选择 Secret
      3. 卷名称字段中,输入名称或接受默认名称。
      4. Secret 列表中选择要使用的 Secret。
      5. 路径 1 字段中,输入要装载的文件的名称。
      6. 版本 1 列表中,选择要引用的 Secret 版本。系统默认选择最新版本。您可以根据需要选择特定版本。
      7. 点击完成
      8. 前往容器标签页,将 Secret 装载到容器中。
      9. 卷装载标签页中,点击装载卷
      10. 名称 1列表中,选择您的卷名称。
      11. 装载路径 1 字段中,输入此 Secret 的装载路径。这是所有 Secret 版本所在的目录。
      12. 点击完成
      13. 点击创建部署
    • 如需将密文公开为环境变量,请执行以下操作:

      1. 点击容器标签页。
      2. 变量和 Secret 标签页中,点击引用 Secret
      3. 名称 1 字段中,输入环境变量的名称。
      4. Secret 列表中选择要使用的 Secret。
      5. 版本 1 列表中,选择要引用的 Secret 版本。
      6. 点击完成
      7. 点击创建部署

gcloud

要使 Secret 可访问您的服务,请输入以下某个命令。

  • 如需在部署服务时将 Secret 作为卷装载,请执行以下操作:

    gcloud run deploy SERVICE --image IMAGE_URL  \
    --update-secrets=PATH=SECRET_NAME:VERSION

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • PATH 替换为卷的卷路径和 Secret 文件名。它必须以正斜杠开头,例如 /etc/secrets/dbconfig/password,其中 /etc/secrets/dbconfig/ 是卷的装载路径,password 是 Secret 的文件名。
    • SECRET_NAME 替换为同一项目中的 Secret 名称,例如 mysecret
    • VERSION 替换为 Secret 版本。请使用 latest 获取最新版本,或者使用数字,例如 2
  • 如需在部署服务时将 Secret 公开为环境变量,请执行以下操作:

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

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • ENV_VAR_NAME 替换为要与 Secret 搭配使用的环境变量的名称。
    • SECRET_NAME 替换为同一项目中的 Secret 名称,例如 mysecret
    • VERSION 替换为 Secret 版本。请使用 latest 获取最新版本,或者使用数字,例如 2
  • 您可以同时更新多个 Secret。为此,请使用英文逗号分隔每个 Secret 的配置选项。以下命令会更新一个作为卷装载的 Secret,以及另一个作为环境变量公开的 Secret。

    如需更新现有 Secret,请输入以下命令:

    gcloud run deploy SERVICE --image IMAGE_URL \
    --update-secrets=PATH=SECRET_NAME:VERSION,ENV_VAR_NAME=SECRET_NAME:VERSION
  • 要清除现有 Secret 并使新 Secret 可用于服务,请使用 --set-secrets 标志:

    gcloud run services update SERVICE \
    --set-secrets="ENV_VAR_NAME=SECRET_NAME:VERSION"

YAML

  1. 如果您要创建新的服务,请跳过此步骤。如果您要更新现有服务,请下载其 YAML 配置

    gcloud run services describe SERVICE --format export > service.yaml
  2. 对于作为环境变量公开的 Secret,在 env 下根据需要更新 ENV_VARVERSION 和/或 SECRET_NAME。如果您已将多个 Secret 作为环境变量装载,将具有多个这些属性。

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: SERVICE
    spec:
      template:
        metadata:
          name: REVISION
        spec:
          containers:
          - image: IMAGE_URL
            env:
            - name: ENV_VAR
              valueFrom:
                secretKeyRef:
                  key: VERSION
                  name: SECRET_NAME
  3. 对于以文件路径形式装载的 Secret,您可以根据需要更新 MOUNT_PATHVOLUME_NAMEVERSIONFILENAME 和/或 SECRET_NAME。如果您将多个 Secret 作为文件路径进行装载,则会拥有多个这些属性。

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: SERVICE
    spec:
      template:
        metadata:
          name: REVISION
        spec:
          containers:
          - image: IMAGE_URL
            volumeMounts:
            - mountPath: MOUNT_PATH
              name: VOLUME_NAME
          volumes:
          - name: VOLUME_NAME
            secret:
              items:
              - key: VERSION
                path: FILENAME
              secretName: SECRET_NAME

    请注意,VOLUME_NAME 可以设置为任意名称。

    您需要进行如下替换

    • SERVICE 替换为您的 Cloud Run 服务的名称
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • REVISION 替换为新的修订版本名称或者将其删除(如果存在)。如果您提供新的修订版本名称,则该名称必须满足以下条件:
      • 开头为 SERVICE-
      • 仅包含小写字母、数字和 -
      • 不以 - 结尾
      • 不超过 63 个字符
  4. 使用以下命令将服务替换为其新配置:

    gcloud run services replace service.yaml

Terraform

  1. 创建 Secret 和 Secret 版本。

    resource "google_secret_manager_secret" "default" {
      secret_id = "my-secret"
      replication {
        auto {}
      }
    }
    
    resource "google_secret_manager_secret_version" "default" {
      secret      = google_secret_manager_secret.default.name
      secret_data = "this is secret data"
    }
  2. 创建一个服务账号并向其授予 Secret 的访问权限:

    resource "google_service_account" "default" {
      account_id   = "cloud-run-service-account"
      display_name = "Service account for Cloud Run"
    }
    
    resource "google_secret_manager_secret_iam_member" "default" {
      secret_id = google_secret_manager_secret.default.id
      role      = "roles/secretmanager.secretAccessor"
      # Grant the new deployed service account access to this secret.
      member     = "serviceAccount:${google_service_account.default.email}"
      depends_on = [google_secret_manager_secret.default]
    }
  3. Secret Manager Secret 可作为已装载的文件路径或环境变量从 Cloud Run 进行访问。

    1. 对于作为文件路径装载的 Secret,请在 volumes 参数中引用 Secret Manager 资源。name 对应于 volume_mounts 参数中的一个条目:

      resource "google_cloud_run_v2_service" "mounted_secret" {
        name     = "service-with-mounted-secret"
        location = "us-central1"
        ingress  = "INGRESS_TRAFFIC_ALL"
      
        deletion_protection = false # set to "true" in production
      
        template {
          volumes {
            name = "my-service-volume"
            secret {
              secret = google_secret_manager_secret.default.secret_id
              items {
                version = "latest"
                path    = "my-secret"
                mode    = 0 # use default 0444
              }
            }
          }
          containers {
            image = "us-docker.pkg.dev/cloudrun/container/hello"
            volume_mounts {
              name       = "my-service-volume"
              mount_path = "/secrets"
            }
          }
          service_account = google_service_account.default.email
        }
        depends_on = [google_secret_manager_secret_version.default]
      }
    2. 对于作为环境变量公开的 Secret,请在 env 参数中引用 Secret Manager 资源:

      resource "google_cloud_run_v2_service" "env_variable_secret" {
        name     = "service-with-env-var-secret"
        location = "us-central1"
        ingress  = "INGRESS_TRAFFIC_ALL"
      
        deletion_protection = false # set to "true" in production
      
        template {
          containers {
            image = "us-docker.pkg.dev/cloudrun/container/hello"
            env {
              name = "MY_SECRET"
              value_source {
                secret_key_ref {
                  secret  = google_secret_manager_secret.default.secret_id
                  version = "latest"
                }
              }
            }
          }
          service_account = google_service_account.default.email
        }
        depends_on = [google_secret_manager_secret_version.default]
      }

引用其他项目中的 Secret

如需引用其他项目中的 Secret,请验证您项目的服务账号是否有权访问该 Secret

控制台

  1. 在 Google Cloud 控制台中,前往 Cloud Run:

    转到 Cloud Run

  2. 点击部署容器,然后选择服务以配置新服务。填写初始服务设置页面,然后点击容器、卷、网络、安全性以展开服务配置页面。

  3. 如果您要配置现有服务,请点击该服务,然后点击修改和部署新的修订版本

  4. 按照相应步骤将 Secret 作为卷装载,或将 Secret 作为环境变量公开。

    • 如需将 Secret 装载为卷,请执行以下操作:

      1. 点击标签页,然后选择添加卷
      2. 卷类型列表中,选择 Secret
      3. 卷名称字段中,输入名称或接受默认名称。
      4. Secret 列表中,点击手动输入 Secret
      5. 按以下格式输入密文的资源 ID:

        projects/PROJECT_NUMBER/secrets/SECRET_NAME
        

        替换以下内容:

        • PROJECT_NUMBER 替换为您的 Google Cloud 项目编号。 如需详细了解如何查找项目编号,请参阅创建和管理项目

        • SECRET_NAME:Secret Manager 中的密文名称。

      6. 路径 1 字段中,输入要装载的文件的名称。

      7. 版本 1 列表中,选择要引用的 Secret 版本。系统默认选择最新版本。您可以根据需要选择特定版本。

      8. 点击完成

      9. 前往容器标签页,将 Secret 装载到容器中。

      10. 卷装载标签页中,点击装载卷

      11. 名称 1列表中,选择您的卷名称。

      12. 装载路径 1 字段中,输入此 Secret 的装载路径。这是所有 Secret 版本所在的目录。

      13. 点击完成

      14. 点击创建部署

    • 如需将密文公开为环境变量,请执行以下操作:

      1. 点击容器标签页。
      2. 变量和 Secret 标签页中,点击引用 Secret
      3. 名称 1 字段中,输入环境变量的名称。
      4. Secret 列表中,点击手动输入 Secret
      5. 按以下格式输入密文的资源 ID:

        projects/PROJECT_NUMBER/secrets/SECRET_NAME
        

        替换以下内容:

        • PROJECT_NUMBER 替换为您的 Google Cloud 项目编号。 如需详细了解如何查找项目编号,请参阅创建和管理项目

        • SECRET_NAME:Secret Manager 中的密文名称。

      6. 版本 1 列表中,选择要引用的 Secret 版本。

      7. 点击完成

      8. 点击创建部署

gcloud

  • 如需在部署服务时将 Secret 作为卷装载,请执行以下操作:

    gcloud run deploy SERVICE --image IMAGE_URL  \
    --update-secrets=PATH=projects/PROJECT_NUMBER/secrets/SECRET_NAME:VERSION

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • PATH 替换为卷的卷路径和 Secret 文件名。它必须以正斜杠开头,例如 /etc/secrets/dbconfig/password,其中 /etc/secrets/dbconfig/ 是卷的装载路径,password 是 Secret 的文件名。
    • PROJECT_NUMBER 替换为在其中创建 Secret 的项目的编号。
    • SECRET_NAME 替换为 Secret 名称,例如 mysecret
    • VERSION 替换为 Secret 版本。请使用 latest 获取最新版本,或者使用数字,例如 2

YAML

  1. 如果您要创建新的服务,请跳过此步骤。如果您要更新现有服务,请下载其 YAML 配置

    gcloud run services describe SERVICE --format export > service.yaml

由于 API 兼容性的限制,Secret 位置必须存储在注解中。

  1. 对于作为环境变量公开的 Secret:

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: SERVICE
    spec:
      template:
        metadata:
          annotations:
            run.googleapis.com/secrets: SECRET_LOOKUP_NAME:projects/PROJECT_NUMBER/secrets/SECRET_NAME
        spec:
          containers:
          - image: IMAGE_URL
            env:
            - name: ENV_VAR
              valueFrom:
                secretKeyRef:
                  key: VERSION
                  name: SECRET_LOOKUP_NAME

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • ENV_VAR
    • PROJECT_NUMBER 替换为在其中创建 Secret 的项目的编号。
    • SECRET_NAME 替换为 Secret 名称,例如 mysecret
    • VERSION 替换为 Secret 版本。请使用 latest 获取最新版本,或者使用数字,例如 2
    • SECRET_LOOKUP_NAME 替换为任何具有有效 Secret 名称语法的名称(例如 my-secret),它可以与 SECRET_NAME 相同
  2. 对于作为文件路径装载的 Secret:

    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: SERVICE
    spec:
      template:
        metadata:
          annotations:
            run.googleapis.com/secrets: SECRET_LOOKUP_NAME:projects/PROJECT_NUMBER/secrets/SECRET_NAME
        spec:
          containers:
          - image: IMAGE_URL
            volumeMounts:
            - mountPath: MOUNT_PATH
              name: VOLUME_NAME
          volumes:
          - name: VOLUME_NAME
            secret:
              items:
              - key: VERSION
                path: FILENAME
              secretName: SECRET_LOOKUP_NAME

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • PATH 替换为卷的卷路径和 Secret 文件名。它必须以正斜杠开头,例如 /etc/secrets/dbconfig/password,其中 /etc/secrets/dbconfig/ 是卷的装载路径,password 是 Secret 的文件名。
    • PROJECT_NUMBER 替换为在其中创建 Secret 的项目的编号。
    • SECRET_NAME 替换为 Secret 名称,例如 mysecret
    • VERSION 替换为 Secret 版本。请使用 latest 获取最新版本,或者使用数字,例如 2
    • SECRET_LOOKUP_NAME 替换为任何具有有效 Secret 名称语法的名称(例如 my-secret),它可以与 SECRET_NAME 相同
    • VOLUME_NAME 替换为任何名称(例如 my-volume),它可以与 SECRET_NAME 相同

查看 Secret 设置

如需查看 Cloud Run 服务的当前 Secret 设置,请执行以下操作:

控制台

  1. 在 Google Cloud 控制台中,前往 Cloud Run:

    转到 Cloud Run

  2. 点击您感兴趣的服务以打开“服务详细信息”页面。

  3. 点击修订版本标签页。

  4. 在右侧的详细信息面板中,“容器”标签页下列出了 Secret 设置。

gcloud

  1. 使用以下命令:

    gcloud run services describe SERVICE
  2. 在返回的配置中找到并发设置。

从服务中移除密钥

您可以使用 Google Cloud 控制台或 gcloud CLI 从服务中移除密文:

控制台

  1. 在 Google Cloud 控制台中,前往 Cloud Run:

    转到 Cloud Run

  2. 从列表中选择您的服务,然后点击修改和部署新的修订版本

  3. 点击容器标签页。

  4. 如需删除作为卷挂载的 Secret,请选择 Volume mounts(卷挂载)标签页,将鼠标指针悬停在要移除的 Secret 上,然后点击 Delete(删除)。

  5. 如需删除作为环境变量公开的 Secret,请选择变量和 Secret 标签页,将指针悬停在要移除的 Secret 上,然后点击 删除

  6. 点击部署

gcloud

您可以从服务中移除所有密文,或指定一个或多个要移除的密文:

  • 如需移除所有密文,请运行以下命令:

    gcloud run deploy SERVICE --image IMAGE_URL \
    --clear-secrets
    

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
  • 如需指定要移除的密文列表,请使用 --remove-secrets 标志。以下命令会移除一个装载为卷的密文,以及另一个公开为环境变量的密文。

    gcloud run deploy SERVICE --image IMAGE_URL \
    --remove-secrets=ENV_VAR_NAME,SECRET_FILE_PATH
    

    您需要进行如下替换:

    • SERVICE 替换为您的服务名称。
    • IMAGE_URL 替换为对容器映像的引用,例如 us-docker.pkg.dev/cloudrun/container/hello:latest。 如果您使用 Artifact Registry,则必须预先创建制品库 REPO_NAME。网址格式为 LOCATION-docker.pkg.dev/PROJECT_ID/REPO_NAME/PATH:TAG
    • ENV_VAR_NAME:环境变量的名称。
    • SECRET_FILE_PATH:密文的完整路径。例如 /mnt/secrets/primary/latest,其中 /mnt/secrets/primary/ 是装载路径,latest 是密文路径。您也可以分别指定装载路径和密文路径:

          --set-secrets MOUNT_PATH:SECRET_PATH=SECRET:VERSION
      

在代码中使用 Secret

如需查看如何将代码中的 Secret 作为环境变量进行访问的示例,请参阅有关最终用户身份验证的教程,尤其是使用 Secret Manager 处理敏感配置部分。

不允许的路径及相关限制

Cloud Run 不允许您在 /dev/proc/sys 或其子目录上装载 Secret。

如果您要在 /tmp 上装载 Secret,并且使用的是第一代执行环境,请参阅有关/tmp 上装载 Secret 的已知问题。

Cloud Run 不允许在同一路径下装载多个 Secret,因为两个卷装载无法装载到同一位置。

覆盖目录

如果 Secret 在 Cloud Run 中作为卷装载,并且卷装载路径中的最终目录已存在,则现有目录中的任何文件或文件夹都将无法访问。

例如,如果名为 my-secret 的 Secret 装载到路径 /etc/app_data 中,则 app_data 目录中的所有内容都将被覆盖,并且唯一可见的文件是 /etc/app_data/my-secret

如需避免覆盖现有目录中的文件,请创建新目录以用于装载 Secret(例如 /etc/app_data/secrets),以便 Secret 的装载路径为 /etc/app_data/secrets/my-secret