Como armazenar secrets do Cassandra no Hashicorp Vault

Como armazenar secrets do Cassandra no Hashicorp Vault

Esse recurso permite armazenar credenciais do Cassandra DB para a Apigee híbrida no Hashicorp Vault, um gerenciador de secrets externo. Com os gerenciadores de secrets externos, você gerencia a forma como os secrets são armazenados no Kubernetes, incluindo o gerenciamento da residência de dados e os controles de acesso refinados.

Antes da versão 1.10 da Apigee híbrida, a única maneira de fornecer senhas para os usuários do Cassandra era especificar a senha em replace.yaml. Essas senhas são armazenadas em secrets do Kubernetes. Exemplo:

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

Com o Hashicorp Vault, é possível fornecer essas senhas por meio da API Kubernetes Secrets Store CSI Driver (SecretProviderClass). Isso permite que o Kubernetes monte vários secrets, chaves e certificados armazenados em um Vault externo.

Usuários e senhas do Cassandra

Você precisará criar secrets para os seguintes usuários do Cassandra. Altere os valores padrão para atender às políticas de segurança da sua organização.

Usuário do Cassandra Nome de usuário padrão Senha padrão
Administrador admin_user "********"
DDL ddl_user "********"
Padrão cassandra Observação: o nome de usuário padrão precisa ser sempre "cassandra" "********"
DML dml_user "********"
JMX "jmxuser" "********"
Jolokia "apigee" "********"

Consulte a propriedade de configuração do Cassandra para mais informações.

Configurar a integração do secret externo

A configuração da integração do Vault para a Apigee híbrida consiste nos procedimentos a seguir.

  • Nos dois primeiros procedimentos, você interage diretamente com o Vault.
  • No terceiro e no quarto procedimentos, você vai aplicar as configurações ao cluster do Kubernetes.

Use os procedimentos a seguir para criar os secrets no Vault e permitir que sua instalação híbrida tenha acesso a eles.

Criar secrets, políticas e papéis do Vault

  1. Verifique se o contexto atual do Kubernetes está definido como seu cluster:
    kubectl config current-context
  2. Use a API Vault, a CLI ou a IU para criar os secrets do Cassandra. Os valores de secret criados precisam corresponder aos nomes de usuário e senhas do Cassandra atualmente usados no cluster.
    • Chave de secret: qualquer chave de secret (ou combinação de várias chaves) pode ser usada. Por exemplo:
      secret/data/apigee/cassandra
    • Dados de secret: a Apigee híbrida espera os pares de nome de usuário e senha dos seguintes usuários do Cassandra:
      Usuários do Cassandra
      Administrador
      DDL
      Padrão
      DML
      JMX
      Jolokia
      É possível distribuir esses valores de nome de usuário e senha em várias chaves secretas.
    • CLI do Vault: o comando a seguir mostra como criar uma chave de secret com todos os nomes de usuário e senhas necessários:
      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"
      Estes são os nomes de usuário padrão de cada usuário:
      Usuário do Cassandra Valor padrão
      Administrador admin_user
      DDL ddl_user
      Padrão cassandra
      DML dml_user
      JMX jmxuser
      Jolokia apigee
  3. No Vault, crie uma política para conceder acesso ao secret que você acabou de criar.
    1. Crie um arquivo de política apigee-cassandra-auth.txt (nome sugerido) com o seguinte conteúdo:
      path "secret/data/apigee/cassandra" {
        capabilities = ["read"]
      }
      Se você criou vários secrets, adicione cada um deles ao arquivo de política:
      path "secret/data/apigee/cassandra/admin" {
        capabilities = ["read"]
      }
      
      path "secret/data/apigee/cassandra/ddl" {
        capabilities = ["read"]
      }
    2. Aplique a política ao Vault:
      vault policy write apigee-cassandra-auth apigee-cassandra-auth.txt

      É possível criar a política usando a entrada padrão em vez de ler em um arquivo:

      echo 'path "secret/data/apigee/cassandra" { capabilities = ["read"] }' | vault policy write apigee-cassandra-auth -
  4. Vincule a política às contas de serviço do Kubernetes do Apigee Cassandra.
    1. Defina as seguintes variáveis de ambiente:
      export ORG_NAME=APIGEE_ORG_NAME
      export ENVS_LIST=LIST_OF_APIGEE-ENVS
      export APIGEE_NAMESPACE=YOUR_APIGEE_NAMESPACE

      Em que:

      • ORG_NAME é o nome da organização da Apigee;
      • ENVS_LIST é uma lista separada por vírgulas dos seus ambientes da Apigee, por exemplo, dev,prod.
      • APIGEE_NAMESPACE é seu namespace da Apigee. O padrão é apigee.
    2. Crie um script com os conteúdos a seguir: O script pode ter qualquer nome. No exemplo a seguir, o nome do script é 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. Execute o script e atribua a saída à variável SERVICE_ACCOUNT_NAMES. Isso vai criar uma lista separada por vírgulas de nomes de contas de serviço do Kubernetes.
      export SERVICE_ACCOUNT_NAMES=$(./create-vault-cassandra-role)

      Verifique se a variável foi preenchida com a lista:

      echo $SERVICE_ACCOUNT_NAMES
    4. Use a CLI do Vault para criar um papel que vincule a política às contas de serviço do 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

