Hashicorp Vault에 Cassandra 보안 비밀 저장

Hashicorp Vault에 Cassandra 보안 비밀 저장

이 기능을 사용하면 외부 보안 비밀 관리자인 Hashicorp Vault에 Apigee Hybrid의 Cassandra DB 사용자 인증 정보를 저장할 수 있습니다. 외부 보안 비밀 관리자를 사용하면 데이터 상주 관리와 세분화된 액세스 제어 관리 등 Kubernetes에 보안 비밀이 저장되는 방식을 관리할 수 있습니다.

Apigee Hybrid 버전 1.10 이전에는 Cassandra 사용자에게 비밀번호를 제공하는 유일한 방법은 override.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 구성 속성을 참조하세요.

외부 보안 비밀 통합 구성

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에 적용합니다.
      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
      export NAMESPACES=apigee-system,${APIGEE_NAMESPACE}

      각 항목의 의미는 다음과 같습니다.

      • ORG_NAME는 Apigee 조직의 이름입니다.
      • ENVS_LIST는 쉼표로 구분된 Apigee 환경 목록입니다(예: dev,prod).
      • APIGEE_NAMESPACE는 Apigee 네임스페이스입니다. 기본값은 apigee입니다.
      • NAMESPACES는 쉼표로 구분된 Apigee, apigee-system, 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=${NAMESPACES} \
          policies=apigee-cassandra-auth \
          ttl=1m

CSI 드라이버 및 Vault 제공업체 설치

Apigee Hybrid 1.12.3에서는 다음 Helm 차트 버전을 지원합니다.

소프트웨어 버전
Secrets Store CSI 드라이버 v1.4.1
Vault 1.15.2
  1. Secrets Store CSI 드라이버 설치 안내에 따라 CSI 드라이버를 클러스터에 설치합니다. CSI 드라이버에는 설치를 위한 Helm 차트가 있습니다.
  2. Vault CSI 제공업체를 아직 설치하지 않았으면 Vault CSI 제공업체 설치 안내에 따라 설치합니다.

SecretProviderClass 객체 만들기

SecretProviderClass 리소스는 보안 비밀을 요청할 때 CSI 드라이버에 통신할 제공업체를 알려줍니다. 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. apigeeapigee-system 네임스페이스 모두에 SecretProviderClass를 적용합니다. 다음 명령어에서 네임스페이스는 apigeeapigee-system입니다. 다른 네임스페이스를 사용하는 경우 해당 값을 바꿉니다.
    kubectl -n apigee apply -f spc.yaml
    kubectl -n apigee-system 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-system \
        --atomic \
        -f overrides.yaml
    • apigee-datastore는 Cassandra에 연결할 때 apigee-runtime, 동기화 담당자, MART와 같은 다운스트림 구성요소에서 사용하는 사용자 인증 정보를 제공합니다.
      helm upgrade datastore apigee-datastore/ \
        --namespace apigee \
        --atomic \
        -f overrides.yaml
  3. 외부 보안 비밀이 사용 중인지 확인합니다. 외부 보안 비밀이 사용 설정되면 보안 비밀을 참조하는 새 Volume, Volume Mount, Environment Variable가 추가됩니다.
    • apigee-controller-manager 배포를 확인합니다.

      apigee-external-secrets라는 Volume이 있고 앞에서 만든 SecretProviderClass를 참조하는지 확인합니다.

      kubectl -n apigee-system 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-system 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-system 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-system \
      --atomic \
      -f overrides.yaml
    helm upgrade datastore apigee-datastore/ \
      --namespace apigee \
      --atomic \
      -f overrides.yaml

문제 해결: 디버깅을 위한 클라이언트 컨테이너 만들기

Vault를 사용하는 경우 이 섹션은 디버깅을 위한 클라이언트 컨테이너 만들기 문제 해결 섹션의 안내를 대체합니다.

이 섹션에서는 cqlsh와 같이 Cassandra 디버깅 유틸리티에 액세스할 수 있는 클라이언트 컨테이너를 만드는 방법을 설명합니다. 이러한 유틸리티는 Cassandra 테이블을 쿼리할 수 있고 디버깅 목적에 유용할 수 있습니다.

클라이언트 컨테이너 만들기

클라이언트 컨테이너를 만들려면 다음 단계를 따르세요.

  1. 컨테이너에서 apigee-cassandra-user-setup 포드의 TLS 인증서를 사용합니다. 첫 번째 단계는 이 인증서 이름을 가져오는 것입니다.
    kubectl get secrets -n apigee --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
      spec:
        containers:
        - name: CASSANDRA_CLIENT_NAME
          image: "gcr.io/apigee-release/hybrid/apigee-hybrid-cassandra-client:1.12.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
  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 cassandra-client