Configurar a federação de identidade da carga de trabalho com o Kubernetes

Neste guia, descrevemos como usar a federação de identidade da carga de trabalho para permitir que as cargas de trabalho executadas no Serviço do Azure Kubernetes (AKS), no Amazon Elastic Kubernetes Service ou em um cluster auto-hospedado do Kubernetes sejam autenticadas no Google Cloud.

O Kubernetes permite configurar um cluster para que as cargas de trabalho recebam tokens da ServiceAccount do Kubernetes de um volume projetado. Ao configurar a federação de identidade da carga de trabalho, é possível permitir que ela use esses tokens da ServiceAccount do Kubernetes para se autenticar no Google Cloud.

Se estiver usando o GKE, use a Federação de Identidade da Carga de Trabalho para GKE em vez de configurar a federação de identidade da carga de trabalho.

Antes de começar

Antes de configurar a federação de identidade da carga de trabalho, verifique se o cluster do Kubernetes atende aos seguintes critérios:

GKE

Para usuários do Google Kubernetes Engine (GKE), consulte Autenticar as APIs do Google Cloud nas cargas de trabalho do GKE.

AKS

O cluster precisa atender aos seguintes requisitos:

  • Você ativou o recurso emissor do OIDC.

    Ative esse recurso para que a federação de identidade da carga de trabalho possa acessar os metadados do OpenID Connect e o conjunto de chaves da Web JSON (JWKS, na sigla em inglês) do cluster.

EKS

Não é necessário fazer mudanças na configuração do EKS.

Kubernetes

O cluster precisa atender aos seguintes requisitos:

O cluster não precisa ser acessível pela Internet.

Configurar a federação de identidade da carga de trabalho

Você só precisa realizar essas etapas uma vez para cada cluster do Kubernetes. Depois disso, será possível usar o mesmo pool de identidade da carga de trabalho e servidor em várias cargas de trabalho e em vários projetos do Google Cloud.

Para começar a configurar a federação de identidade da carga de trabalho, faça isto:

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Recomendamos que você use um projeto dedicado para gerenciar pools de identidade da carga de trabalho e de transporte público.
  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the IAM, Resource Manager, Service Account Credentials, and Security Token Service APIs.

    Enable the APIs

Definir um mapeamento e uma condição de atributo

Os tokens da ServiceAccount do Kubernetes contêm várias declarações, incluindo:

  • sub: contém o namespace e o nome da ServiceAccount, por exemplo, system:serviceaccount:NAMESPACE:KSA_NAME, em que NAMESPACE é o namespace da ServiceAccount e KSA_NAME é o nome da ServiceAccount.
  • "kubernetes.io".namespace: contém o namespace da ServiceAccount.
  • "kubernetes.io".serviceaccount.name: contém o nome da ServiceAccount.
  • "kubernetes.io".pod.name: contém o nome do pod.

Para usar sub como identificador de assunto (google.subject) no Google Cloud, use o seguinte mapeamento:

google.subject=assertion.sub

Também é possível mapear outros atributos. Consulte esses atributos ao conceder acesso aos recursos. Por exemplo:

google.subject=assertion.sub,
attribute.namespace=assertion['kubernetes.io']['namespace'],
attribute.service_account_name=assertion['kubernetes.io']['serviceaccount']['name'],
attribute.pod=assertion['kubernetes.io']['pod']['name']

Também é possível definir uma condição de atributo. As condições de atributo são expressões CEL que podem verificar atributos de declaração e atributos de destino. Se a condição do atributo for avaliada como true para uma determinada credencial, a credencial será aceita. Caso contrário, a credencial será rejeitada.

É possível usar uma condição de atributo para restringir quais contas de serviço do Kubernetes podem usar a federação de identidade da carga de trabalho para receber tokens de curta duração do Google Cloud. Por exemplo, a condição a seguir restringe o acesso às contas de serviço do Kubernetes dos namespaces backend e monitoring:

assertion['kubernetes.io']['namespace'] in ['backend', 'monitoring']

