将 Secret 同步到 Kubernetes Secret

本文档介绍了如何将存储在 Secret Manager 中的 Secret 同步到 Google Kubernetes Engine (GKE) 集群中的 Kubernetes Secret。

通过同步流程,在 GKE 上运行的应用可以使用标准 Kubernetes 方法(例如环境变量或卷装载)从 Secret Manager 访问 Secret。对于已设计为从 Kubernetes Secret 对象读取 Secret 的应用,此功能非常有用,因为这些应用无需更新即可直接访问 Secret Manager。

建议:Secret 同步功能是 Secret Manager 插件的替代方案,该插件可将 Secret 作为内存中文件直接装载到您的 Pod 中。只要您的应用支持,就应使用 Secret Manager 插件,因为这是在 GKE 中从 Secret Manager 访问 Secret 的更安全方法。

准备工作

在同步 Secret 之前,请完成以下前提条件:

  • Enable the Secret Manager and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  • 安装初始化 gcloud CLI。如果您之前安装了 gcloud CLI,请运行 gcloud components update 命令以获取最新版本。

  • 确保您拥有正在运行的 GKE 集群。此功能需要 GKE 1.34 版及更高版本。

  • 确保已在 GKE 集群上启用 Workload Identity Federation for GKE。 这是进行身份验证所必需的。Autopilot 集群默认启用 Workload Identity Federation for GKE。

  • 确保您拥有必要的 Identity and Access Management 权限来管理 GKE 集群和 Secret Manager。

在 GKE 集群上启用 Secret 同步

在创建新集群或更新现有集群时启用 Secret 同步功能。此功能适用于 Standard 集群和 Autopilot 集群。

在新集群上启用 Secret 同步

如需创建启用 Secret 同步的新集群,请使用以下 gcloud CLI 命令之一:

标准集群

如需在命令行上使用 Secret Manager,请先安装或升级到 Google Cloud CLI 版本 378.0.0 或更高版本。在 Compute Engine 或 GKE 上,您必须使用 cloud-platform 范围进行身份验证

启用密文同步,但不启用自动轮替。

gcloud beta container clusters create CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --workload-pool=PROJECT_ID.svc.id.goog \
    --enable-secret-sync

启用自动轮替的密文同步。默认间隔为 2 分钟。

gcloud beta container clusters create CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --workload-pool=PROJECT_ID.svc.id.goog \
    --enable-secret-sync \
    --enable-secret-sync-rotation

启用以自定义轮替间隔进行的密文同步。最短间隔时间为 1 分钟。

gcloud beta container clusters create CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --workload-pool=PROJECT_ID.svc.id.goog \
    --enable-secret-sync \
    --enable-secret-sync-rotation \
    --secret-sync-rotation-interval=1m

替换以下内容:

  • CLUSTER_NAME:GKE 集群的名称
  • CONTROL_PLANE_LOCATION:集群控制平面所在的区域或可用区,例如 us-central1us-east1-a
  • PROJECT_ID:您的 Google Cloud 项目 ID

Autopilot 集群

如需在命令行上使用 Secret Manager,请先安装或升级到 Google Cloud CLI 版本 378.0.0 或更高版本。在 Compute Engine 或 GKE 上,您必须使用 cloud-platform 范围进行身份验证

启用密文同步,但不启用自动轮替。

gcloud beta container clusters create-auto CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --enable-secret-sync

启用自动轮替的密文同步。默认间隔为 2 分钟。

gcloud beta container clusters create-auto CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --enable-secret-sync \
    --enable-secret-sync-rotation

启用以自定义轮替间隔进行的密文同步。最短间隔时间为 1 分钟。

gcloud beta container clusters create-auto CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --enable-secret-sync \
    --enable-secret-sync-rotation \
    --secret-sync-rotation-interval=1m

替换以下内容:

  • CLUSTER_NAME:GKE 集群的名称
  • CONTROL_PLANE_LOCATION:集群控制平面所在的区域或可用区,例如 us-central1us-east1-a

在现有集群上启用 Secret 同步

