Aceda a segredos armazenados fora dos clusters do GKE através de bibliotecas de cliente

Este tutorial mostra como armazenar os dados confidenciais usados pelos seus clusters do Google Kubernetes Engine (GKE) no Secret Manager. Saiba como aceder aos dados dos seus pods de forma mais segura através da Workload Identity Federation para o GKE e dasGoogle Cloud bibliotecas de cliente.

Armazenar os seus dados confidenciais fora do armazenamento do cluster reduz o risco de acesso não autorizado aos dados se ocorrer um ataque. A utilização da Workload Identity Federation para o GKE para aceder aos dados permite-lhe evitar os riscos associados à gestão de chaves de contas de serviço de longa duração e controlar o acesso aos seus segredos através da gestão de identidade e acesso (IAM) em vez de regras RBAC no cluster. Pode usar qualquer fornecedor de armazenamento secreto externo, como o Secret Manager ou o HashiCorp Vault.

Esta página destina-se a especialistas em segurança que pretendam mover dados confidenciais para fora do armazenamento no cluster. Para saber mais sobre as funções comuns e as tarefas de exemplo que referimos no conteúdo, consulte o artigo Funções e tarefas comuns do utilizador do GKE. Google Cloud

Este tutorial usa um cluster do GKE Autopilot. Para realizar os passos com o GKE Standard, tem de ativar manualmente a Workload Identity Federation para o GKE.

Pode usar a federação de identidades da carga de trabalho para o GKE para aceder a quaisquer Google Cloud APIs a partir de cargas de trabalho do GKE sem ter de usar abordagens menos seguras, como ficheiros de chaves de contas de serviço estáticos. Este tutorial usa o Secret Manager como exemplo, mas pode usar os mesmos passos para aceder a outras Google Cloud APIs. Para saber mais, consulte o artigo Federação de identidades de cargas de trabalho para o GKE.

Objetivos

  • Crie um segredo no Google Cloud Secret Manager.
  • Crie um cluster do GKE Autopilot, espaços de nomes do Kubernetes e contas de serviço do Kubernetes.
  • Crie políticas de autorização da IAM para conceder acesso às suas contas de serviço do Kubernetes no segredo.
  • Use aplicações de teste para validar o acesso da conta de serviço.
  • Execute uma app de exemplo que aceda ao segredo através da API Secret Manager.

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Quando terminar as tarefas descritas neste documento, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