Criar um pool de identidade e um pol de Identidade da carga de trabalho

Funções exigidas

Para receber as permissões necessárias para configurar a federação de identidade da carga de trabalho, peça ao administrador para conceder a você os seguintes papéis do IAM no projeto:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Também é possível conseguir as permissões necessárias por meio de papéis personalizados ou de outros papéis predefinidos.

Como alternativa, o papel básico de Proprietário do IAM (roles/owner) também inclui permissões para configurar a federação de identidade. Não conceda papéis básicos em um ambiente de produção, recomendamos que você faça isso em um ambiente de desenvolvimento ou teste.

Para criar um pool de identidades e um provedor de carga de trabalho, faça o seguinte:

AKS

  1. Determine o URL do emissor do cluster do AKS:

    az aks show -n NAME -g RESOURCE_GROUP --query "oidcIssuerProfile.issuerUrl" -otsv
    

    Substitua:

    • NAME: o nome do cluster.
    • RESOURCE_GROUP: o grupo de recursos do cluster.

    O comando gera o URL do emissor. Você precisa do URL do emissor em uma das etapas a seguir.

    Se o comando não retornar um URL do emissor, verifique se você ativou o recurso emissor do OIDC.

  2. Crie um novo pool de identidade da carga de trabalho:

    gcloud iam workload-identity-pools create POOL_ID \
        --location="global" \
        --description="DESCRIPTION" \
        --display-name="DISPLAY_NAME"
    

    Substitua:

    • POOL_ID: o ID exclusivo do pool.
    • DISPLAY_NAME: o nome do pool.
    • DESCRIPTION: uma descrição do pool escolhido. Essa descrição aparece quando você concede acesso às identidades do pool.
  3. Adicione o cluster do AKS como um provedor de pool de Identidade da carga de trabalho:

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="ISSUER" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS"
    

    Substitua:

    • PROVIDER_ID: um ID de provedor do pool de Identidade da carga de trabalho exclusivo de sua escolha.
    • POOL_ID: o ID do pool de Identidade da carga de trabalho que você criou anteriormente.
    • ISSUER: o URI do emissor que você determinou anteriormente.
    • MAPPINGS: uma lista separada por vírgulas de mapeamentos de atributos criados anteriormente neste guia.
    • CONDITIONS: uma condição de atributo opcional que você criou anteriormente neste guia. Remova o parâmetro se você não tiver uma condição de atributo.

EKS

  1. Determine o URL do emissor do cluster do EKS:

    aws eks describe-cluster --name NAME --query "cluster.identity.oidc.issuer" --output text
    

    Substitua NAME pelo nome do cluster.

    O comando gera o URL do emissor. Você precisa do URL do emissor em uma das etapas a seguir.

  2. Crie um novo pool de identidade da carga de trabalho:

    gcloud iam workload-identity-pools create POOL_ID \
        --location="global" \
        --description="DESCRIPTION" \
        --display-name="DISPLAY_NAME"
    

    Substitua:

    • POOL_ID: o ID exclusivo do pool.
    • DISPLAY_NAME: o nome do pool.
    • DESCRIPTION: uma descrição do pool escolhido. Essa descrição aparece quando você concede acesso às identidades do pool.
  3. Adicione o cluster do EKS como um provedor de pool de Identidade da carga de trabalho:

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="ISSUER" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS"
    

    Substitua:

    • PROVIDER_ID: um ID de provedor do pool de Identidade da carga de trabalho exclusivo de sua escolha.
    • POOL_ID: o ID do pool de Identidade da carga de trabalho que você criou anteriormente.
    • ISSUER: o URI do emissor que você determinou anteriormente.
    • MAPPINGS: uma lista separada por vírgulas de mapeamentos de atributos criados anteriormente neste guia.
    • CONDITIONS: uma condição de atributo opcional que você criou anteriormente neste guia. Remova o parâmetro se você não tiver uma condição de atributo.

