Almacenar secretos de Cassandra en HashiCorp Vault

Almacenar secretos de Cassandra en HashiCorp Vault

Esta función te permite almacenar las credenciales de la base de datos de Cassandra de Apigee Hybrid en Hashicorp Vault, un gestor de secretos externo. Los gestores de secretos externos te permiten gestionar cómo se almacenan los secretos en Kubernetes, así como la residencia de los datos y los controles de acceso detallados.

Antes de la versión 1.10 de Apigee hybrid, la única forma de proporcionar contraseñas para los usuarios de Cassandra era especificar la contraseña en overrides.yaml. Estas contraseñas se almacenan en secretos de Kubernetes. Por ejemplo:

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

Con HashiCorp Vault, puedes proporcionar estas contraseñas a través de la API del controlador de CSI de Kubernetes Secrets Store (SecretProviderClass). De esta forma, Kubernetes puede montar varios secretos, claves y certificados almacenados en un Vault externo.

Nombres de usuario y contraseñas de Cassandra

Deberá crear secretos para los siguientes usuarios de Cassandra. Cambia los valores predeterminados para cumplir las políticas de seguridad de tu organización.

Usuario de Cassandra Nombre de usuario predeterminado Contraseña predeterminada
Administrador admin_user "********"
DDL ddl_user "********"
Predeterminado cassandra Nota: El nombre de usuario predeterminado siempre debe ser "cassandra". "********"
DML dml_user "********"
JMX "jmxuser" "********"
Jolokia "apigee" "********"

Consulta la propiedad de configuración de Cassandra para obtener más información.

Configurar la integración de secretos externos

Para configurar la integración de Vault en Apigee hybrid, debes seguir estos procedimientos.

  • En los dos primeros procedimientos, interactúas directamente con Vault.
  • En el tercer y cuarto procedimiento, aplicas las configuraciones a tu clúster de Kubernetes.

Sigue los procedimientos que se indican a continuación para crear los secretos en Vault y permitir que tu instalación híbrida tenga acceso a ellos.

Crear secretos, políticas y roles de Vault

  1. Verifica que el contexto de Kubernetes actual esté configurado en tu clúster:
    kubectl config current-context
  2. Usa la API, la CLI o la interfaz de usuario de Vault para crear los secretos de Cassandra. Los valores secretos que crees deben coincidir con los nombres de usuario y las contraseñas de Cassandra que se utilicen en tu clúster.
    • Clave secreta: se puede usar cualquier clave secreta (o combinación de varias claves). Por ejemplo:
      secret/data/apigee/cassandra
    • Datos secretos: Apigee Hybrid espera pares de nombre de usuario y contraseña para los siguientes usuarios de Cassandra:
      Usuarios de Cassandra
      Administrador
      DDL
      Predeterminado
      DML
      JMX
      Jolokia
      Estos valores de nombre de usuario y contraseña se pueden distribuir en cualquier número de claves secretas.
    • CLI de Vault: el siguiente comando muestra cómo crear un único secreto que contenga todos los nombres de usuario y contraseñas necesarios:
      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"
      Los nombres de usuario predeterminados de cada usuario son los siguientes:
      Usuario de Cassandra Valor predeterminado
      Administrador admin_user
      DDL ddl_user
      Predeterminado cassandra
      DML dml_user
      JMX jmxuser
      Jolokia apigee
  3. En Vault, crea una política para conceder acceso al secreto que acabas de crear.
    1. Crea un archivo de política (nombre sugerido: apigee-cassandra-auth.txt) con el siguiente contenido:
      path "secret/data/apigee/cassandra" {
        capabilities = ["read"]
      }
      Si has creado varios secretos, debes añadir cada uno de ellos al archivo de política:
      path "secret/data/apigee/cassandra/admin" {
        capabilities = ["read"]
      }
      
      path "secret/data/apigee/cassandra/ddl" {
        capabilities = ["read"]
      }
    2. Aplica la política a Vault:
      vault policy write apigee-cassandra-auth apigee-cassandra-auth.txt

      Es posible crear la política usando la entrada estándar en lugar de leerla de un archivo:

      echo 'path "secret/data/apigee/cassandra" { capabilities = ["read"] }' | vault policy write apigee-cassandra-auth -
  4. Vincula la política a las cuentas de servicio de Kubernetes de Apigee Cassandra.
    1. Define las siguientes variables de entorno:
      export ORG_NAME=APIGEE_ORG_NAME
      export ENVS_LIST=LIST_OF_APIGEE-ENVS
      export APIGEE_NAMESPACE=YOUR_APIGEE_NAMESPACE

      Donde:

      • ORG_NAME es el nombre de tu organización de Apigee.
      • ENVS_LIST Es una lista separada por comas de tus entornos de Apigee. Por ejemplo, dev,prod.
      • APIGEE_NAMESPACE es tu espacio de nombres de Apigee. El valor predeterminado es apigee.
    2. Crea una secuencia de comandos con el siguiente contenido. La secuencia de comandos puede tener cualquier nombre. En el siguiente ejemplo, el nombre de la secuencia de comandos es 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. Ejecuta la secuencia de comandos y asigna la salida a la variable SERVICE_ACCOUNT_NAMES. Se creará una lista de nombres de cuentas de servicio de Kubernetes separados por comas.
      export SERVICE_ACCOUNT_NAMES=$(./create-vault-cassandra-role)

      Comprueba que la variable se haya rellenado con la lista:

      echo $SERVICE_ACCOUNT_NAMES
    4. Usa la CLI de Vault para crear un rol que vincule la política a las cuentas de servicio de 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 el controlador de CSI y el proveedor de Vault