如需使用 Secret 同步功能更新现有集群,请使用以下 gcloud CLI 命令之一:

gcloud

如需在命令行上使用 Secret Manager,请先安装或升级到 Google Cloud CLI 版本 378.0.0 或更高版本。在 Compute Engine 或 GKE 上,您必须使用 cloud-platform 范围进行身份验证

在现有集群上启用 Secret 同步

gcloud beta container clusters update CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --enable-secret-sync

以自定义时间间隔启用轮播

gcloud beta container clusters update CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --enable-secret-sync-rotation \
    --secret-sync-rotation-interval=5m

停用轮播

gcloud beta container clusters update CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --no-enable-secret-sync-rotation

替换以下内容:

  • CLUSTER_NAME:GKE 集群的名称
  • CONTROL_PLANE_LOCATION:集群控制平面所在的区域或可用区,例如 us-central1us-east1-a

配置 Secret 同步

如需同步密钥,请完成以下步骤:

  1. 使用以下命令创建 Kubernetes ServiceAccount

    kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
    

    替换以下内容:

    • KSA_NAME:Kubernetes ServiceAccount 的名称
    • NAMESPACE:您要在其中创建 ServiceAccount 的 Kubernetes 命名空间
  2. 创建引用新的 Kubernetes ServiceAccount 的 IAM 许可政策,并向该 ServiceAccount 授予访问相应 Secret 的权限:

    gcloud

    如需在命令行上使用 Secret Manager,请先安装或升级到 Google Cloud CLI 版本 378.0.0 或更高版本。在 Compute Engine 或 GKE 上,您必须使用 cloud-platform 范围进行身份验证

    gcloud secrets add-iam-policy-binding SECRET_PROJECT_ID \
       --role=roles/secretmanager.secretAccessor \
       --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_IDsvc.id.goog/subject/ns/NAMESPACE/sa/KSA_NAME
    

    替换以下内容:

    • SECRET_PROJECT_ID:存储 Secret 的项目的 ID。如果密钥存储在与 GKE 集群相同的项目中,则此值可以与 PROJECT_ID 相同。
    • PROJECT_NUMBER:您的 Google Cloud 项目编号
    • PROJECT_ID:您的 Google Cloud 项目 ID
    • NAMESPACE:Kubernetes 命名空间
    • KSA_NAME:Kubernetes ServiceAccount 的名称
  3. 使用 YAML 清单创建 SecretProviderClass 自定义资源。SecretProviderClass 资源用于定义要从 Secret Manager 中检索的特定 Secret,包括其资源名称和路径。Secret Manager 插件还使用 SecretProviderClass 资源来列出要挂载的 Secret 以及要将这些 Secret 挂载为的文件名。

    创建一个包含以下内容的 spc.yaml 文件:

    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: SECRET_PROVIDER_CLASS_NAME
      namespace: NAMESPACE
    spec:
      provider: gke
      parameters:
        secrets: |
          -   resourceName: "projects/SECRET_PROJECT_ID/secrets/SECRET_NAME/versions/SECRET_VERSION"
              path: "FILENAME.txt"
          -   resourceName: "projects/SECRET_PROJECT_ID/secrets/SECRET_NAME/versions/SECRET_VERSION"
              path: "FILENAME1.txt"
    

    替换以下内容:

    • SECRET_PROVIDER_CLASS_NAME:SecretProviderClass 对象的名称。
    • NAMESPACE:您要创建此资源的 Kubernetes 命名空间。
    • resourceName:Secret Manager 中相应 Secret 的完整资源标识符。此参数必须包含项目 ID、密钥名称和版本,格式如下:projects/SECRET_PROJECT_ID/secrets/SECRET_NAME/versions/SECRET_VERSION
      • SECRET_PROJECT_ID:存储 Secret 的 Google Cloud 项目的 ID。如果 Secret 存储在与 GKE 集群相同的项目中,则此值可以与 PROJECT_ID 相同。
      • SECRET_NAME:密文名称。
      • SECRET_VERSION:Secret 版本。Secret 版本必须与集群位于同一区域。
    • path:在 Kubernetes 环境中,Secret 值将作为本地文件名或别名公开。它是将特定 Secret Manager 版本与集群使用的本地表示形式相关联的唯一标识符。当使用 SecretSync 资源将 Secret 同步到 Kubernetes Secret 时,sourcePath 字段会引用此路径,以找到要同步的 Secret 值。 您可以将多个 Secret(由 resourceName 定义)映射到同一 SecretProviderClass 中的不同路径名称。
  4. 如需应用清单,请运行以下命令:

    kubectl apply -f spc.yaml
    
  5. 使用 YAML 清单创建 SecretSync 自定义资源。此资源会指示同步控制器根据 SecretProviderClass 中定义的内容创建或更新 Kubernetes Secret。

    创建一个包含以下内容的 secret-sync.yaml 文件:

    apiVersion: secret-sync.gke.io/v1
    kind: SecretSync
    metadata:
      name: KUBERNETES_SECRET_NAME
      namespace: NAMESPACE
    spec:
      serviceAccountName: KSA_NAME
      secretProviderClassName: SECRET_PROVIDER_CLASS_NAME
      secretObject:
        type: KUBERNETES_SECRET_TYPE
        data:
          -   sourcePath: "FILENAME.txt"
              targetKey: "TARGET_KEY1"
          -   sourcePath: "FILENAME1.txt"
              targetKey: "TARGET_KEY2"
    

    替换以下内容:

    • KUBERNETES_SECRET_NAME:您要为 SecretSync 资源将创建的新 Kubernetes Secret 指定的名称。
    • NAMESPACE:创建新资源的 Kubernetes 命名空间。它必须与 SecretProviderClass 位于同一命名空间中。
    • KSA_NAME:SecretSync 控制器用于创建和更新目标 Kubernetes Secret 的 Kubernetes ServiceAccount 的名称。 此服务账号必须具有从 Secret Manager 访问外部 Secret 的必要权限。
    • SECRET_PROVIDER_CLASS_NAME:您在上一步中创建的 SecretProviderClass 对象的名称。SecretSync 资源使用此字段来查找 Secret 的正确配置。
    • KUBERNETES_SECRET_TYPE:要创建的 Kubernetes Secret 的类型,例如 Opaquetlsdocker-registry。这决定了 Kubernetes 如何处理 Secret 的数据。
    • sourcePath:用于标识要检索的 Secret 数据的本地文件名或别名(SecretProviderClass 中 path 字段的值)。SecretSync 控制器使用此 sourcePath 请求特定的 Secret 内容,并将其转换为新的 Kubernetes Secret。
    • targetKey:将在所创建的新 Kubernetes Secret 的 data 部分中使用的密钥。此属性用于定义使用 sourcePath 检索到的 Secret 内容在最终 Kubernetes Secret 对象中的命名和存储方式。通过在数据数组中使用多个条目,您可以在同一目标 Secret 中定义多个键值对。
  6. 如需应用清单,请运行以下命令:

    kubectl apply -f secret-sync.yaml
    

    同步控制器会在指定命名空间中创建 Kubernetes Secret。此 Secret 包含从 Secret Manager 映射的数据。

  7. 验证 Kubernetes Secret 是否已创建:

    kubectl get secret KUBERNETES_SECRET_NAME -n NAMESPACE -o yaml
    

    替换以下内容:

    • KUBERNETES_SECRET_NAME:新 Kubernetes Secret 的名称
    • NAMESPACE:创建新 Secret 的 Kubernetes 命名空间
  8. 如需排查同步问题,请使用以下命令:

    kubectl describe secretSync KUBERNETES_SECRET_NAME -n NAMESPACE
    

    替换以下内容:

    • KUBERNETES_SECRET_NAME:新 Kubernetes Secret 的名称
    • NAMESPACE:新 Secret 应存在的 Kubernetes 命名空间

