Accéder aux secrets stockés en dehors des clusters GKE à l'aide de bibliothèques clientes


Ce tutoriel explique comment stocker les données sensibles utilisées par vos clusters Google Kubernetes Engine (GKE) dans Secret Manager et comment accéder de manière plus sécurisée aux données de vos pods à l'aide de la fédération d'identité de charge de travail pour GKE et les bibliothèques clientes Google Cloud. Ce tutoriel est destiné aux administrateurs de sécurité qui souhaitent déplacer des données sensibles pour sortir du principe de stockage dans le cluster.

Le stockage de vos données sensibles en dehors du stockage de votre cluster réduit le risque d'accès non autorisé aux données en cas d'attaque. Utiliser la fédération d'identité de charge de travail pour GKE afin d'accéder aux données vous permet d'éviter les risques associés à la gestion des clés de compte de service à longue durée de vie, et vous permet de contrôler l'accès à vos secrets à l'aide d'Identity and Access Management (IAM) au lieu des règles RBAC intégrées au cluster. Vous pouvez utiliser n'importe quel fournisseur de stockage de secrets externe, tel que Secret Manager ou HashiCorp Vault.

Ce tutoriel utilise un cluster GKE Autopilot. Pour effectuer les étapes avec GKE Standard, vous devez activer manuellement la fédération d'identité de charge de travail pour GKE.

Vous pouvez utiliser la fédération d'identité de charge de travail pour GKE afin d'accéder à n'importe quelle API Google Cloud à partir de charges de travail GKE, sans avoir à utiliser des approches moins sécurisées, telles que les fichiers de clé de compte de service statiques. Ce tutoriel utilise Secret Manager comme exemple, mais vous pouvez utiliser les mêmes étapes pour accéder à d'autres API Google Cloud. Pour en savoir plus, consultez la page Fédération d'identité de charge de travail pour GKE.

Objectifs

  • Créer un secret dans Google Cloud Secret Manager.
  • Créer et configurer les comptes de service IAM pour accéder au secret.
  • Créer un cluster GKE Autopilot, des espaces de noms Kubernetes et des comptes de service Kubernetes.
  • Utiliser des applications de test pour vérifier l'accès au compte de service.
  • Exécuter un exemple d'application qui accède au secret à l'aide de l'API Secret Manager.

Coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

  1. Connectez-vous à votre compte Google Cloud. Si vous débutez sur Google Cloud, créez un compte pour évaluer les performances de nos produits en conditions réelles. Les nouveaux clients bénéficient également de 300 $ de crédits gratuits pour exécuter, tester et déployer des charges de travail.
  2. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

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

    • 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.

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Enable the Kubernetes Engine and Secret Manager APIs:

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

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

    • 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.

  10. Make sure that billing is enabled for your Google Cloud project.

  11. Enable the Kubernetes Engine and Secret Manager APIs:

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

    gcloud projects add-iam-policy-binding PROJECT_ID --member="USER_IDENTIFIER" --role=ROLE
    • Replace PROJECT_ID with your project ID.
    • Replace USER_IDENTIFIER with the identifier for your user account. For example, user:myemail@example.com.

    • Replace ROLE with each individual role.

Préparer l'environnement

Clonez le dépôt GitHub contenant les exemples de fichiers de ce tutoriel :

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

Créer un secret dans Secret Manager

  1. L'exemple suivant montre les données que vous utiliserez pour créer un secret :

    key=my-api-key
  2. Créez un secret pour stocker les exemples de données :

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

    Cette commande effectue les opérations suivantes :

    • Elle crée un secret Secret Manager avec l'exemple de clé dans la région Google Cloud us-central1.
    • Elle définit le secret de sorte qu'il expire une heure après l'exécution de la commande.

Configurer des comptes de service IAM

  1. Créez deux comptes de service IAM pour l'accès en lecture seule et l'accès en lecture/écriture :

    gcloud iam service-accounts create readonly-secrets --display-name="Read secrets"
    gcloud iam service-accounts create readwrite-secrets --display-name="Read write secrets"
    
  2. Accordez au compte de service IAM readonly-secrets un accès en lecture seule au secret :

    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=serviceAccount:readonly-secrets@PROJECT_ID.iam.gserviceaccount.com \
        --role='roles/secretmanager.secretAccessor'
    
  3. Accordez aux comptes de service IAM readwrite-secrets un accès en lecture/écriture au secret :

    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=serviceAccount:readwrite-secrets@PROJECT_ID.iam.gserviceaccount.com \
        --role='roles/secretmanager.secretAccessor'
    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=serviceAccount:readwrite-secrets@PROJECT_ID.iam.gserviceaccount.com \
        --role='roles/secretmanager.secretVersionAdder'
    

