在 Hashicorp Vault 中存储服务账号密钥

在 Hashicorp Vault 中存储服务账号 Secret

此功能可让您在外部 Secret 管理器 Hashicorp Vault 中存储 Apigee Hybrid 的 Google 服务账号证书。外部 Secret 管理器可让您管理数据在 Kubernetes 中的存储方式,包括管理数据驻留和精细的访问权限控制。

如果您未使用 GKE 集群上的 Workload IdentityEKS 和 AKS 上的工作负载身份联合,您的 Apigee Hybrid 组件需要对 Google 服务账号进行身份验证才能执行其任务。您可以通过以下三种方法在 Apigee Hybrid 中存储和引用 Google 服务账号密钥:

  • 存储在硬盘上的服务账号证书文件(.json 文件)。请使用 serviceAccountPath 配置属性在替换文件中引用这些内容。例如:
    logger:
      serviceAccountPath: service-accounts/myhybridorg-apigee-logger.json
    
  • 存储在硬盘上的服务账号证书文件(.json 文件)。请使用 serviceAccountPath 配置属性在替换文件中引用这些内容。请参阅服务账号简介
  • 存储在 Kubernetes Secret 中的服务账号证书。请使用 serviceAccountRef 配置属性在替换文件中引用这些内容。请参阅在 Kubernetes Secret 中存储数据
  • 存储在 Hashicorp Vault 中的服务账号证书(在本指南中进行了介绍)。请使用 serviceAccountSecretProviderClass 配置属性在替换文件中引用这些内容。

设置为在 Vault 中存储服务账号 Secret

安装 CSI 驱动程序和 Vault 提供程序

如果您尚未使用 Helm 在集群上安装 CSI 驱动程序,请按照 Secrets Store CSI 驱动程序:安装中的说明操作。如需了解详情,请参阅 Vault 文档中的安装 Vault CSI 提供程序

如需了解 Apigee Hybrid 支持的最低 CSI 驱动程序版本,请参阅 Apigee Hybrid 支持的平台和版本

创建 Vault Secret、政策和角色