Apigee hybrid v1.15.0 admite las siguientes versiones de gráficos de Helm:

Software Versión
Controlador de CSI de Secrets Store v1.4.1
Vault 1.15.2
  1. Sigue las instrucciones de instalación del controlador de CSI de Secrets Store para instalar el controlador de CSI en tu clúster. El controlador de CSI tiene un gráfico de Helm para la instalación.
  2. Sigue las instrucciones de Instalar el proveedor de CSI de Vault para instalarlo si aún no lo has hecho.

Crear un objeto SecretProviderClass

El recurso SecretProviderClass indica al controlador CSI con qué proveedor debe comunicarse al solicitar secretos. Las credenciales de los usuarios de Cassandra deben configurarse a través de este objeto. En la siguiente tabla se muestran los nombres de archivo (objectName) que espera Apigee Cassandra:

Usuario de Cassandra Nombres de archivo secretos esperados
Administrador adminUsername, adminPassword
DDL ddlUsername, ddlPassword
Predeterminado cassandra, defaultPassword
DML dmlUsername, dmlPassword
JMX jmxUsername, jmxPassword
Jolokia jolokiaUsername, jolokiaPassword
  1. Crea un archivo YAML para tu SecretProviderClass. El nombre del archivo puede ser cualquiera, por ejemplo, spc.yaml. Usa la siguiente plantilla 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. Aplica el SecretProviderClass al espacio de nombres apigee:
    kubectl -n $APIGEE_NAMESPACE apply -f spc.yaml

Habilitar secretos externos para Cassandra

  1. En tu overrides.yaml, añade la siguiente configuración para habilitar el uso de secretos externos en Cassandra:
    cassandra:
      auth:
        secretProviderClass: apigee-cassandra-auth-spc  # The name of the SecretProviderClass created in spc.yaml.

    Consulta cassandra.auth.secretProviderClass.

  2. Usa helm upgrade para aplicar el cambio a los componentes apigee-operator y apigee-datastore:
    • El controlador de almacén de datos de apigee-operator participa en la retirada de Cassandra y en la replicación de datos durante la expansión de la región. Estas tareas requieren las credenciales de JMX y Jolokia.
      helm upgrade operator apigee-operator/ \
        --namespace $APIGEE_NAMESPACE> \
        --atomic \
        -f overrides.yaml
    • apigee-datastore proporciona las credenciales que usan los componentes posteriores, como apigee-runtime, Synchronizer y MART, al conectarse a Cassandra.
      helm upgrade datastore apigee-datastore/ \
        --namespace $APIGEE_NAMESPACE \
        --atomic \
        -f overrides.yaml
  3. Verifica que se estén usando secretos externos. Cuando se habilitan los secretos externos, se añaden nuevos Volumes, Volume Mounts y Environment Variables que hacen referencia a los secretos.
    • Verifica la implementación de apigee-controller-manager.

      Comprueba que existe un Volume llamado apigee-external-secrets y que hace referencia al SecretProviderClass creado anteriormente:

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

      Ejemplo:

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

      Comprueba que existe un elemento VolumeMount llamado 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")]}'

      Ejemplo:

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

      Comprueba que existan Environment Variable que hagan referencia a secretos externos:

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

      Ejemplo:

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

Volver al secreto de K8s

  1. Para volver a usar secretos no externos, elimina la configuración de secretProviderClass en overrides.yaml y usa la configuración anterior:
    cassandra:
          auth:
            secretProviderClass: apigee-cassandra-auth-spc # remove this line
  2. Usa helm upgrade para aplicar el cambio a los componentes apigee-operator y 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

Solución de problemas: crear un contenedor de cliente para depurar

Si usas Vault, esta sección sustituye a las instrucciones de la sección de solución de problemas Crear un contenedor de cliente para depurar.

En esta sección se explica cómo crear un contenedor de cliente desde el que puedes acceder a las utilidades de depuración de Cassandra, como cqlsh. Estas utilidades te permiten consultar tablas de Cassandra y pueden ser útiles para depurar.

Crear el contenedor de cliente

Para crear el contenedor de cliente, siga estos pasos:

  1. El contenedor usa el certificado TLS del pod apigee-cassandra-user-setup. El primer paso es obtener el nombre de este certificado:
    kubectl get secrets -n APIGEE_NAMESPACE --field-selector type=kubernetes.io/tls | grep apigee-cassandra-user-setup | awk '{print $1}'

    Este comando devuelve el nombre del certificado. Por ejemplo: apigee-cassandra-user-setup-rg-hybrid-b7d3b9c-tls.

  2. Abre un archivo nuevo y pega la siguiente especificación de pod en él:
    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. Guarda el archivo con la extensión .yaml. Por ejemplo: my-spec.yaml.
  4. Aplica la especificación a tu clúster:
    kubectl apply -f my-spec.yaml -n $APIGEE_NAMESPACE
  5. Inicia sesión en el contenedor:
    kubectl exec -n CASSANDRA_CLIENT_NAME -it -- bash
  6. Conéctate a la interfaz de Cassandra cqlsh con los siguientes comandos. Introduce los comandos exactamente como se muestra:
    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

Eliminar el pod del cliente

Usa este comando para eliminar el pod del cliente de Cassandra:

kubectl delete pods -n $APIGEE_NAMESPACE cassandra-client