配置 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 无法访问,则读取已装载的卷的尝试将失败。

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

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

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

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

允许 Cloud Run 访问 Secret

您可以使用现有的 Secret Manager Secret,也可以创建新的 Secret。但是,如需访问 Secret,您必须向用于 Cloud Run 服务身份的服务账号授予 Secret Manager Secret Accessor 角色。

从 Google Cloud 控制台中的 Cloud Run 页面选择 Secret 时,系统会自动执行权限检查,并提示您添加缺少的权限。

如需手动执行此操作,请遵循以下步骤:

  1. 进入 Google Cloud 控制台中的 Secret Manager 页面:

    转到 Secret Manager

  2. 点击列表中的 Secret

  3. 权限标签页中,点击授予访问权限

  4. 新的主账号文本框中,输入 Cloud Run 服务身份的电子邮件地址

  5. 向其授予 Secret Manager Secret Accessor 角色。

将 Secret 设为可供 Cloud Run 访问

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

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

控制台

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

    转到 Cloud Run

  2. 如果您是要配置一个新服务来作为部署目标,请点击创建服务。如果您要配置现有服务,请点击该服务,然后点击修改和部署新的修订版本

  3. 如果您要配置新服务,请根据需要填写初始服务设置页面,然后点击容器、网络、安全性以展开服务配置页面。

  4. 点击容器标签页。

    图片

    • 在 Secret 下:
      • 点击引用 Secret
      • Secret 下拉列表中选择要使用的 Secret。
      • 在“引用方法”下拉菜单中,选择您要使用 Secret 的方法,即作为卷装载或作为环境变量公开。
      • 如果要将 Secret 作为卷装载:
        1. 装载路径下,指定您要用于 Secret 的装载路径。
        2. 系统默认选择最新版本。您可以根据需要选择特定版本。在指定的 Secret 路径下,指定版本的路径和版本号。
        3. 点击完成
      • 如果您将 Secret 作为环境变量公开,请执行以下操作:
        1. 提供变量的名称并选择 Secret 版本,或者选择 最新版以始终使用当前的 Secret 版本。
        2. 点击完成
  5. 点击创建部署

命令行

要使 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

您可以使用 gcloud run services describe --format export 命令下载并查看现有服务配置,该命令会生成清理后的 YAML 格式的结果。然后按照后续说明修改字段,最后使用 gcloud run services replace 命令上传修改后的 YAML。请务必严格按照说明修改字段。

  1. 要查看和下载配置,请运行以下命令:

    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 版本。

    
    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = "~> 5.13.0"
        }
      }
    }
    
    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     = "cloudrun-srv-mounted-secret"
        location = "us-central1"
        ingress  = "INGRESS_TRAFFIC_ALL"
      
        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     = "cloudrun-srv-env-var-secret"
        location = "us-central1"
        ingress  = "INGRESS_TRAFFIC_ALL"
      
        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?请输入 Secret 资源 ID(在 Secret 下拉列表中),以显示以下表单:

        跨项目 Secret

      • 按资源 ID 添加 Secret 表单中,输入其他项目的 Secret,格式为 projects/PROJECT_NUMBER/secrets/SECRET_NAME。您也可以选择复制并粘贴其他项目中的资源 ID,具体方法是:选择 Secret,点击 Secret 右侧的操作省略号,从下拉菜单中选择复制资源 ID
      • 点击添加 Secret
      • 在“引用方法”下拉菜单中,选择您要使用 Secret 的方法,即作为卷装载或作为环境变量公开。
      • 如果要将 Secret 作为卷装载:
        1. 装载路径下,指定您要用于 Secret 的装载路径。
        2. 系统默认选择最新版本。您可以根据需要选择特定版本。在指定的 Secret 路径下,指定版本的路径和版本号。
        3. 点击完成
      • 如果您将 Secret 作为环境变量公开,请执行以下操作:
        1. 提供变量的名称并选择 Secret 版本,或者选择 最新版以始终使用当前的 Secret 版本。
        2. 点击完成
  5. 点击创建部署

命令行

  • 如需在部署服务时将 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

您可以使用 gcloud run services describe --format export 命令下载并查看现有服务配置,该命令会生成清理后的 YAML 格式的结果。然后按照后续说明修改字段,最后使用 gcloud run services replace 命令上传修改后的 YAML。请务必严格按照说明修改字段。

  1. 要查看和下载配置,请运行以下命令:

    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 设置。

命令行

  1. 使用以下命令:

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

在代码中使用 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/secrets。这将创建一个装载路径 /etc/app_data/secrets/my-secret,其中包含该 Secret。