在 Hashicorp Vault 中儲存 Cassandra 密鑰

將 Cassandra 密鑰儲存在 Hashicorp Vault

這項功能可讓您將 Apigee Hybrid 的 Cassandra DB 憑證儲存在 Hashicorp Vault (外部 Secret Manager) 中。外部 Secret Manager 可讓您管理 Kubernetes 中的 Secret 儲存方式,包括管理資料落地和精細的存取控管。

在 Apigee Hybrid 1.10 版之前,為 Cassandra 使用者提供密碼的唯一方法,是在 overrides.yaml 中指定密碼。這些密碼會儲存在 Kubernetes 密鑰中。例如:

cassandra:
  auth:
    default:
      password: "********"
    admin:
      password: "********"
    ddl:
      password: "********"
    dml:
      password: "********"
    jmx:
      username: "jmxuser"
      password: "********"
    jolokia:
      username: "apigee"
      password: "********"

使用 Hashicorp Vault 時,您可以透過 Kubernetes Secrets Store CSI Driver API (SecretProviderClass) 提供這些密碼。這樣一來,Kubernetes 就能掛接儲存在外部 Vault 中的多個密鑰、金鑰和憑證。

Cassandra 使用者和密碼

您必須為下列 Cassandra 使用者建立密鑰。請根據貴機構的安全政策變更預設值。

Cassandra 使用者 預設使用者名稱 預設密碼
管理員 admin_user "********"
DDL ddl_user "********"
預設 cassandra 注意:預設使用者名稱一律須為「cassandra」 "********"
DML dml_user "********"
JMX "jmxuser" "********"
Jolokia "apigee" "********"

詳情請參閱「cassandra 設定屬性」。

設定外部 Secret 整合

為 Apigee hybrid 設定 Vault 整合功能,包含下列程序。

  • 在前兩項程序中,您會直接與 Vault 互動。
  • 在第三和第四項程序中,您會將設定套用至 Kubernetes 叢集。

請按照下列程序在 Vault 中建立 Secret,並讓混合式安裝作業能存取這些 Secret。

