Auf Secrets außerhalb von GKE-Clustern mit Clientbibliotheken zugreifen


In dieser Anleitung erfahren Sie, wie Sie die von Ihren GKE-Clustern (Google Kubernetes Engine) verwendeten sensiblen Daten in Secret Manager speichern und mit der Identitätsföderation von Arbeitslasten für GKE und den Google Cloud-Clientbibliotheken sicherer abrufen. Diese Anleitung richtet sich an Sicherheitsadministratoren, die sensible Daten aus dem Clusterspeicher verschieben möchten.

Das Speichern sensibler Daten außerhalb des Clusterspeichers reduziert das Risiko eines nicht autorisierten Zugriffs auf die Daten, wenn ein Angriff stattfindet. Wenn Sie für den Zugriff auf die Daten Workload Identity-Föderation für GKE verwenden, können Sie die Risiken vermeiden, die mit der Verwaltung langlebiger Dienstkontoschlüssel verbunden sind. Außerdem können Sie den Zugriff auf Ihre Secrets mithilfe von Identity and Access Management (IAM) anstelle von clusterinternen RBAC-Regeln steuern. Sie können einen beliebigen externen Secret-Speicheranbieter wie Secret Manager oder HashiCorp Vault verwenden.

In dieser Anleitung wird ein GKE Autopilot-Cluster verwendet. Um die Schritte mit GKE Standard auszuführen, müssen Sie die Identitätsföderation von Arbeitslasten für GKE manuell aktivieren.

Sie können die Identitätsföderation von Arbeitslasten für GKE verwenden, um über GKE-Arbeitslasten auf alle Google Cloud APIs zuzugreifen, ohne weniger sichere Ansätze wie statische Dienstkonto-Schlüsseldateien verwenden zu müssen. In dieser Anleitung wird als Beispiel Secret Manager verwendet. Sie können jedoch dieselben Schritte ausführen, um auf andere Google Cloud APIs zuzugreifen. Weitere Informationen finden Sie unter Identitätsföderation von Arbeitslasten für GKE.

Lernziele

  • Secret in Google Cloud Secret Manager erstellen.
  • IAM-Dienstkonten für den Zugriff auf das Secret erstellen und konfigurieren.
  • GKE Autopilot-Cluster, Kubernetes-Namespaces und Kubernetes-ServiceAccounts erstellen.
  • Testanwendungen verwenden, um den Zugriff auf Dienstkonten zu prüfen.
  • Beispielanwendung ausführen, die über die Secret Manager API auf das Secret zugreift.

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen. Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.

Hinweis

  1. Melden Sie sich bei Ihrem Google Cloud-Konto an. Wenn Sie mit Google Cloud noch nicht vertraut sind, erstellen Sie ein Konto, um die Leistungsfähigkeit unserer Produkte in der Praxis sehen und bewerten zu können. Neukunden erhalten außerdem ein Guthaben von 300 $, um Arbeitslasten auszuführen, zu testen und bereitzustellen.
  2. Installieren Sie die Google Cloud CLI.
  3. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    gcloud init
  4. Google Cloud-Projekt erstellen oder auswählen.

    • Erstellen Sie ein Google Cloud-Projekt:

      gcloud projects create PROJECT_ID

      Ersetzen Sie PROJECT_ID durch einen Namen für das Google Cloud-Projekt, das Sie erstellen.

    • Wählen Sie das von Ihnen erstellte Google Cloud-Projekt aus:

      gcloud config set project PROJECT_ID

      Ersetzen Sie PROJECT_ID durch den Namen Ihres Google Cloud-Projekts.

  5. Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.

  6. Aktivieren Sie die Kubernetes Engine and Secret Manager APIs:

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  7. Installieren Sie die Google Cloud CLI.
  8. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    gcloud init
  9. Google Cloud-Projekt erstellen oder auswählen.

    • Erstellen Sie ein Google Cloud-Projekt:

      gcloud projects create PROJECT_ID

      Ersetzen Sie PROJECT_ID durch einen Namen für das Google Cloud-Projekt, das Sie erstellen.

    • Wählen Sie das von Ihnen erstellte Google Cloud-Projekt aus:

      gcloud config set project PROJECT_ID

      Ersetzen Sie PROJECT_ID durch den Namen Ihres Google Cloud-Projekts.

  10. Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.

  11. Aktivieren Sie die Kubernetes Engine and Secret Manager APIs:

    gcloud services enable container.googleapis.com secretmanager.googleapis.com
  12. Gewähren Sie Ihrem Google-Konto Rollen. Führen Sie den folgenden Befehl für jede der folgenden IAM-Rollen einmal aus: roles/secretmanager.admin, roles/container.clusterAdmin, roles/iam.serviceAccountAdmin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:EMAIL_ADDRESS" --role=ROLE
    • Ersetzen Sie PROJECT_ID durch Ihre Projekt-ID.
    • Ersetzen Sie EMAIL_ADDRESS durch Ihre E-Mail-Adresse.
    • Ersetzen Sie ROLE durch jede einzelne Rolle.