Kubernetes

  1. Conecte-se ao cluster do Kubernetes e use kubectl para determinar o URL do emissor do cluster:

    kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
    

    Você precisa do URL do emissor em uma das etapas a seguir.

  2. Faça o download do conjunto de chaves da Web JSON (JWKS, na sigla em inglês) do cluster:

    kubectl get --raw /openid/v1/jwks > cluster-jwks.json
    

    Em uma das etapas a seguir, faça upload do JWKS para que a federação de identidade da carga de trabalho possa verificar a autenticidade dos tokens da ServiceAccount do Kubernetes emitidos pelo cluster.

  3. Crie um novo pool de identidade da carga de trabalho:

    gcloud iam workload-identity-pools create POOL_ID \
        --location="global" \
        --description="DESCRIPTION" \
        --display-name="DISPLAY_NAME"
    

    Substitua:

    • POOL_ID: o ID exclusivo do pool.
    • DISPLAY_NAME: o nome do pool.
    • DESCRIPTION: uma descrição do pool escolhido. Essa descrição aparece quando você concede acesso às identidades do pool.
  4. Adicione o cluster do Kubernetes como provedor de pool de identidades de carga de trabalho e faça upload do JWKS do cluster:

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID \
        --location="global" \
        --workload-identity-pool="POOL_ID" \
        --issuer-uri="ISSUER" \
        --attribute-mapping="MAPPINGS" \
        --attribute-condition="CONDITIONS" \
        --jwk-json-path="cluster-jwks.json"
    

    Substitua:

    • PROVIDER_ID: um ID de provedor do pool de Identidade da carga de trabalho exclusivo de sua escolha.
    • POOL_ID: o ID do pool de Identidade da carga de trabalho que você criou anteriormente.
    • ISSUER: o URI do emissor que você determinou anteriormente.
    • MAPPINGS: uma lista separada por vírgulas de mapeamentos de atributos criados anteriormente neste guia.
    • CONDITIONS: uma condição de atributo opcional que você criou anteriormente neste guia. Remova o parâmetro se você não tiver uma condição de atributo.

Conceder acesso a uma carga de trabalho do Kubernetes

Esta seção descreve como configurar uma carga de trabalho do Kubernetes para acessar as APIs do Google Cloud usando o acesso direto a recursos da federação de identidade da carga de trabalho ou a identidade temporária de conta de serviço.

Execute essas etapas uma vez para cada carga de trabalho do Kubernetes que precise de acesso ao Google Cloud.

Recomendamos usar a federação de identidade da carga de trabalho. No entanto, ao usar a federação de identidade, alguns métodos de API podem ter limitações. Para ver uma lista de limitações, consulte Federação de identidade: produtos e limitações.

Se os métodos usados pela carga de trabalho tiverem essas limitações, use a representação do IAM.

Usar a federação de identidade da carga de trabalho para conceder acesso direto a recursos

Nesta seção, use a federação de identidade da carga de trabalho para conceder um papel do IAM a uma ServiceAccount do Kubernetes para que ela possa acessar diretamente os recursos do Google Cloud.

Para criar uma ServiceAccount do Kubernetes e conceder um papel a ela, faça o seguinte:

  1. Crie uma ServiceAccount do Kubernetes:

    kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
    

    Substitua:

    • KSA_NAME: um nome da ServiceAccount.
    • NAMESPACE: o namespace em que a ServiceAccount será criada.
  2. Conceda acesso do IAM à ServiceAccount do Kubernetes para um recurso do Google Cloud.

    Seguindo o princípio de privilégio mínimo, recomendamos conceder apenas papéis específicos para os recursos que o aplicativo precisa acessar.

    No exemplo a seguir, o comando concede o papel de leitor de cluster do Kubernetes Engine (roles/container.clusterViewer) à ServiceAccount que você criou. O comando usa o assunto que você mapeou anteriormente neste documento.

    gcloud projects add-iam-policy-binding projects/PROJECT_ID \
        --role=roles/container.clusterViewer \
        --member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/MAPPED_SUBJECT \
        --condition=None
    

    Substitua:

    • PROJECT_NUMBER: o número do projeto do Google Cloud associado ao ID do projeto.

    • POOL_ID: o ID do pool de identidade da carga de trabalho.

    • MAPPED_SUBJECT: a ServiceAccount do Kubernetes da reivindicação no token de ID mapeado para google.subject. Por exemplo, se você mapeou google.subject=assertions.sub e o token do ID contém "sub": "system:serviceaccount:default:my-kubernetes-serviceaccount", MAPPED_SUBJECT é system:serviceaccount:default:my-kubernetes-serviceaccount.

    É possível conceder papéis em qualquer recurso do Google Cloud compatível com políticas de permissão do IAM. A sintaxe do identificador principal depende do recurso do Kubernetes. Para uma lista de identificadores compatíveis, consulte Identificadores principais da Federação de Identidade da Carga de Trabalho para GKE.