管理密文轮替

如果您在集群上启用 --enable-secret-sync-rotation 标志,同步控制器会定期检查 Secret Manager 中 SecretProviderClass 资源中指定的 Secret 是否有新版本。--secret-sync-rotation-interval 标志用于确定控制器检查更新的频率。

如果控制器在 Secret Manager 中检测到新的 Secret 版本,则会更新相应的 Kubernetes Secret。控制器会比较 Secret 内容的哈希,以便仅在发生更改时更新 Secret。

使用这些 Secret 的应用必须检测并从 Kubernetes Secret 重新加载更新后的 Secret 值。具体处理方式取决于应用的设计。

停用密文同步

如需停用 Secret 同步,请运行以下 gcloud CLI 命令:

gcloud

如需在命令行上使用 Secret Manager,请先安装或升级到 Google Cloud CLI 版本 378.0.0 或更高版本。在 Compute Engine 或 GKE 上,您必须使用 cloud-platform 范围进行身份验证

gcloud beta container clusters update CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --no-enable-secret-sync

替换以下内容:

  • CLUSTER_NAME:GKE 集群的名称
  • CONTROL_PLANE_LOCATION:集群控制平面所在的区域或可用区,例如 us-central1us-east1-a

此命令会停止同步控制器。它不会删除任何已创建的 Kubernetes Secret。如果您不再需要任何已同步的 Kubernetes Secret,则必须手动将其删除。