Umgebung vorbereiten

Klonen Sie das GitHub-Repository, das die Beispieldateien für diese Anleitung enthält:

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

Secret in Secret Manager erstellen

  1. Im folgenden Beispiel sehen Sie die Daten, die Sie zum Erstellen eines Secrets verwenden:

    key=my-api-key
  2. Erstellen Sie ein Secret zum Speichern der Beispieldaten:

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

    Mit diesem Befehl wird Folgendes ausgeführt:

    • Erstellt ein neues Secret Manager-Secret mit dem Beispielschlüssel in der Google Cloud-Region us-central1.
    • Legt fest, dass das Secret eine Stunde nach Ausführung des Befehls abläuft.

IAM-Dienstkonten konfigurieren

  1. Erstellen Sie zwei neue IAM-Dienstkonten für den schreibgeschützten und den Lese-/Schreibzugriff:

    gcloud iam service-accounts create readonly-secrets --display-name="Read secrets"
    gcloud iam service-accounts create readwrite-secrets --display-name="Read write secrets"
    
  2. Gewähren Sie dem IAM-Dienstkonto readonly-secrets Lesezugriff auf das Secret:

    gcloud secrets add-iam-policy-binding bq-readonly-key \
        --member=serviceAccount:readonly-secrets@PROJECT_ID.iam.gserviceaccount.com \
        --role='roles/secretmanager.secretAccessor'
    
  3. Gewähren Sie den readwrite-secrets-IAM-Dienstkonten Lese- und Schreibzugriff auf das 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'
    

Cluster und Kubernetes-Ressourcen erstellen

GKE-Cluster, Kubernetes-Namespaces und Kubernetes-Dienstkonten erstellen. Sie erstellen zwei Namespaces, einen für den Lesezugriff und einen für den Lese-/Schreibzugriff auf das Secret. Außerdem erstellen Sie in jedem Namespace ein Kubernetes-Dienstkonto für die Verwendung mit Workload Identity-Föderation für GKE.

  1. Erstellen Sie einen GKE Autopilot-Cluster:

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

    Die Bereitstellung des Clusters kann etwa fünf Minuten dauern. Für Autopilot-Cluster ist Workload Identity Federation for GKE immer aktiviert. Wenn Sie stattdessen einen GKE Standard-Cluster verwenden möchten, müssen Sie Workload Identity-Föderation für GKE manuell aktivieren, bevor Sie fortfahren.

  2. Erstellen Sie einen readonly-ns- und einen admin-ns-Namespace:

    kubectl create namespace readonly-ns
    kubectl create namespace admin-ns
    
  3. Erstellen Sie ein Kubernetes-Dienstkonto readonly-sa und ein Kubernetes-Dienstkonto admin-sa:

    kubectl create serviceaccount readonly-sa --namespace=readonly-ns
    kubectl create serviceaccount admin-sa --namespace=admin-ns
    
  4. Binden Sie die IAM-Dienstkonten an die Kubernetes-Dienstkonten:

    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. Annotieren Sie die Kubernetes-Dienstkonten mit den Namen der gebundenen IAM-Dienstkonten:

    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
    

Sie haben jetzt einen Cluster, der für den Zugriff auf das Secret von Pods über Workload Identity-Föderation für GKE konfiguriert ist.

Secret-Zugriff prüfen

Stellen Sie Test-Pods in jedem Namespace bereit, um den Lesezugriff und den Lese-/Schreibzugriff zu überprüfen.

  1. Prüfen Sie das schreibgeschützte Pod-Manifest:

    # 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

    Dieser Pod verwendet das Dienstkonto readonly-sa im Namespace readonly-ns.

  2. Prüfen Sie das Pod-Manifest mit Lese-/Schreibzugriff:

    # 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

    Dieser Pod verwendet das Dienstkonto admin-sa im Namespace admin-ns.

  3. Stellen Sie die Test-Pods bereit:

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

    Es kann einige Minuten dauern, bis die Pods ausgeführt werden. Führen Sie den folgenden Befehl aus, um den Fortschritt zu überwachen:

    watch kubectl get pods -n readonly-ns
    

    Wenn sich der Pod-Status in RUNNING ändert, drücken Sie Ctrl+C, um zur Befehlszeile zurückzukehren.

Lesezugriff testen

  1. Öffnen Sie eine Shell im readonly-test-Pod:

    kubectl exec -it readonly-test --namespace=readonly-ns -- /bin/bash
    
  2. Versuchen Sie, das Secret zu lesen:

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

    Die Ausgabe lautet key=my-api-key.

  3. Versuchen Sie, neue Daten in das Secret zu schreiben:

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

    Die Ausgabe sieht etwa so aus:

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

    Der Pod, der das schreibgeschützte Dienstkonto verwendet, kann nur das Secret lesen und keine neuen Daten schreiben.

  4. Beenden Sie den Pod:

    exit
    

