在 Hashicorp Vault 中儲存 Cassandra 密鑰

在 Hashicorp Vault 中儲存 Cassandra 密鑰

這項功能可讓您在外部密碼管理工具 Hashicorp Vault 中,儲存 Apigee Hybrid 的 Cassandra 資料庫憑證。外部密鑰管理工具可讓您管理密鑰在 Kubernetes 中的儲存方式,包括管理資料落地和精細的存取控制。

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

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

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

Cassandra 使用者和密碼

您需要為下列 Cassandra 使用者建立密碼。變更預設值,以符合貴機構的安全性政策。

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

詳情請參閱 Cassandra 設定屬性

設定外部密鑰整合

為 Apigee Hybrid 設定 Vault 整合功能時,請按照下列程序操作。

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

請按照下列程序在 Vault 中建立密鑰,並允許混合式安裝存取這些密鑰。

建立 Vault 密鑰、政策和角色

  1. 確認目前的 Kubernetes 內容已設為叢集:
    kubectl config current-context
  2. 使用 Vault API、CLI 或 UI 建立 Cassandra 密鑰。您建立的密碼值必須與叢集中目前使用的 Cassandra 使用者名稱和密碼相符。
    • 私密金鑰:可以使用任何私密金鑰 (或多個金鑰的組合),例如:
      secret/data/apigee/cassandra
    • 私密資料:Apigee Hybrid 需要下列 Cassandra 使用者的使用者名稱和密碼配對:
      Cassandra 使用者
      管理員
      DDL
      預設
      DML
      JMX
      Jolokia
      這些使用者名稱和密碼值可分散在任意數量的密鑰中。
    • Vault CLI:下列指令說明如何建立單一密碼,其中包含所有必要的使用者名稱和密碼:
      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 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-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 1.13.4 版支援下列 Helm 圖表版本:

軟體 版本
Secrets Store CSI 驅動程式 v1.4.4
保管箱 1.17.2
  1. 請按照 Secrets Store CSI 驅動程式安裝操作說明,在叢集上安裝 CSI 驅動程式。CSI 驅動程式有 Helm 資訊套件可供安裝。
  2. 如果尚未安裝,請按照「安裝 Vault CSI 供應商」一文的說明進行安裝。

建立 SecretProviderClass 物件

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

Cassandra 使用者 預期密鑰檔案名稱
管理員 adminUsernameadminPassword
DDL ddlUsernameddlPassword
預設 cassandradefaultPassword
DML dmlUsernamedmlPassword
JMX jmxUsernamejmxPassword
Jolokia jolokiaUsernamejolokiaPassword
  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 啟用外部密鑰

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

    請參閱 cassandra.auth.secretProviderClass

  2. 使用 helm upgrade 將變更套用至 apigee-operatorapigee-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. 確認是否使用外部密鑰。啟用外部密鑰後,系統會新增參照密鑰的 VolumeVolume MountEnvironment Variable
    • 驗證 apigee-controller-manager 部署作業。

      確認名為 apigee-external-secretsVolume 存在,並參照上方建立的 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-secretsVolumeMount 存在:

      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
      }

      確認是否有參照外部密鑰的 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-operatorapigee-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. 容器會使用 Pod 中的 TLS 憑證。apigee-cassandra-user-setup 第一步是擷取這個憑證名稱:
    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.13.4"
          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