删除已同步的密钥

如需删除已同步的 Kubernetes Secret,请使用以下命令删除 SecretSync 资源:

    kubectl delete secretsync KUBERNETES_SECRET_NAME --namespace NAMESPACE

替换以下内容:

  • KUBERNETES_SECRET_NAME:Kubernetes Secret 的名称
  • NAMESPACE:Secret 所在的 Kubernetes 命名空间

从现有 Secret Store CSI 驱动程序迁移

如果您要从现有安装的 Secrets Store CSI 驱动程序迁移,请按以下步骤操作:

  1. 将 SecretProviderClass 中的 provider 字段从 gcp 更新为 gke。 以下示例展示了如何更新 provider 字段:

    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: app-secrets-gke
    spec:
      provider: gke
      parameters:
        secrets: |
          -   resourceName: "projects/87654321/secrets/api-key-secret/versions/2"
              path: "good1.txt"
    
  2. 创建 SecretSync 资源。使用以下示例配置:

    apiVersion: secret-sync.gke.io/v1
    kind: SecretSync
    metadata:
      name: my-kube-secret
      namespace: NAMESPACE
    spec:
      serviceAccountName: KSA_NAME
      secretProviderClassName: my-app-secrets
      secretObject:
        type: Opaque # Or other Kubernetes Secret types
        data:
          -   sourcePath: "my-secret.txt"
              targetKey: "USERNAME"
          -   sourcePath: "another-secret.txt"
              targetKey: "PASSWORD"
    

安全注意事项

Secret Manager 提供多种安全功能,例如 IAM 访问权限控制客户管理的加密密钥 (CMEK)审核日志记录。Secret 在 Secret Manager 中静态存储时和传输过程中都会加密。将 Secret 同步到 Kubernetes Secret 时,它们在集群中的安全性取决于 GKE 集群的配置。请考虑以下事项:

  • 存储:Kubernetes Secret 存储在 etcd 中,而 etcd 是 GKE 的主要数据存储区。默认情况下,GKE 会对静态数据进行加密。为了提高安全性,请使用您在 Cloud Key Management Service(Cloud KMS) 中管理的密钥在应用层加密 Kubernetes secret。加密 Secret 可为敏感工作负载提供额外一层安全保障。

  • 访问权限控制:GKE 支持多种选项,以使用基于角色的访问控制 (RBAC) 管理对项目及其集群中的资源的访问权限。过于宽泛的 RBAC 权限可能会将密钥暴露给意外的工作负载或用户。根据最小权限原则授予访问权限,并定期审核对 Secret Manager 和 Kubernetes Secret 的访问权限。

  • 环境变量:为了提高安全性,请将 Kubernetes Secret 装载为卷,而不是将其用作环境变量。这样可以降低意外记录或暴露给其他进程的风险。

后续步骤