使用 Vault 界面或 API 创建 Secret,并为 Apigee Hybrid 使用的 Kubernetes 服务账号授予权限以读取这些 Secret。

  1. 按以下格式创建特定于组织和环境的 Secret:
    密钥Secret 数据
    secret/data/apigee/orgsakeys
    {
      "cassandraBackup": "***",
      "cassandraRestore": "***",
      "connectAgent": "***",
      "logger": "***",
      "mart": "***",
      "metrics": "***",
      "mint": "***",
      "udca": "***",
      "watcher": "***"
    }
    secret/data/apigee/envsakeys-ENV_NAME
    {
      "runtime": "***",
      "synchronizer": "***",
      "udca": "***". 
    }

    将每对中的 "***" 替换为与 Apigee 组件对应的 Google 服务账号的 .json 文件内容。apigee-cassandra-backupapigee-cassandra-restore 都使用 apigee-cassandra 服务账号。例如:

    {
      "cassandraBackup": "{
        "type": "service_account",
        "project_id": "myhybridorg",
        "private_key_id": "PRIVATE_KEY_ID",
        "private_key": "-----BEGIN PRIVATE KEY-----\nPRIVATE_KEY_TEXT\n-----END PRIVATE KEY-----\n",
        "client_email": "apigee-cassandra@myhybridorg.iam.gserviceaccount.com",
        "client_id": "123456789012345678901",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/apigee-cassandra%40myhybridorg.iam.gserviceaccount.com",
        "universe_domain": "googleapis.com"
      }",
      "cassandraRestore":...
    ...
    }
        
  2. 授予对组织 Secret 的访问权限。创建名为 orgsakeys-auth-policy.txt 的文本文件,其中包含以下内容:
    path "secret/data/apigee/orgsakeys" {
      capabilities = ["read"]
    }
  3. 在 Vault 中,创建政策以授予对组织 Secret 的访问权限:
    vault policy write apigee-orgsakeys-auth orgsakeys-auth-policy.txt
  4. 对于每个环境,创建名为 envsakeys-ENV_NAME-auth-policy.txt 的文本文件,其中包含以下内容:
    path "secret/data/apigee/envsakeys-ENV_NAME" {
      capabilities = ["read"]
    }

    对每个环境重复执行此步骤。

  5. 在 Vault 中,创建政策以授予对环境 Secret 的访问权限:
    vault policy write apigee-envsakeys-ENV_NAME-auth envsakeys-ENV_NAME-auth-policy.txt

    对每个环境重复执行此步骤。

  6. 创建一个名为 generate-encoded-sas.sh 的脚本,其中包含以下内容:
    # generate-encoded-sas.sh
    
    ORG=$APIGEE_ORG            # Apigee organization name
    ENVS=$APIGEE_ENV_LIST      # comma separated env names, for example: dev,prod
    
    ORG_SHORT_NAME=$(echo $ORG | head -c 15)
    ENCODE=$(echo -n $ORG | shasum -a 256 | head -c 7)
    ORG_ENCODE=$(echo "$ORG_SHORT_NAME-$ENCODE")
    NAMES=apigee-manager,apigee-cassandra-default,apigee-cassandra-backup-sa,apigee-cassandra-restore-sa,apigee-cassandra-schema-setup-${ORG_ENCODE},apigee-cassandra-schema-val-${ORG_ENCODE},apigee-cassandra-user-setup-${ORG_ENCODE},apigee-mart-${ORG_ENCODE},apigee-mint-task-scheduler-${ORG_ENCODE},apigee-connect-agent-${ORG_ENCODE},apigee-watcher-${ORG_ENCODE},apigee-udca-${ORG_ENCODE},apigee-metrics-apigee-telemetry,apigee-open-telemetry-collector-apigee-telemetry,apigee-logger-apigee-telemetry
    
    for ENV in ${ENVS//,/ }
    do
      ENV_SHORT_NAME=$(echo $ENV | head -c 15)
      ENCODE=$(echo -n $ORG:$ENV | shasum -a 256 | head -c 7)
      ENV_ENCODE=$(echo "$ORG_SHORT_NAME-$ENV_SHORT_NAME-$ENCODE")
      NAMES+=,apigee-synchronizer-${ENV_ENCODE},apigee-runtime-${ENV_ENCODE}
    done
    
    echo $NAMES
    
  7. 运行该脚本以生成将政策绑定到的服务账号名称列表:
    ./generate-encoded-sas.sh

    输出应该是以英文逗号分隔的 Kubernetes 服务账号名称列表,类似于以下示例:

    ./generate-encoded-sas.sh
    apigee-manager,apigee-cassandra-default,apigee-cassandra-backup-sa,
    apigee-cassandra-restore-sa,apigee-cassandra-schema-setup-myhybrido
    rg-5b044c1,apigee-cassandra-schema-val-myhybridorg-5b044c1,apigee-c
    assandra-user-setup-myhybridorg-5b044c1,apigee-mart-myhybridorg-5b0
    44c1,apigee-mint-task-scheduler-myhybridorg-5b044c1,apigee-connect-
    agent-myhybridorg-5b044c1,apigee-watcher-myhybridorg-5b044c1,apigee
    -udca-myhybridorg-5b044c1,apigee-metrics-apigee-telemetry,apigee-op
    en-telemetry-collector-apigee-telemetry,apigee-logger-apigee-teleme
    try,apigee-synchronizer-myhybridorg-dev-ee52aca,apigee-runtime-myhy
    bridorg-dev-ee52aca,apigee-synchronizer-myhybridorg-prod-2d0221c,ap
    igee-runtime-myhybridorg-prod-2d0221c
  8. 复制输出文本并分为各个列表,组织服务账号名称有一个对应的列表,而每个环境的环境服务账号名称都有一个对应的单独列表。组织服务账号是输出列表中的前几个账号(直到 apigee-logger-apigee-telemetry)。

    上一个示例中的组织服务名称列表

    apigee-manager,apigee-cassandra-default,apigee-cassandra-backup-sa,
    apigee-cassandra-restore-sa,apigee-cassandra-schema-setup-myhybrido
    rg-5b044c1,apigee-cassandra-schema-val-myhybridorg-5b044c1,apigee-c
    assandra-user-setup-myhybridorg-5b044c1,apigee-mart-myhybridorg-5b0
    44c1,apigee-mint-task-scheduler-myhybridorg-5b044c1,apigee-connect-
    agent-myhybridorg-5b044c1,apigee-watcher-myhybridorg-5b044c1,apigee
    -udca-myhybridorg-5b044c1,apigee-metrics-apigee-telemetry,apigee-op
    en-telemetry-collector-apigee-telemetry,apigee-logger-apigee-teleme
    try

    环境服务账号名称采用 apigee-synchronizer-ORG_NAME-ENV_NAME-HASH_TEXTapigee-runtime-ORG_NAME-ENV_NAME-HASH_TEXT 模式。系统会针对每个环境将它们分为单独的列表。例如,上一个示例的输出可分为以下两个列表:

    dev 环境:

    apigee-synchronizer-myhybridorg-dev-ee52aca,apigee-runtime-myhybrid
    org-dev-ee52aca

    prod 环境:

    apigee-synchronizer-myhybridorg-prod-2d0221c,apigee-runtime-myhybri
    dorg-prod-2d0221c
  9. 使用政策创建绑定组织特定 Apigee 服务账号的 Vault 角色:
    vault write auth/kubernetes/role/apigee-orgsakeys \
        bound_service_account_names=LIST_OF_ORG_SA_NAMES \
        bound_service_account_namespaces=apigee \
        policies=apigee-orgsakeys-auth \
        ttl=1m
    
  10. 对于每个环境,为其服务账号密钥创建 Vault 角色:
    vault write auth/kubernetes/role/apigee-envsakeys-ENV_NAME \
        bound_service_account_names=LIST_OF_ENV_NAME_SA_NAMES \
        bound_service_account_namespaces=apigee \
        policies=apigee-envsakeys-ENV_NAME-auth \ 
        ttl=1m
    

    对每个环境重复执行此步骤。

创建 SecretProviderClass 对象

SecretProviderClass 资源告知 CSI 驱动程序在请求 Secret 时要通信的提供程序。必须通过此对象配置服务账号密钥。下表显示了 Apigee Hybrid 预期的文件名 (objectNames):

服务账号预期的 Secret 文件名
Cassandra 备份 cassandraBackup
Cassandra 恢复 cassandraRestore
Connect Agent connectAgent
Logger logger
MART mart
指标 metrics
创收 mint
运行时 runtime
同步器 synchronizer
UDCA udca
Watcher watcher
  1. 使用以下 SecretProviderClass 模板为特定于组织的 Secret 配置此资源:
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: apigee-orgsakeys-spc
    spec:
      provider: vault
      parameters:
        roleName: apigee-orgsakeys
        vaultAddress: VAULT_ADDRESS
        # "objectName" is an alias used within the SecretProviderClass to reference
        # that specific secret. This will also be the filename containing the secret.
        # Apigee Hybrid expects these exact values so they must not be changed.
        # "secretPath" is the path in Vault where the secret should be retrieved.
        # "secretKey" is the key within the Vault secret response to extract a value from.
        objects: |
          - objectName: "cassandraBackup"
            secretPath: ""
            secretKey: ""
          - objectName: "cassandraRestore"
            secretPath: ""
            secretKey: ""
          - objectName: "connectAgent"
            secretPath: ""
            secretKey: ""
          - objectName: "logger"
            secretPath: ""
            secretKey: ""
          - objectName: "mart"
            secretPath: ""
            secretKey: ""
          - objectName: "metrics"
            secretPath: ""
            secretKey: ""
          - objectName: "mint"
            secretPath: ""
            secretKey: ""
          - objectName: "udca"
            secretPath: ""
            secretKey: ""
          - objectName: "watcher"
            secretPath: ""
            secretKey: ""
    

    VAULT_ADDRESS 是 Vault 服务器运行的端点。如果 Vault 与 Apigee 在同一集群中运行,则格式通常为 http://vault.APIGEE_NAMESPACE.svc.cluster.local:VAULT_SERVICE_PORT

    将模板保存到名为 spc-org.yaml 的文件中。

  2. 将特定于组织的 SecretProviderClass 应用于 Apigee 命名空间:
    kubectl -n apigee apply -f spc-org.yaml
  3. 对于每个环境,使用以下 SecretProviderClass 模板为特定于环境的 Secret 配置此资源。对每个环境重复执行此步骤:
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: apigee-envsakeys-ENV_NAME-spc
    spec:
      provider: vault
      parameters:
        roleName: apigee-envsakeys-ENV_NAME
        vaultAddress: VAULT_ADDRESS
        # "objectName" is an alias used within the SecretProviderClass to reference
        # that specific secret. This will also be the filename containing the secret.
        # Apigee Hybrid expects these exact values so they must not be changed.
        # "secretPath" is the path in Vault where the secret should be retrieved.
        # "secretKey" is the key within the Vault secret response to extract a value from.
        objects: |
          - objectName: "runtime"
            secretPath: ""
            secretKey: ""
          - objectName: "synchronizer"
            secretPath: ""
            secretKey: ""
          - objectName: "udca"
            secretPath: ""
            secretKey: ""
    

    VAULT_ADDRESS 是 Vault 服务器运行的端点。如果 Vault 与 Apigee 在同一集群中运行,则格式通常为 http://vault.APIGEE_NAMESPACE.svc.cluster.local:VAULT_SERVICE_PORT

    将模板保存到名为 spc-env-ENV_NAME.yaml 的文件中。

  4. 对于每个环境,将特定于环境的 SecretProviderClass 应用于 Apigee 命名空间:
    kubectl -n apigee apply -f spc-env-ENV_NAME.yaml

    对每个环境重复执行此步骤。

为 Google 服务账号启用外部 Secret

  1. 在替换文件中,添加 serviceAccountSecretProviderClassenvs[].serviceAccountSecretProviderClass 配置属性,以便为 Google 服务账号启用外部 Secret。您可以移除或注释掉 serviceAccountPathserviceAccountPaths 配置属性:
    serviceAccountSecretProviderClass: apigee-orgsakeys-spc
    
    envs:
      - name: ENV_NAME
        serviceAccountSecretProviderClass: apigee-envsakeys-ENV_NAME-spc
  2. 应用每个 Helm 图表:
    helm upgrade datastore apigee-datastore/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
    helm upgrade telemetry apigee-telemetry/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
    helm upgrade redis apigee-redis/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
    helm upgrade ORG_NAME apigee-org/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
  3. 对于每个环境,应用 apigee-env 图表:
    helm upgrade ENV_NAME apigee-env/ \
        --install \
        --namespace apigee \
        --set env=ENV_NAME \
        --atomic \
        -f overrides.yaml
    

回滚到使用服务账号证书文件

如果您需要回滚到使用存储的 Google 服务账号证书文件,请按照以下步骤操作:

  1. 更新替换文件:
    1. 移除或注释掉 serviceAccountSecretProviderClassenvs:serviceAccountSecretProviderClass 行。
    2. 添加 serviceAccountPathserviceAccountPaths 配置属性,其中包含相应服务账号的路径。

    例如:

    # serviceAccountSecretProviderClass: apigee-orgsakeys-spc - (commented out)
    
    cassandra:
      backup:
        serviceAccountPath: service-accounts/myhybridorg-apigee-cassandra.json
      restore:
        serviceAccountPath: service-accounts/myhybridorg-apigee-cassandra.json
    
    connectAgent:
      serviceAccountPath: service-accounts/myhybridorg-apigee-mart.json
    
    envs:
      - name: test
      # serviceAccountSecretProviderClass: apigee-envsakeys-spc - (commented out)
        serviceAccountPaths:
          runtime: service-accounts/myhybridorg-apigee-runtime.json
          synchronizer: service-accounts/myhybridorg-apigee-synchronizer.json
    
    logger:
      serviceAccountPath: service-accounts/myhybridorg-apigee-logger.json
    
    mart:
      serviceAccountPath: service-accounts/myhybridorg-apigee-mart.json
    
    metrics:
      serviceAccountPath: service-accounts/myhybridorg-apigee-metrics.json
    
    udca:
      serviceAccountPath: service-accounts/myhybridorg-apigee-udca.json
    
    watcher:
      serviceAccountPath: service-accounts/myhybridorg-apigee-watcher.json
    
  2. 应用每个 Helm 图表:
    helm upgrade datastore apigee-datastore/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
    helm upgrade telemetry apigee-telemetry/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
    helm upgrade redis apigee-redis/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
    helm upgrade ORG_NAME apigee-org/ \
        --install \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
    
  3. 对于每个环境,应用 apigee-env 图表:
    helm upgrade ENV_NAME apigee-env/ \
        --install \
        --namespace apigee \
        --set env=ENV_NAME \
        --atomic \
        -f overrides.yaml
    

    对每个环境重复执行此步骤。