Créer le cluster et les ressources Kubernetes

Créer un cluster GKE, des espaces de noms Kubernetes et des comptes de service Kubernetes. Vous créez deux espaces de noms, l'un pour l'accès en lecture seule et l'autre pour l'accès en lecture/écriture au secret. Vous allez également créer un compte de service Kubernetes dans chaque espace de noms à utiliser avec la fédération d'identité de charge de travail pour GKE.

  1. Créez un cluster GKE Autopilot :

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

    Le déploiement du cluster prend environ cinq minutes. La fédération d'identité de charge de travail pour GKE est toujours activée sur les clusters Autopilot. Si vous préférez utiliser un cluster GKE Standard, vous devez activer manuellement la fédération d'identité de charge de travail pour GKE avant de continuer.

  2. Créez un espace de noms readonly-ns et un espace de noms admin-ns :

    kubectl create namespace readonly-ns
    kubectl create namespace admin-ns
    
  3. Créez un compte de service Kubernetes readonly-sa et un compte de service Kubernetes admin-sa :

    kubectl create serviceaccount readonly-sa --namespace=readonly-ns
    kubectl create serviceaccount admin-sa --namespace=admin-ns
    
  4. Associez les comptes de service IAM aux comptes de service Kubernetes :

    gcloud iam service-accounts add-iam-policy-binding readonly-secrets@PROJECT_ID.iam.gserviceaccount.com \
        --member=serviceAccount:PROJECT_ID.svc.id.goog[readonly-ns/readonly-sa] \
        --role='roles/iam.workloadIdentityUser'
    gcloud iam service-accounts add-iam-policy-binding readwrite-secrets@PROJECT_ID.iam.gserviceaccount.com \
        --member=serviceAccount:PROJECT_ID.svc.id.goog[admin-ns/admin-sa] \
        --role='roles/iam.workloadIdentityUser'
    
  5. Annotez les comptes de service Kubernetes avec les noms des comptes de service IAM liés :

    kubectl annotate serviceaccount readonly-sa \
        --namespace=readonly-ns \
        iam.gke.io/gcp-service-account=readonly-secrets@PROJECT_ID.iam.gserviceaccount.com
    kubectl annotate serviceaccount admin-sa \
        --namespace=admin-ns \
        iam.gke.io/gcp-service-account=readwrite-secrets@PROJECT_ID.iam.gserviceaccount.com
    

Vous disposez maintenant d'un cluster configuré pour accéder au secret à partir des pods à l'aide de la fédération d'identité de charge de travail pour GKE.

Vérifier l'accès au secret

Déployez des pods de test dans chaque espace de noms pour vérifier l'accès en lecture seule et l'accès en lecture/écriture.

  1. Examinez le fichier manifeste du pod en lecture seule :

    # 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

    Ce pod utilise le compte de service readonly-sa dans l'espace de noms readonly-ns.

  2. Examinez le fichier manifeste du pod en lecture-écriture :

    # 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

    Ce pod utilise le compte de service admin-sa dans l'espace de noms admin-ns.

  3. Déployez les pods de test :

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

    Le démarrage des pods peut prendre quelques minutes. Pour surveiller la progression, exécutez la commande suivante :

    watch kubectl get pods -n readonly-ns
    

    Lorsque l'état du pod passe à RUNNING, appuyez sur Ctrl+C pour revenir à la ligne de commande.

Tester l'accès en lecture seule

  1. Ouvrez un shell dans le pod readonly-test :

    kubectl exec -it readonly-test --namespace=readonly-ns -- /bin/bash
    
  2. Essayez de lire le secret :

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

    Le résultat est key=my-api-key.

  3. Essayez d'écrire de nouvelles données dans le secret :

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

    Le résultat ressemble à ce qui suit :

    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).
    

    Le pod utilisant le compte de service en lecture seule peut seulement lire le secret ; il ne peut pas écrire de nouvelles données.

  4. Fermez le pod :

    exit
    