Antes de começar

  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. Se estiver a usar um fornecedor de identidade (IdP) externo, tem primeiro de iniciar sessão na CLI gcloud com a sua identidade federada.

  4. Para inicializar a CLI gcloud, execute o seguinte 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. Se estiver a usar um fornecedor de identidade (IdP) externo, tem primeiro de iniciar sessão na CLI gcloud com a sua identidade federada.

  10. Para inicializar a CLI gcloud, execute o seguinte 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. Prepare o ambiente

    Clone o repositório do GitHub que contém os ficheiros de exemplo para este tutorial:

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

    Crie um Secret no Secret Manager

    1. O exemplo seguinte mostra os dados que vai usar para criar um segredo:

      key=my-api-key
    2. Crie um segredo para armazenar os dados de amostra:

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

      Este comando faz o seguinte:

      • Cria um novo Secret do Secret Manager com a chave de exemplo na região us-central1 Google Cloud .
      • Define o segredo para expirar uma hora após a execução do comando.

    Crie o cluster e os recursos do Kubernetes

    Crie um cluster do GKE, espaços de nomes do Kubernetes e contas de serviço do Kubernetes. Cria dois espaços de nomes, um para acesso só de leitura e outro para acesso de leitura/escrita ao segredo. Também cria uma conta de serviço do Kubernetes em cada espaço de nomes para usar com a Workload Identity Federation para o GKE.

    1. Crie um cluster do GKE Autopilot:

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

      A implementação do cluster pode demorar cerca de cinco minutos. Os clusters do Autopilot têm sempre a federação de identidade da carga de trabalho para o GKE ativada. Se quiser usar um cluster padrão do GKE, tem de ativar manualmente a Workload Identity Federation para o GKE antes de continuar.

    2. Crie um espaço de nomes readonly-ns e um espaço de nomes admin-ns:

      kubectl create namespace readonly-ns
      kubectl create namespace admin-ns
      
    3. Crie uma conta de serviço do readonly-sa Kubernetes e uma conta de serviço do admin-sa Kubernetes:

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

    Crie políticas de autorização da IAM

    1. Conceda à conta de serviço readonly-sa acesso só de leitura ao segredo:

      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
      

      Substitua o seguinte:

      • PROJECT_NUMBER: o número Google Cloud do projeto.
      • PROJECT_ID: o ID do seu Google Cloud projeto.
    2. Conceda à conta de serviço admin-sa acesso de leitura/escrita ao segredo:

      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
      

    Valide o acesso secreto

    Implemente pods de teste em cada espaço de nomes para validar o acesso de leitura e leitura/escrita.

    1. Reveja o manifesto do agrupamento que publica só de leitura:

      # 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 a conta de serviço readonly-sa no espaço de nomes readonly-ns.

    2. Reveja o manifesto do agrupamento de leitura/escrita:

      # 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 a conta de serviço admin-sa no espaço de nomes admin-ns.

    3. Implemente os pods de teste:

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

      Os pods podem demorar alguns minutos a começar a ser executados. Para monitorizar o progresso, execute o seguinte comando:

      watch kubectl get pods -n readonly-ns
      

      Quando o estado do pod mudar para RUNNING, prima Ctrl+C para regressar à linha de comandos.

    Teste o acesso só de leitura

    1. Abra uma shell no readonly-test pod:

      kubectl exec -it readonly-test --namespace=readonly-ns -- /bin/bash
      
    2. Tenta ler o segredo:

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

      O resultado é key=my-api-key.

    3. Tente escrever novos dados no segredo:

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

      O resultado é semelhante ao seguinte:

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

      O Pod que usa a conta de serviço só de leitura só pode ler o segredo e não pode escrever novos dados.

    4. Saia do agrupamento:

      exit
      

    Teste o acesso de leitura/escrita

    1. Abra uma shell no admin-test pod:

      kubectl exec -it admin-test --namespace=admin-ns -- /bin/bash
      
    2. Tenta ler o segredo:

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

      O resultado é key=my-api-key.

    3. Tente escrever novos dados no segredo:

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

      O resultado é semelhante ao seguinte:

      Created version [2] of the secret [bq-readonly-key].
      
    4. Leia a nova versão do segredo:

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

      O resultado é my-second-api-key.

    5. Saia do agrupamento:

      exit
      

    Os pods só recebem o nível de acesso que concedeu à conta de serviço do Kubernetes usada no manifesto do pod. Todos os pods que usam a conta do Kubernetes no espaço de nomes admin-ns podem escrever novas versões do segredo, mas todos os pods no espaço de nomes readonly-ns que usam a conta de serviço do Kubernetes readonly-sa só podem ler o segredo.admin-sa

    Aceda a segredos a partir do seu código

    Nesta secção, faz o seguinte:

    1. Implemente uma aplicação de exemplo que leia o seu segredo no Secret Manager através de bibliotecas de cliente.

    2. Verifique se a aplicação consegue aceder ao seu segredo.

    Sempre que possível, deve aceder aos Secrets do Secret Manager a partir do código da sua aplicação, usando a API Secret Manager.

    1. Reveja o código-fonte da aplicação de exemplo:

      // 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 aplicação chama a API Secret Manager para tentar ler o segredo.

    2. Reveja o manifesto do agrupamento da aplicação de exemplo:

      # 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 manifesto faz o seguinte:

      • Cria um pod no espaço de nomes readonly-ns que usa a conta de serviço readonly-sa.
      • Extrai uma aplicação de amostra de um registo de imagens da Google. Esta aplicação chama a API Secret Manager através dasGoogle Cloud bibliotecas cliente. Pode ver o código da aplicação em /main.go no repositório.
      • Define as variáveis de ambiente que a aplicação de exemplo vai usar.
    3. Substitua as variáveis de ambiente na aplicação de exemplo:

      sed -i "s/YOUR_PROJECT_ID/PROJECT_ID/g" "manifests/secret-app.yaml"
      
    4. Implemente a app de exemplo:

      kubectl apply -f manifests/secret-app.yaml
      

      O Pod pode demorar alguns minutos a começar a funcionar. Se o pod precisar de um novo nó no cluster, pode reparar em eventos do tipo CrashLoopBackOff enquanto o GKE aprovisiona o nó. As falhas de sistema param quando o nó é aprovisionado com êxito.

    5. Valide o acesso secreto:

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

      O resultado é my-second-api-key. Se a saída estiver em branco, o pod pode ainda não estar em execução. Aguarde alguns minutos e tente novamente.

    Abordagens alternativas

    Se precisar de montar os seus dados confidenciais nos seus pods, use o suplemento Secret Manager para o GKE. Este suplemento implementa e gere o fornecedor do Google Cloud Secret Manager para o controlador CSI da Secret Store nos seus clusters do GKE. Para obter instruções, consulte o artigo Use o suplemento Secret Manager com o GKE.

    Fornecer segredos como volumes montados tem os seguintes riscos:

    1. Os volumes montados são suscetíveis a ataques de travessia de diretórios.
    2. As variáveis de ambiente podem ser comprometidas devido a configurações incorretas, como a abertura de um ponto final de depuração.

    Sempre que possível, recomendamos que aceda aos segredos de forma programática através da API Secret Manager. Para ver instruções, use a aplicação de exemplo neste tutorial ou consulte as bibliotecas de cliente do Secret Manager.

    Limpar

    Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

    Elimine recursos individuais

    1. Elimine o cluster:

      gcloud container clusters delete secret-cluster \
          --location=us-central1
      
    2. Opcional: elimine o segredo no Secret Manager:

      gcloud secrets delete bq-readonly-key
      

      Se não realizar este passo, o segredo expira automaticamente porque definiu a flag --ttl durante a criação.

    Elimine o projeto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    O que se segue?