Agora você pode implantar uma carga de trabalho que usa a ServiceAccount do Kubernetes para acessar os recursos do Google Cloud a que você concedeu acesso.

Alternativa: usar a identidade temporária de conta de serviço do IAM para conceder acesso

Para configurar a ServiceAccount do Kubernetes para usar a personificação de ServiceAccount do IAM, faça o seguinte:

  1. Crie uma ServiceAccount do Kubernetes, se ainda não tiver feito isso:

    kubectl create serviceaccount KSA_NAME --namespace NAMESPACE
    

    Substitua:

    • KSA_NAME: um nome para a ServiceAccount
    • NAMESPACE: o namespace em que a ServiceAccount será criada.
  2. Crie uma conta de serviço do IAM que represente a carga de trabalho.

    A conta de serviço não precisa estar no mesmo projeto que o pool de identidade da carga de trabalho, mas você precisa especificar o projeto que contém a conta de serviço ao se referir a ela.

    gcloud iam service-accounts create IAM_SA_NAME \
        --project=IAM_SA_PROJECT_ID
    

    Substitua:

    • IAM_SA_NAME: o nome da conta de serviço.
    • IAM_SA_PROJECT_ID: o ID do projeto do consumidor da conta de serviço.
  3. Conceda à conta de serviço do IAM acesso aos recursos específicos do Google Cloud que você quer que a carga de trabalho do Kubernetes acesse.

    gcloud projects add-iam-policy-binding IAM_SA_PROJECT_ID \
        --member="serviceAccount:IAM_SA_NAME@IAM_SA_PROJECT_ID.iam.gserviceaccount.com" \
        --role="ROLE"
    

    Substitua:

    • IAM_SA_PROJECT_ID: o ID do projeto em que você criou a conta de serviço
    • IAM_SA_NAME: o nome da conta de serviço.
    • ROLE: com o nome do papel como, por exemplo, roles/container.clusterViewer
  4. Conceda à ServiceAccount do Kubernetes acesso para personificar a conta de serviço do IAM:

    gcloud iam service-accounts add-iam-policy-binding \
      IAM_SA_NAME@IAM_SA_PROJECT_ID.iam.gserviceaccount.com \
        --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/MAPPED_SUBJECT" \
        --role=roles/iam.workloadIdentityUser
    
    

    Substitua:

    • IAM_SA_NAME: o nome da conta de serviço.
    • PROJECT_ID: o ID do projeto executando o Kubernetes
    • IAM_SA_PROJECT_NUMBER: o número do projeto em que você criou a conta de serviço
    • POOL_ID: o ID do pool de identidade da carga de trabalho.
    • MAPPED_SUBJECT: a ServiceAccount do Kubernetes da reivindicação no token de ID mapeado para google.subject. Por exemplo, se você mapeou google.subject=assertions.sub e o token do ID contém "sub": "system:serviceaccount:default:my-kubernetes-serviceaccount", MAPPED_SUBJECT é system:serviceaccount:default:my-kubernetes-serviceaccount.

    Para ver informações sobre como autorizar contas de serviço do Google a acessar as APIs do Google Cloud, consulte Como entender as contas de serviço.

