Acceder a secretos almacenados fuera de los clústeres de GKE mediante bibliotecas de cliente

En este tutorial se muestra cómo almacenar en Secret Manager los datos sensibles que usan tus clústeres de Google Kubernetes Engine (GKE). Aprenderás a acceder de forma más segura a los datos de tus pods mediante Workload Identity Federation para GKE y lasGoogle Cloud bibliotecas de cliente.

Almacenar tus datos sensibles fuera del almacenamiento del clúster se reduce el riesgo de que se acceda a ellos sin autorización en caso de que se produzca un ataque. Si usas Workload Identity Federation para GKE con el fin de acceder a los datos, puedes evitar los riesgos asociados a la gestión de claves de cuentas de servicio de larga duración y controlar el acceso a tus secretos mediante Gestión de Identidades y Accesos (IAM) en lugar de con reglas de control de acceso basado en roles (RBAC) en el clúster. Puedes usar cualquier proveedor de almacenamiento de secretos externo, como Secret Manager o HashiCorp Vault.

Esta página está dirigida a especialistas en seguridad que quieran mover datos sensibles fuera del almacenamiento en clúster. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido, consulta Roles y tareas habituales de los usuarios de GKE. Google Cloud

En este tutorial se usa un clúster de Autopilot de GKE. Para seguir los pasos con GKE Standard, debes habilitar Workload Identity Federation para GKE manualmente.

Puedes usar Workload Identity Federation for GKE para acceder a cualquier API desde cargas de trabajo de GKE sin tener que usar métodos menos seguros, como archivos de claves de cuentas de servicio estáticas. Google Cloud En este tutorial se usa Secret Manager como ejemplo, pero puedes seguir los mismos pasos para acceder a otras APIs Google Cloud. Para obtener más información, consulta Workload Identity Federation para GKE.

Objetivos

  • Crea un secreto en Google Cloud Secret Manager.
  • Crea un clúster de Autopilot de GKE, espacios de nombres de Kubernetes y cuentas de servicio de Kubernetes.
  • Crea políticas de gestión de identidades y accesos para conceder acceso a tus cuentas de servicio de Kubernetes en el secreto.
  • Usa aplicaciones de prueba para verificar el acceso de la cuenta de servicio.
  • Ejecuta una aplicación de ejemplo que acceda al secreto mediante la API de Secret Manager.

Costes

En este documento, se utilizan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costes basada en el uso previsto, utiliza la calculadora de precios.

Los usuarios nuevos Google Cloud pueden disfrutar de una prueba gratuita.

Cuando termines las tareas que se describen en este documento, puedes evitar que se te siga facturando eliminando los recursos que has creado. Para obtener más información, consulta la sección Limpiar.