建立 Vault 密鑰、政策和角色

  1. 確認目前的 Kubernetes 內容已設為叢集:
    kubectl config current-context
  2. 使用 Vault API、CLI 或 UI 建立 Cassandra 密鑰。您建立的密鑰值必須與叢集目前使用的 Cassandra 使用者名稱和密碼相符。
    • Secret key:可以使用任何 Secret key (或多個金鑰的組合),例如:
      secret/data/apigee/cassandra
    • Secret 資料:Apigee Hybrid 預期下列 Cassandra 使用者會提供使用者名稱和密碼組合:
      Cassandra 使用者
      管理員
      DDL
      預設
      DML
      JMX
      Jolokia
      這些使用者名稱和密碼值可以分散在任意數量的 Secret 金鑰中。
    • Vault CLI:下列指令說明如何建立單一 Secret,其中包含所有必要的使用者名稱和密碼:
      vault kv put secret/apigee/cassandra \
          adminUsername="ADMIN_USERNAME" \
          adminPassword="ADMIN_PASSWORD" \
          ddlUsername="DDL_USERNAME" \
          ddlPassword="DDL_PASSWORD" \
          defaultUsername="cassandra" \
          defaultPassword="DEFAULT_PASSWORD" \
          dmlUsername="DML_USERNAME" \
          dmlPassword="DML_PASSWORD" \
          jmxUsername="JMX_USERNAME" \
          jmxPassword="JMX_PASSWORD" \
          jolokiaUsername="JOLOKIA_USERNAME" \
          jolokiaPassword="JOLOKIA_PASSWORD"
      每位使用者的預設使用者名稱如下:
      Cassandra 使用者 預設值
      管理員 admin_user
      DDL ddl_user
      預設 cassandra
      DML dml_user
      JMX jmxuser
      Jolokia apigee
  3. 在 Vault 中建立政策,授予您剛建立的密鑰存取權。
    1. 建立政策檔案 (建議名稱:apigee-cassandra-auth.txt),並加入下列內容:
      path "secret/data/apigee/cassandra" {
        capabilities = ["read"]
      }
      如果您建立了多個密鑰,則必須將每個密鑰新增至政策檔案:
      path "secret/data/apigee/cassandra/admin" {
        capabilities = ["read"]
      }
      
      path "secret/data/apigee/cassandra/ddl" {
        capabilities = ["read"]
      }
    2. 將政策套用至 Vault:
      vault policy write apigee-cassandra-auth apigee-cassandra-auth.txt

      您可以使用標準輸入內容建立政策,而不必從檔案讀取:

      echo 'path "secret/data/apigee/cassandra" { capabilities = ["read"] }' | vault policy write apigee-cassandra-auth -
  4. 將政策繫結至 Apigee Cassandra Kubernetes 服務帳戶。
    1. 定義下列環境變數:
      export ORG_NAME=APIGEE_ORG_NAME
      export ENVS_LIST=LIST_OF_APIGEE-ENVS
      export APIGEE_NAMESPACE=YOUR_APIGEE_NAMESPACE

      其中:

      • ORG_NAME 是 Apigee 組織的名稱。
      • ENVS_LIST 是以半形逗號分隔的 Apigee 環境清單,例如 dev,prod。
      • APIGEE_NAMESPACE 是 Apigee 命名空間。預設值為 apigee。
    2. 建立含有下列內容的指令碼。指令碼名稱不限。在以下範例中,指令碼名稱為 create-vault-cassandra-role.sh:
      # create-vault-cassandra-role.sh
      
      ORG=ORG_NAME  # ORG name
      ENVS=ENVS_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-guardrails-sa,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}
      
      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
      
    3. 執行指令碼,並將輸出內容指派給 SERVICE_ACCOUNT_NAMES 變數。 這會建立以半形逗號分隔的 Kubernetes 服務帳戶名稱清單。
      export SERVICE_ACCOUNT_NAMES=$(./create-vault-cassandra-role)

      確認變數已填入清單:

      echo $SERVICE_ACCOUNT_NAMES
    4. 使用 Vault CLI 建立角色,將政策繫結至 Kubernetes 服務帳戶:
      vault write auth/kubernetes/role/cassandra \
          bound_service_account_names=${SERVICE_ACCOUNT_NAMES} \
          bound_service_account_namespaces=${APIGEE_NAMESPACE} \
          policies=apigee-cassandra-auth \
          ttl=1m

安裝 CSI 驅動程式和 Vault 供應商

Apigee hybrid v1.17.3 支援下列 Helm 圖表版本:

軟體 版本
Secrets Store CSI 驅動程式 v1.4.1
保管箱 1.16.2
  1. 按照 Secrets Store CSI 驅動程式安裝操作說明,在叢集上安裝 CSI 驅動程式。CSI 驅動程式提供 Helm 圖表,方便您安裝。
  2. 如果您尚未安裝 Vault CSI 供應器,請按照「安裝 Vault CSI 供應器」中的操作說明安裝。

建立 SecretProviderClass 物件

SecretProviderClass 資源會告知 CSI 驅動程式,在要求 Secret 時要與哪個供應商通訊。Cassandra 使用者的憑證必須透過這個物件設定。下表列出 Apigee Cassandra 預期的檔案名稱 (objectName):