Agora você pode implantar uma carga de trabalho que usa a ServiceAccount do Kubernetes e a ServiceAccount do IAM para acessar os recursos do Google Cloud a que você concedeu acesso.

Implantar a carga de trabalho do Kubernetes

Para implantar uma carga de trabalho do Kubernetes que possa acessar recursos do Google Cloud, faça o seguinte:

  1. Crie um arquivo de configuração de credenciais:

    gcloud iam workload-identity-pools create-cred-config \
        projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID \
        --service-account=SERVICE_ACCOUNT_EMAIL \
        --credential-source-file=/var/run/service-account/token \
        --credential-source-type=text \
        --output-file=credential-configuration.json

    Substitua:

    • PROJECT_NUMBER: o número do projeto que contém o pool de Identidade da carga de trabalho
    • POOL_ID: o ID do pool de identidades da carga de trabalho
    • PROVIDER_ID: o ID do provedor do pool de Identidade da carga de trabalho
    • SERVICE_ACCOUNT_EMAIL: endereço de e-mail da conta de serviço, se você configurou a ServiceAccount do Kubernetes para usar a falsificação de identidade da ServiceAccount do IAM. Omita essa flag se você tiver configurado a ServiceAccount do Kubernetes para usar o acesso direto aos recursos.

    O arquivo de configuração de credenciais permite que as bibliotecas de cliente do Cloud, a gcloud CLI e o Terraform determinem o seguinte:

    • De onde receber credenciais externas
    • Qual pool de identidades de carga de trabalho e provedor usar
    • Qual conta de serviço representar
  2. Importe o arquivo de configuração de credenciais como um ConfigMap

    kubectl create configmap CONFIGMAP_NAME \
      --from-file credential-configuration.json \
      --namespace NAMESPACE
    

    Substitua:

    • CONFIGMAP_NAME: o nome do ConfigMap.
    • NAMESPACE: o namespace em que o ConfigMap será criado.
  3. Implante uma carga de trabalho e permita que ela use a ServiceAccount do Kubernetes e o ConfigMap.

    Crie um manifesto e configure-o da seguinte maneira:

    • Ative um volume de token projetado para que a carga de trabalho possa receber um token de ServiceAccount do Kubernetes de um arquivo local. Configure o volume para que o token da ServiceAccount do Kubernetes use o público-alvo esperado pelo provedor do pool de identidade da carga de trabalho.
    • Ative o ConfigMap que contém o arquivo de configuração da credencial para que a carga de trabalho possa acessar a configuração necessária para usar a federação de identidade da carga de trabalho.
    • Adicione uma variável de ambiente GOOGLE_APPLICATION_CREDENTIALS que contenha o caminho do arquivo de configuração da credencial para que as cargas de trabalho possam encontrá-lo.

    Veja a seguir um manifesto de exemplo que usa a ServiceAccount do Kubernetes e o ConfigMap para permitir que a CLI do Google Cloud seja autenticada no Google Cloud:

    apiVersion: v1
    kind: Pod
    metadata:
      name: example
      namespace: NAMESPACE
    spec:
      containers:
      - name: example
        image: google/cloud-sdk:alpine
        command: ["/bin/sh", "-c", "gcloud auth login --cred-file $GOOGLE_APPLICATION_CREDENTIALS && gcloud auth list && sleep 600"]
        volumeMounts:
        - name: token
          mountPath: "/var/run/service-account"
          readOnly: true
        - name: workload-identity-credential-configuration
          mountPath: "/etc/workload-identity"
          readOnly: true
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: "/etc/workload-identity/credential-configuration.json"
    
      serviceAccountName: KSA_NAME
      volumes:
      - name: token
        projected:
          sources:
          - serviceAccountToken:
              audience: https://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID
              expirationSeconds: 3600
              path: token
      - name: workload-identity-credential-configuration
        configMap:
          name: CONFIGMAP_NAME

    É possível seguir a mesma abordagem para permitir que ferramentas e cargas de trabalho que usam uma das seguintes bibliotecas de cliente encontrem credenciais automaticamente:

    C++

    As bibliotecas de cliente do Google Cloud para C++ são compatíveis com a federação de identidade da carga de trabalho desde a versão v2.6.0. Para usar a federação de identidade da carga de trabalho, crie as bibliotecas de cliente com a versão 1.36.0 ou mais recente do gRPC.

    Go

    As bibliotecas de cliente do Go são compatíveis com a federação de identidade da carga de trabalho se usarem a versão v0.0.0-20210218202405-ba52d332ba99 ou posteriores do módulo golang.org/x/oauth2.

    Para verificar qual versão deste módulo sua biblioteca de cliente usa, execute os seguintes comandos:

    cd $GOPATH/src/cloud.google.com/go
    go list -m golang.org/x/oauth2
    

    Java

    As bibliotecas de cliente do Java aceitam federação de identidade da carga de trabalho se usarem a versão 0.24.0 ou posteriores do artefato com.google.auth:google-auth-library-oauth2-http.

    Para verificar qual versão desse artefato a biblioteca de cliente usa, execute o seguinte comando do Maven no diretório do aplicativo:

    mvn dependency:list -DincludeArtifactIds=google-auth-library-oauth2-http
    

    Node.js

    As bibliotecas de cliente do Node.js são compatíveis com a federação de identidade da carga de trabalho se usarem a versão 7.0.2 ou posteriores do pacote google-auth-library.

    Para verificar qual versão desse pacote sua biblioteca de cliente usa, execute o seguinte comando no diretório do seu aplicativo:

    npm list google-auth-library
    

    Ao criar um objeto GoogleAuth, é possível especificar um ID de projeto ou permitir que GoogleAuth encontre o ID do projeto automaticamente. Para encontrar o ID do projeto automaticamente, a conta de serviço no arquivo de configuração precisa ter o papel de navegador (roles/browser), ou um papel com permissões equivalentes no projeto. Para ver detalhes, consulte o README do pacote google-auth-library.

    Python

    As bibliotecas de cliente do Python são compatíveis com a federação de identidade da carga de trabalho se usarem a versão 1.27.0 ou posteriores do pacote google-auth.

    Para verificar qual versão desse pacote sua biblioteca de cliente usa, execute o seguinte comando no ambiente em que o pacote está instalado:

    pip show google-auth
    

    Para especificar um ID de projeto para o cliente de autenticação, defina a variável de ambiente GOOGLE_CLOUD_PROJECT ou permita que o cliente encontre o ID do projeto automaticamente. Para encontrar o ID do projeto automaticamente, a conta de serviço no arquivo de configuração precisa ter o papel de Navegador (roles/browser) ou um papel com permissões equivalentes no projeto. Para ver detalhes, consulte o guia do usuário do pacote google-auth.

    gcloud

    Para autenticar usando a federação de identidade da carga de trabalho, use o comando gcloud auth login:

    gcloud auth login --cred-file=FILEPATH.json
    

    Substitua FILEPATH pelo caminho para o arquivo de configuração de credencial.

    O suporte para a federação de identidade da carga de trabalho na gcloud CLI está disponível na versão 363.0.0 e posteriores da gcloud CLI.

    Terraform

    O provedor do Google Cloud é compatível com a federação de identidade da carga de trabalho se você usar a versão 3.61.0 ou posterior:

    terraform {
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = "~> 3.61.0"
        }
      }
    }
    

    bq

    Para autenticar usando a federação de identidade da carga de trabalho, use o comando gcloud auth login da seguinte maneira:

    gcloud auth login --cred-file=FILEPATH.json
    

    Substitua FILEPATH pelo caminho para o arquivo de configuração de credencial.

    O suporte para a federação de identidade da carga de trabalho no bq está disponível na versão 390.0.0 e posteriores da gcloud CLI.

  4. Se quiser, verifique se a autenticação funciona corretamente executando o seguinte comando:

    kubectl exec example --namespace NAMESPACE -- gcloud auth print-access-token

A seguir