Tester l'accès en lecture/écriture

  1. Ouvrez un shell dans le pod admin-test :

    kubectl exec -it admin-test --namespace=admin-ns -- /bin/bash
    
  2. Essayez de lire le secret :

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

    Le résultat est key=my-api-key.

  3. Essayez d'écrire de nouvelles données dans le secret :

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

    Le résultat ressemble à ce qui suit :

    Created version [2] of the secret [bq-readonly-key].
    
  4. Lisez la nouvelle version du secret :

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

    Le résultat est my-second-api-key.

  5. Fermez le pod :

    exit
    

Les pods n'obtiennent que le niveau d'accès que vous avez accordé au compte de service IAM lié au compte de service Kubernetes, qui est utilisé dans le fichier manifeste du pod. Tous les pods qui utilisent le compte Kubernetes admin-sa dans l'espace de noms admin-ns peuvent écrire de nouvelles versions du secret, mais tous les pods de l'espace de noms readonly-ns qui utilisent le compte de service Kubernetes readonly-sa ne peuvent lire que le secret.

Accéder aux secrets depuis votre code

Dans cette section, vous allez exécuter les opérations suivantes :

  1. Déployer un exemple d'application qui lit votre secret dans Secret Manager à l'aide de bibliothèques clientes.

  2. Vérifier que l'application peut accéder à votre secret.

Dans la mesure du possible, vous devez accéder aux secrets de Secret Manager à partir du code de votre application, à l'aide de l'API Secret Manager.

  1. Examinez le code source de l'exemple d'application :

    // 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)
    }
    

    Cette application appelle l'API Secret Manager pour essayer de lire le secret.

  2. Examinez l'exemple de fichier manifeste de pod d'application :

    # 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

    Ce fichier manifeste effectue les opérations suivantes :

    • Il crée un pod dans l'espace de noms readonly-ns qui utilise le compte de service readonly-sa.
    • Il extrait un exemple d'application d'un registre d'images Google. Cette application appelle l'API Secret Manager à l'aide des bibliothèques clientes Google Cloud. Vous pouvez consulter le code de l'application dans le dépôt, dans /main.go.
    • Il définit les variables d'environnement que l'exemple d'application doit utiliser.
  3. Remplacez les variables d'environnement dans l'exemple d'application :

    sed -i "s/YOUR_PROJECT_ID/PROJECT_ID/g" "manifests/secret-app.yaml"
    
  4. Déployez l'exemple d'application :

    kubectl apply -f manifests/secret-app.yaml
    

    L'initialisation du pod peut prendre quelques minutes. Si le pod a besoin d'un nouveau nœud dans votre cluster, vous remarquerez peut-être des événements de type CrashLoopBackOff pendant que GKE provisionne le nœud. Ces plantages s'arrêtent une fois que le nœud a bien été provisionné.

  5. Vérifiez l'accès au secret :

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

    Le résultat est my-second-api-key. Si le résultat est vide, il est possible que le pod ne soit pas encore en cours d'exécution. Patientez quelques minutes, puis réessayez.

Autres approches

Si vous devez installer vos données sensibles sur vos pods, utilisez le module complémentaire Secret Manager pour GKE (bêta). Ce module complémentaire déploie et gère le fournisseur Google Cloud Secret Manager pour le pilote CSI Kubernetes Secret Store dans vos clusters GKE. Pour obtenir des instructions, consultez la page Utiliser le module complémentaire Secret Manager avec GKE.

La spécification de secrets en tant que volumes installés présente les risques suivants :

  1. Les volumes installés sont sensibles aux attaques par balayage de répertoire.
  2. Les variables d'environnement peuvent être compromises en raison d'erreurs de configuration telles que l'ouverture d'un point de terminaison de débogage.

Dans la mesure du possible, nous vous recommandons d'accéder par programmation aux secrets via l'API Secret Manager. Pour obtenir des instructions, utilisez l'exemple d'application dans ce tutoriel ou reportez-vous aux bibliothèques clientes de Secret Manager.

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer des ressources individuelles

  1. Supprimez le cluster à l'aide de la commande suivante :

    gcloud container clusters delete secret-cluster \
        --region=us-central1
    
  2. Supprimez les comptes de service IAM :

    gcloud iam service-accounts delete readonly-secrets@PROJECT_ID.iam.gserviceaccount.com
    gcloud iam service-accounts delete readwrite-secrets@PROJECT_ID.iam.gserviceaccount.com
    
  3. Facultatif : Supprimez le secret dans Secret Manager :

    gcloud secrets delete bq-readonly-key
    

    Si vous n'effectuez pas cette étape, le secret expire automatiquement, car vous avez défini l'option --ttl lors de la création.

Supprimer le projet

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

Étapes suivantes