Instalar o driver CSI e o provedor do Vault

A Apigee híbrida v1.13.0 oferece suporte às seguintes versões de gráficos do Helm:

Software Versão
Driver CSI do Secrets Store v1.3.4
Vault v0.25.0
  1. Siga as instruções de instalação do driver CSI do Secrets Store para instalar o driver CSI no cluster. O driver CSI tem um gráfico Helm para instalação.
  2. Siga as instruções em Como instalar o provedor CSI do Vault para instalar o provedor CSI do Vault, se ele ainda não tiver sido instalado.

Criar o objeto SecretProviderClass

O recurso SecretProviderClass informa ao driver CSI com qual provedor se comunicar ao solicitar secrets. As credenciais dos usuários do Cassandra precisam ser configuradas por meio desse objeto. A tabela a seguir mostra os nomes dos arquivos (objectNames) esperados pelo Apigee Cassandra:

Usuário do Cassandra Nomes de arquivos de secrets esperados
Administrador adminUsername, adminPassword
DDL ddlUsername, ddlPassword
Padrão cassandra, defaultPassword
DML dmlUsername, dmlPassword
JMX jmxUsername, jmxPassword
Jolokia jolokiaUsername, jolokiaPassword
  1. Crie um arquivo YAML para o SecretProviderClass. O nome do arquivo pode ser qualquer coisa, por exemplo: spc.yaml. Use o seguinte modelo de SecretProviderClass para configurar este recurso:
    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. Aplique o SecretProviderClass ao namespace apigee:
    kubectl -n $APIGEE_NAMESPACE apply -f spc.yaml

Ativar secret externo para Cassandra

  1. No overrides.yaml, adicione a seguinte configuração para ativar o uso de secrets externos para o Cassandra:
    cassandra:
      auth:
        secretProviderClass: apigee-cassandra-auth-spc  # The name of the SecretProviderClass created in spc.yaml.

    Veja cassandra.auth.secretProviderClass.

  2. Use helm upgrade para aplicar a mudança aos componentes apigee-operator e apigee-datastore:
    • O controlador de repositório de dados em apigee-operator participa da desativação do Cassandra e da replicação de dados durante a expansão da região. Essas tarefas exigem as credenciais JMX e Jolokia.
      helm upgrade operator apigee-operator/ \
        --namespace $APIGEE_NAMESPACE> \
        --atomic \
        -f overrides.yaml
    • apigee-datastore fornece credenciais que componentes downstream, como apigee-runtime, Sincronizador e MART, usam ao se conectar ao Cassandra.
      helm upgrade datastore apigee-datastore/ \
        --namespace $APIGEE_NAMESPACE \
        --atomic \
        -f overrides.yaml
  3. Verifique se os secrets externos estão sendo usados. Quando os secrets externos são ativados, novos Volumes, Volume Mounts e Environment Variables são adicionados como referência.
    • Verifique a implantação apigee-controller-manager.

      Verifique se existe um Volume chamado apigee-external-secrets e se faz referência ao SecretProviderClass criado acima:

      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"
      }

      Verifique se existe um VolumeMount chamado apigee-external-secrets:

      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
      }

      Verifique se há Environment Variables que fazem referência a secrets externos:

      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"
        }
      ]

Reverter para o secret do K8s

  1. Para reverter para secrets não externos, remova a configuração secretProviderClass em overrides.yaml e use a configuração anterior:
    cassandra:
          auth:
            secretProviderClass: apigee-cassandra-auth-spc # remove this line
  2. Use helm upgrade para aplicar a mudança aos componentes apigee-operator e 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

Solução de problemas: criar um contêiner do cliente para depuração

Se você usa o Vault, esta seção substitui as instruções da seção de solução de problemas Criar um contêiner de cliente para depuração.

Nesta seção, explicamos como criar um contêiner do cliente em que é possível acessar utilitários de depuração do Cassandra, como cqlsh. Esses utilitários permitem consultar tabelas do Cassandra e podem ser úteis para fins de depuração.

Criar o contêiner do cliente

Para criar o contêiner do cliente, siga estas etapas:

  1. O contêiner usa o certificado TLS do pod apigee-cassandra-user-setup. A primeira etapa é buscar esse nome de certificado:
    kubectl get secrets -n APIGEE_NAMESPACE --field-selector type=kubernetes.io/tls | grep apigee-cassandra-user-setup | awk '{print $1}'

    Esse comando retorna o nome do certificado. Por exemplo, apigee-cassandra-user-setup-rg-hybrid-b7d3b9c-tls.

  2. Abra um novo arquivo e cole a seguinte especificação de pod nele:
    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.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. Salve o arquivo com uma extensão .yaml. Por exemplo, my-spec.yaml.
  4. Aplique a especificação ao cluster:
    kubectl apply -f my-spec.yaml -n $APIGEE_NAMESPACE
  5. Faça login no contêiner:
    kubectl exec -n CASSANDRA_CLIENT_NAME -it -- bash
  6. Conecte-se à interface cqlsh do Cassandra com os comandos a seguir. Digite os comandos exatamente como mostrado:
    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

Como excluir o pod cliente

Use este comando para excluir o pod de cliente do Cassandra:

kubectl delete pods -n $APIGEE_NAMESPACE cassandra-client