Cassandra 使用者 預期的密鑰檔案名稱
管理員 adminUsername、adminPassword
DDL ddlUsername、ddlPassword
預設 cassandra、defaultPassword
DML dmlUsername、dmlPassword
JMX jmxUsername、jmxPassword
Jolokia jolokiaUsername、jolokiaPassword
  1. 為 SecretProviderClass 建立 YAML 檔案。檔案名稱不限,例如:spc.yaml。使用下列 SecretProviderClass 範本設定這項資源:
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: apigee-cassandra-auth-spc
    spec:
      provider: vault
      parameters:
        roleName: apigee-cassandra-auth  # the roleName should match the vault role you created earlier in this procedure
    
        # vaultAddress is the endpoint your Vault server is running at.
        # If Vault is running in the same cluster as Apigee, the format will generally be:
        # http://vault.<namespace>.svc.cluster.local:<vaultServicePort>
        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 Cassandra 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.
        # For example, if the Vault secret is located at `secret/data/apigee/cassandra`
        # and you want to specify the admin password, you would use the following:
        # - objectName: "adminPassword"
        #   secretPath: "secret/data/apigee/cassandra"
        #   secretKey: "key within Vault secret specifying the admin password"
        objects: |
          - objectName: "adminUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "adminPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "defaultUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "defaultPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "ddlUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "ddlPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "dmlUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "dmlPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "jolokiaUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "jolokiaPassword"
            secretPath: ""
            secretKey: ""
          - objectName: "jmxUsername"
            secretPath: ""
            secretKey: ""
          - objectName: "jmxPassword"
            secretPath: ""
            secretKey: ""
  2. 將 SecretProviderClass 套用至 apigee 命名空間:
    kubectl -n $APIGEE_NAMESPACE apply -f spc.yaml

啟用 Cassandra 的外部 Secret

  1. 在 overrides.yaml 中,新增下列設定,為 Cassandra 啟用外部 Secret:
    cassandra:
      auth:
        secretProviderClass: apigee-cassandra-auth-spc  # The name of the SecretProviderClass created in spc.yaml.

    請參閱 cassandra.auth.secretProviderClass。

  2. 使用 helm upgrade 將變更套用至 apigee-operator 和 apigee-datastore 元件:
    • apigee-operator 中的資料儲存庫控制器會在區域擴充期間,參與 Cassandra 停用和資料複製作業。這些工作需要 JMX 和 Jolokia 憑證。
      helm upgrade operator apigee-operator/ \
        --namespace $APIGEE_NAMESPACE> \
        --atomic \
        -f overrides.yaml
    • apigee-datastore 提供憑證,供 apigee-runtime、Synchronizer 和 MART 等下游元件連線至 Cassandra 時使用。
      helm upgrade datastore apigee-datastore/ \
        --namespace $APIGEE_NAMESPACE \
        --atomic \
        -f overrides.yaml
  3. 確認是否使用外部 Secret。啟用外部 Secret 後,系統會新增參照 Secret 的 Volume、Volume Mount 和 Environment Variable。
    • 驗證 apigee-controller-manager 部署作業。

      確認名為 apigee-external-secrets 的 Volume 存在,且參照上方建立的 SecretProviderClass:

      kubectl -n $APIGEE_NAMESPACE get deployment apigee-controller-manager -o jsonpath='{.spec.template.spec.volumes[?(@.name=="apigee-external-secrets")]}'

      輸出內容範例:

      {
        "csi": {
          "driver": "secrets-store.csi.k8s.io",
          "readOnly": true,
          "volumeAttributes": {
            "secretProviderClass": "apigee-cassandra-auth-spc"
          }
        },
        "name": "apigee-external-secrets"
      }

      確認名為 apigee-external-secrets 的 VolumeMount 存在:

      kubectl -n $APIGEE_NAMESPACE get deployment apigee-controller-manager -o jsonpath='{.spec.template.spec.containers[?(@.name=="manager")].volumeMounts[?(@.name=="apigee-external-secrets")]}'

      輸出內容範例:

      {
        "mountPath": "/opt/apigee/externalsecrets",
        "name": "apigee-external-secrets",
        "readOnly": true
      }

      確認是否有參照外部 Secret 的 Environment Variable:

      kubectl -n $APIGEE_NAMESPACE get deployment apigee-controller-manager -o jsonpath='{.spec.template.spec.containers[?(@.name=="manager")].env}'

      輸出內容範例:

      [
        ...
        {
          "name": "CASSANDRA_JOLOKIA_USERNAME_PATH",
          "value": "/opt/apigee/externalsecrets/jolokiaUsername"
        },
        {
          "name": "CASSANDRA_JOLOKIA_PASSWORD_PATH",
          "value": "/opt/apigee/externalsecrets/jolokiaPassword"
        }
      ]