Lese-/Schreibzugriff testen

  1. Öffnen Sie eine Shell im admin-test-Pod:

    kubectl exec -it admin-test --namespace=admin-ns -- /bin/bash
    
  2. Versuchen Sie, das Secret zu lesen:

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

    Die Ausgabe lautet key=my-api-key.

  3. Versuchen Sie, neue Daten in das Secret zu schreiben:

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

    Die Ausgabe sieht etwa so aus:

    Created version [2] of the secret [bq-readonly-key].
    
  4. Lesen Sie die neue Secret-Version:

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

    Die Ausgabe lautet my-second-api-key.

  5. Beenden Sie den Pod:

    exit
    

Die Pods erhalten nur die Zugriffsebene, die Sie dem IAM-Dienstkonto gewährt haben, das an das im Pod-Manifest verwendete Kubernetes-Dienstkonto gebunden ist. Alle Pods, die das Kubernetes-Konto admin-sa im Namespace admin-ns verwenden, können neue Versionen des Secrets schreiben, aber alle Pods im Namespace readonly-ns, die das Dienstkonto readonly-sa von Kubernetes verwenden, können das Secret nur lesen.

Über Ihren Code auf Secrets zugreifen

In diesem Abschnitt tun Sie Folgendes:

  1. Stellen Sie mithilfe von Clientbibliotheken eine Beispielanwendung bereit, die Ihr Secret in Secret Manager liest.

  2. Prüfen Sie, ob die Anwendung auf Ihr Secret zugreifen kann.

Sie sollten nach Möglichkeit immer mithilfe der Secret Manager API über Ihren Anwendungscode auf Secret Manager-Secrets zugreifen.

  1. Sehen Sie sich den Quellcode der Beispielanwendung an:

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

    Diese Anwendung ruft die Secret Manager API auf, um zu versuchen, das Secret zu lesen.

  2. Prüfen Sie das Pod-Manifest der Beispielanwendung:

    # 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

    Das Manifest tut Folgendes:

    • Erstellt einen Pod im Namespace readonly-ns, der das Dienstkonto readonly-sa verwendet.
    • Ruft eine Beispielanwendung aus einer Google Image Registry ab. Diese Anwendung ruft die Secret Manager API mithilfe der Google Cloud-Clientbibliotheken auf. Sie können sich den Anwendungscode im Repository in /main.go ansehen.
    • Legt Umgebungsvariablen für die zu verwendende Beispielanwendung fest.
  3. Ersetzen Sie Umgebungsvariablen in der Beispielanwendung:

    sed -i "s/YOUR_PROJECT_ID/PROJECT_ID/g" "manifests/secret-app.yaml"
    
  4. Stellen Sie die Beispiel-App bereit:

    kubectl apply -f manifests/secret-app.yaml
    

    Es kann einige Minuten dauern, bis der Pod funktioniert. Wenn der Pod einen neuen Knoten in Ihrem Cluster benötigt, bemerken Sie möglicherweise Ereignisse vom Typ CrashLoopBackOff, während GKE den Knoten bereitstellt. Die Abstürze enden, wenn der Knoten erfolgreich bereitgestellt wurde.

  5. Prüfen Sie den Secret-Zugriff:

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

    Die Ausgabe lautet my-second-api-key. Wenn die Ausgabe leer ist, wird der Pod möglicherweise noch nicht ausgeführt. Warten Sie ein paar Minuten und versuchen Sie es noch einmal.

Alternative Ansätze

Wenn Sie vertrauliche Daten auf Ihren Pods bereitstellen müssen, verwenden Sie das Secret Manager-Add-on für GKE (Vorschau). Dieses Add-on stellt den Google Cloud Secret Manager-Anbieter für den CSI-Treiber für Kubernetes Secret Store in Ihren GKE-Clustern bereit und verwaltet ihn. Eine Anleitung finden Sie unter Secret Manager-Add-on mit GKE verwenden.

Die Bereitstellung von Secrets als bereitgestellte Volumes birgt die folgenden Risiken:

  1. Bereitgestellte Volumes sind anfällig für Directory-Traversal-Angriffe.
  2. Umgebungsvariablen können aufgrund von Fehlkonfigurationen wie dem Öffnen eines Debugging-Endpunkts manipuliert werden.

Wann immer möglich, empfehlen wir den programmatischen Zugriff auf Secrets über die Secret Manager API. Eine Anleitung dazu erhalten Sie anhand der Beispielanwendung in diesem Tutorial oder unter Secret Manager-Clientbibliotheken.

Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

Einzelne Ressourcen löschen

  1. Löschen Sie den Cluster:

    gcloud container clusters delete secret-cluster \
        --region=us-central1
    
  2. Löschen Sie die IAM-Dienstkonten:

    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. Optional: Secret in Secret Manager löschen:

    gcloud secrets delete bq-readonly-key
    

    Wenn Sie diesen Schritt nicht ausführen, läuft das Secret automatisch ab, da Sie bei der Erstellung das --ttl-Flag gesetzt haben.

Projekt löschen

    Google Cloud-Projekt löschen:

    gcloud projects delete PROJECT_ID

Nächste Schritte