在 Hashicorp Vault 中儲存 Cassandra 密鑰

在 Hashicorp Vault 中儲存 Cassandra 密鑰

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

在 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 就能掛接儲存在外部保管箱中的多個密鑰、金鑰和憑證。

Cassandra 使用者和密碼

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

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

詳情請參閱 cassandra 設定屬性

設定外部機密資料整合

為 Apigee hybrid 設定 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:下列指令說明如何建立單一 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 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 1.15.0 支援下列 Helm 圖表版本:

軟體 版本
Secrets Store CSI 驅動程式 v1.4.1
保管箱 1.15.2
  1. 請按照Secrets Store CSI 驅動程式安裝操作說明在叢集上安裝 CSI 驅動程式。CSI 驅動程式有用於安裝的 Helm 資訊套件。
  2. 如果您尚未安裝 Vault CSI 供應器,請按照「安裝 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 密鑰

  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,本節會取代疑難排解部分的「建立用於偵錯的用戶端容器」說明。

本節將說明如何建立用戶端容器,以便您存取 cqlshCassandra 偵錯公用程式。這些公用程式可讓您查詢 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.15.0"
          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