復原至 K8s Secret

  1. 如要改回非外部密鑰,請移除 overrides.yaml 中的 secretProviderClass 設定,並使用先前的設定:
    cassandra:
          auth:
            secretProviderClass: apigee-cassandra-auth-spc # remove this line
  2. 使用 helm upgrade 將變更套用至 apigee-operator 和 apigee-datastore 元件:
    helm upgrade operator apigee-operator/ \
      --namespace $APIGEE_NAMESPACE \
      --atomic \
      -f overrides.yaml
    helm upgrade datastore apigee-datastore/ \
      --namespace $APIGEE_NAMESPACE \
      --atomic \
      -f overrides.yaml

疑難排解:建立用戶端容器進行偵錯

如果您使用 Vault,請按照本節的操作說明,取代疑難排解一節中的「建立用於偵錯的用戶端容器」操作說明。

本節說明如何建立用戶端容器,以便存取 Cassandra 偵錯公用程式,例如 cqlsh。這些公用程式可讓您查詢 Cassandra 資料表,並可用於偵錯。

建立用戶端容器

如要建立用戶端容器,請按照下列步驟操作:

  1. 容器會使用 apigee-cassandra-user-setup pod 的 TLS 憑證。第一步是擷取這個憑證名稱:
    kubectl get secrets -n APIGEE_NAMESPACE --field-selector type=kubernetes.io/tls | grep apigee-cassandra-user-setup | awk '{print $1}'

    這個指令會傳回憑證名稱。例如:apigee-cassandra-user-setup-rg-hybrid-b7d3b9c-tls。

  2. 開啟新檔案,並在當中貼上以下 Pod 規格:
    apiVersion: v1
      kind: Pod
      metadata:
        labels:
        name: CASSANDRA_CLIENT_NAME   # For example: my-cassandra-client
        namespace: $APIGEE_NAMESPACE
      spec:
        containers:
        - name: CASSANDRA_CLIENT_NAME
          image: "gcr.io/apigee-release/hybrid/apigee-hybrid-cassandra-client:1.17.3"
          imagePullPolicy: Always
          command:
          - sleep
          - "3600"
          env:
          - name: CASSANDRA_SEEDS
            value: apigee-cassandra-default.apigee.svc.cluster.local
          - name: APIGEE_DML_USERNAME_PATH
            value: /opt/apigee/externalsecrets/dmlUsername
          - name: APIGEE_DML_PASSWORD_PATH
            value: /opt/apigee/externalsecrets/dmlPassword
          volumeMounts:
          - mountPath: /opt/apigee/ssl
            name: tls-volume
            readOnly: true
          - name: apigee-external-secrets
            mountPath: /opt/apigee/externalsecrets
            readOnly: true
        volumes:
        - name: tls-volume
          secret:
            defaultMode: 420
            secretName: apigee-cassandra-user-setup-vaibhavhybridor-8b3e61d-tls
        - name: apigee-external-secrets
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: apigee-cass-password
        serviceAccount: apigee-cassandra-default
        serviceAccountName: apigee-cassandra-default
        restartPolicy: Never
  3. 使用 .yaml 副檔名儲存檔案。例如:my-spec.yaml。
  4. 將規格套用至叢集:
    kubectl apply -f my-spec.yaml -n $APIGEE_NAMESPACE
  5. 登入容器:
    kubectl exec -n CASSANDRA_CLIENT_NAME -it -- bash
  6. 使用下列指令連線至 Cassandra cqlsh 介面。請按照下列指示輸入指令:
    APIGEE_DML_USER=$(cat "$APIGEE_DML_USERNAME_PATH")
    export APIGEE_DML_USER
    APIGEE_DML_PASSWORD=$(cat "$APIGEE_DML_PASSNAME_PATH")
    export APIGEE_DML_PASSWORD
    cqlsh ${CASSANDRA_SEEDS} -u ${APIGEE_DML_USER} -p ${APIGEE_DML_PASSWORD} --ssl

刪除用戶端 Pod

使用下列指令刪除 Cassandra 用戶端 Pod:

kubectl delete pods -n $APIGEE_NAMESPACE cassandra-client