Antes de empezar

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. Si utilizas un proveedor de identidades (IdP) externo, primero debes iniciar sesión en la CLI de gcloud con tu identidad federada.

  4. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  5. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Kubernetes Engine and Secret Manager APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  8. Install the Google Cloud CLI.

  9. Si utilizas un proveedor de identidades (IdP) externo, primero debes iniciar sesión en la CLI de gcloud con tu identidad federada.

  10. Para inicializar gcloud CLI, ejecuta el siguiente comando:

    gcloud init
  11. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the Kubernetes Engine and Secret Manager APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  14. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/secretmanager.admin, roles/container.clusterAdmin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    Replace the following:

    • PROJECT_ID: your project ID.
    • USER_IDENTIFIER: the identifier for your user account—for example, myemail@example.com.
    • ROLE: the IAM role that you grant to your user account.
  15. Preparar el entorno

    Clona el repositorio de GitHub que contiene los archivos de ejemplo de este tutorial:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd ~/kubernetes-engine-samples/security/wi-secrets
    

    Crear un secreto en Secret Manager

    1. En el siguiente ejemplo se muestran los datos que usarás para crear un secreto:

      key=my-api-key
    2. Crea un secreto para almacenar los datos de ejemplo:

      gcloud secrets create bq-readonly-key \
          --data-file=manifests/bq-readonly-key \
          --ttl=3600s
      

      Este comando hace lo siguiente:

      • Crea un secreto de Secret Manager con la clave de ejemplo en la región us-central1 Google Cloud .
      • Define que el secreto caduque una hora después de ejecutar el comando.

    Crear el clúster y los recursos de Kubernetes

    Crea un clúster de GKE, espacios de nombres de Kubernetes y cuentas de servicio de Kubernetes. Crea dos espacios de nombres: uno para el acceso de solo lectura y otro para el acceso de lectura y escritura al secreto. También debes crear una cuenta de servicio de Kubernetes en cada espacio de nombres para usarla con Workload Identity Federation para GKE.

    1. Crea un clúster de Autopilot de GKE:

      gcloud container clusters create-auto secret-cluster \
          --location=us-central1
      

      El clúster puede tardar unos cinco minutos en implementarse. Los clústeres de Autopilot siempre tienen habilitada la federación de Workload Identity para GKE. Si quieres usar un clúster Estándar de GKE, debes habilitar manualmente Workload Identity Federation para GKE antes de continuar.

    2. Crea un espacio de nombres readonly-ns y otro admin-ns:

      kubectl create namespace readonly-ns
      kubectl create namespace admin-ns
      
    3. Crea una readonly-sacuenta de servicio de Kubernetes y una admin-sacuenta de servicio de Kubernetes:

      kubectl create serviceaccount readonly-sa --namespace=readonly-ns
      kubectl create serviceaccount admin-sa --namespace=admin-ns
      

    Crear políticas de gestión de identidades y accesos de permiso

    1. Concede a la cuenta de servicio readonly-sa acceso de solo lectura al secreto:

      gcloud secrets add-iam-policy-binding bq-readonly-key \
          --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/readonly-ns/sa/readonly-sa \
          --role='roles/secretmanager.secretAccessor' \
          --condition=None
      

      Haz los cambios siguientes:

      • PROJECT_NUMBER: tu número de proyecto Google Cloud numérico.
      • PROJECT_ID: tu ID de proyecto Google Cloud .
    2. Concede a la cuenta de servicio admin-sa acceso de lectura y escritura al secreto:

      gcloud secrets add-iam-policy-binding bq-readonly-key \
          --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/admin-ns/sa/admin-sa \
          --role='roles/secretmanager.secretAccessor' \
          --condition=None
      gcloud secrets add-iam-policy-binding bq-readonly-key \
          --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/admin-ns/sa/admin-sa \
          --role='roles/secretmanager.secretVersionAdder' \
          --condition=None
      

    Verificar el acceso secreto

    Implementa pods de prueba en cada espacio de nombres para verificar el acceso de solo lectura y de lectura y escritura.

    1. Revisa el archivo de manifiesto de Pod de solo lectura:

      # Copyright 2022 Google LLC
      #
      # Licensed under the Apache License, Version 2.0 (the "License");
      # you may not use this file except in compliance with the License.
      # You may obtain a copy of the License at
      #
      #     http://www.apache.org/licenses/LICENSE-2.0
      #
      # Unless required by applicable law or agreed to in writing, software
      # distributed under the License is distributed on an "AS IS" BASIS,
      # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      # See the License for the specific language governing permissions and
      # limitations under the License.
      
      apiVersion: v1
      kind: Pod
      metadata:
        name: readonly-test
        namespace: readonly-ns
      spec:
        containers:
        - image: google/cloud-sdk:slim
          name: workload-identity-test
          command: ["sleep","infinity"]
          resources:
            requests:
              cpu: "150m"
              memory: "150Mi"
        serviceAccountName: readonly-sa

      Este pod usa la cuenta de servicio readonly-sa en el espacio de nombres readonly-ns.

    2. Revisa el archivo de manifiesto de Pod de lectura y escritura:

      # Copyright 2022 Google LLC
      #
      # Licensed under the Apache License, Version 2.0 (the "License");
      # you may not use this file except in compliance with the License.
      # You may obtain a copy of the License at
      #
      #     http://www.apache.org/licenses/LICENSE-2.0
      #
      # Unless required by applicable law or agreed to in writing, software
      # distributed under the License is distributed on an "AS IS" BASIS,
      # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      # See the License for the specific language governing permissions and
      # limitations under the License.
      
      apiVersion: v1
      kind: Pod
      metadata:
        name: admin-test
        namespace: admin-ns
      spec:
        containers:
        - image: google/cloud-sdk:slim
          name: workload-identity-test
          command: ["sleep","infinity"]
          resources:
            requests:
              cpu: "150m"
              memory: "150Mi"
        serviceAccountName: admin-sa

      Este pod usa la cuenta de servicio admin-sa en el espacio de nombres admin-ns.

    3. Despliega los pods de prueba:

      kubectl apply -f manifests/admin-pod.yaml
      kubectl apply -f manifests/readonly-pod.yaml
      

      Los Pods pueden tardar unos minutos en empezar a funcionar. Para monitorizar el progreso, ejecuta el siguiente comando:

      watch kubectl get pods -n readonly-ns
      

      Cuando el estado del pod cambie a RUNNING, pulsa Ctrl+C para volver a la línea de comandos.

    Probar el acceso de solo lectura

    1. Abre un shell en el readonly-test pod:

      kubectl exec -it readonly-test --namespace=readonly-ns -- /bin/bash
      
    2. Prueba a leer el secreto:

      gcloud secrets versions access 1 --secret=bq-readonly-key
      

      El resultado es key=my-api-key.

    3. Intenta escribir datos nuevos en el secreto:

      printf "my-second-api-key" | gcloud secrets versions add bq-readonly-key --data-file=-
      

      El resultado debería ser similar al siguiente:

      ERROR: (gcloud.secrets.versions.add) PERMISSION_DENIED: Permission 'secretmanager.versions.add' denied for resource 'projects/PROJECT_ID/secrets/bq-readonly-key' (or it may not exist).
      

      El pod que usa la cuenta de servicio de solo lectura solo puede leer el secreto y no puede escribir datos nuevos.

    4. Salir del Pod:

      exit
      

    Probar el acceso de lectura y escritura

    1. Abre un shell en el admin-test pod:

      kubectl exec -it admin-test --namespace=admin-ns -- /bin/bash
      
    2. Prueba a leer el secreto:

      gcloud secrets versions access 1 --secret=bq-readonly-key
      

      El resultado es key=my-api-key.

    3. Intenta escribir datos nuevos en el secreto:

      printf "my-second-api-key" | gcloud secrets versions add bq-readonly-key --data-file=-
      

      El resultado debería ser similar al siguiente:

      Created version [2] of the secret [bq-readonly-key].
      
    4. Lee la nueva versión del secreto:

      gcloud secrets versions access 2 --secret=bq-readonly-key
      

      El resultado es my-second-api-key.

    5. Salir del Pod:

      exit
      

    Los pods solo obtienen el nivel de acceso que hayas concedido a la cuenta de servicio de Kubernetes utilizada en el manifiesto del pod. Los pods que usen la cuenta de Kubernetes en el espacio de nombres admin-ns pueden escribir nuevas versiones del secreto, pero los pods del espacio de nombres readonly-ns que usen la cuenta de servicio de Kubernetes readonly-sa solo pueden leer el secreto.admin-sa

    Acceder a los secretos desde tu código

    En esta sección, harás lo siguiente:

    1. Despliega una aplicación de muestra que lea tu secreto en Secret Manager mediante bibliotecas de cliente.

    2. Comprueba que la aplicación pueda acceder a tu secreto.

    Siempre que sea posible, debes acceder a los secretos de Secret Manager desde el código de tu aplicación mediante la API de Secret Manager.

    1. Revisa el código fuente de la aplicación de ejemplo:

      // Copyright 2022 Google LLC
      //
      // Licensed under the Apache License, Version 2.0 (the "License");
      // you may not use this file except in compliance with the License.
      // You may obtain a copy of the License at
      //
      //     http://www.apache.org/licenses/LICENSE-2.0
      //
      // Unless required by applicable law or agreed to in writing, software
      // distributed under the License is distributed on an "AS IS" BASIS,
      // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      // See the License for the specific language governing permissions and
      // limitations under the License.
      
      package main
      
      import (
      	"context"
      	"fmt"
      	"log"
      	"os"
      
      	secretmanager "cloud.google.com/go/secretmanager/apiv1"
      	secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
      )
      
      func main() {
      
              // Get environment variables from Pod spec.
              projectID := os.Getenv("PROJECT_ID")
              secretId := os.Getenv("SECRET_ID")
              secretVersion := os.Getenv("SECRET_VERSION")
      
              // Create the Secret Manager client.
              ctx := context.Background()
              client, err := secretmanager.NewClient(ctx)
              if err != nil {
                      log.Fatalf("failed to setup client: %v", err)
              }
              defer client.Close()
      
              // Create the request to access the secret.
              accessSecretReq := &secretmanagerpb.AccessSecretVersionRequest{
                      Name: fmt.Sprintf("projects/%s/secrets/%s/versions/%s", projectID, secretId, secretVersion),
              }
      
              secret, err := client.AccessSecretVersion(ctx, accessSecretReq)
              if err != nil {
                      log.Fatalf("failed to access secret: %v", err)
              }
      
              // Print the secret payload.
              //
              // WARNING: Do not print the secret in a production environment - this
              // snippet is showing how to access the secret material.
              log.Printf("Welcome to the key store, here's your key:\nKey: %s", secret.Payload.Data)
      }
      

      Esta aplicación llama a la API Secret Manager para intentar leer el secreto.

    2. Revisa el archivo de manifiesto del pod de la aplicación de ejemplo:

      # Copyright 2022 Google LLC
      #
      # Licensed under the Apache License, Version 2.0 (the "License");
      # you may not use this file except in compliance with the License.
      # You may obtain a copy of the License at
      #
      #     http://www.apache.org/licenses/LICENSE-2.0
      #
      # Unless required by applicable law or agreed to in writing, software
      # distributed under the License is distributed on an "AS IS" BASIS,
      # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      # See the License for the specific language governing permissions and
      # limitations under the License.
      
      apiVersion: v1
      kind: Pod
      metadata:
        name: readonly-secret-test
        namespace: readonly-ns
      spec:
        containers:
        - image: us-docker.pkg.dev/google-samples/containers/gke/wi-secret-store:latest
          name: secret-app
          env:
            - name: PROJECT_ID
              value: "YOUR_PROJECT_ID"
            - name: SECRET_ID
              value: "bq-readonly-key"
            - name: SECRET_VERSION
              value: "latest"
          resources:
            requests:
              cpu: "125m"
              memory: "64Mi"
        serviceAccountName: readonly-sa

      Este archivo de manifiesto hace lo siguiente:

      • Crea un pod en el espacio de nombres readonly-ns que usa la cuenta de servicio readonly-sa.
      • Extrae una aplicación de ejemplo de un registro de imágenes de Google. Esta aplicación llama a la API Secret Manager mediante lasGoogle Cloud bibliotecas de cliente. Puedes ver el código de la aplicación en /main.go en el repositorio.
      • Define las variables de entorno que debe usar la aplicación de ejemplo.
    3. Sustituye las variables de entorno en la aplicación de ejemplo:

      sed -i "s/YOUR_PROJECT_ID/PROJECT_ID/g" "manifests/secret-app.yaml"
      
    4. Despliega la aplicación de muestra:

      kubectl apply -f manifests/secret-app.yaml
      

      El Pod puede tardar unos minutos en empezar a funcionar. Si el pod necesita un nuevo nodo en tu clúster, es posible que veas eventos de tipo CrashLoopBackOff mientras GKE aprovisiona el nodo. Los fallos se detienen cuando el nodo se aprovisiona correctamente.

    5. Verifica el acceso secreto:

      kubectl logs readonly-secret-test -n readonly-ns
      

      El resultado es my-second-api-key. Si no se muestra nada, es posible que el pod aún no se esté ejecutando. Espera unos minutos y vuelve a intentarlo.

    Enfoques alternativos

    Si necesitas montar tus datos sensibles en tus pods, usa el complemento Secret Manager para GKE. Este complemento despliega y gestiona el proveedor Google Cloud Secret Manager para el controlador CSI de Secret Store de Kubernetes en tus clústeres de GKE. Para obtener instrucciones, consulta Usar el complemento Secret Manager con GKE.

    Proporcionar secretos como volúmenes montados conlleva los siguientes riesgos:

    1. Los volúmenes montados son vulnerables a los ataques de recorrido de directorios.
    2. Las variables de entorno pueden verse comprometidas debido a errores de configuración, como la apertura de un endpoint de depuración.

    Siempre que sea posible, te recomendamos que accedas a los secretos de forma programática a través de la API Secret Manager. Para obtener instrucciones, usa la aplicación de ejemplo de este tutorial o consulta las bibliotecas de cliente de Secret Manager.

    Limpieza

    Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

    Eliminar recursos concretos

    1. Elimina el clúster:

      gcloud container clusters delete secret-cluster \
          --location=us-central1
      
    2. Opcional: Elimina el secreto en Secret Manager:

      gcloud secrets delete bq-readonly-key
      

      Si no lo haces, el secreto caducará automáticamente porque has definido la marca --ttl durante la creación.

    Eliminar el proyecto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Siguientes pasos