Autenticar usando uma identidade de agente no GKE

Os agentes do Google Kubernetes Engine (GKE) que têm uma identidade de agente podem usar essa identidade para autenticar APIs do Google Cloud e ferramentas e serviços externos. Os agentes podem usar a própria identidade ou agir em nome dos usuários finais. Este documento mostra aos desenvolvedores de aplicativos de agente como configurar os aplicativos para autenticar em vários recursos. Você já precisa saber como solicitar uma identidade de agente para um agente do GKE.

Dependendo do recurso que o agente precisa acessar, o administrador da plataforma pode precisar configurar o cofre de credenciais do gerenciador de autenticação para executar fluxos de trabalho adicionais. Por exemplo, para que um agente se autentique no GitHub em nome de um usuário final, um provedor de autenticação OAuth de três pernas no gerenciador de autenticação precisa processar o login, a autorização e o redirecionamento do usuário. Como desenvolvedor, você modifica seu agente para chamar o provedor de autenticação correto e retomar a conversa para o usuário final.

Limitações

  • Consulte as limitações da identidade do agente.
  • É possível usar a biblioteca de autenticação do Google para receber tokens de acesso e ID vinculados apenas para Python. A biblioteca de autenticação pode não receber tokens vinculados para outros idiomas. Se você usa um idioma diferente, mude para tokens não vinculados definindo a variável de ambiente GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN como false.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ative a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a Google Cloud CLI para essa tarefa, instale e inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando o comando gcloud components update. Talvez as versões anteriores da CLI gcloud não sejam compatíveis com a execução dos comandos neste documento.

Funções exigidas

Para receber as permissões necessárias para configurar agentes implantados em clusters do GKE, peça ao administrador para conceder a você o papel do IAM de Desenvolvedor do Kubernetes Engine (roles/container.developer) no seu 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 usando papéis personalizados ou outros papéis predefinidos.

Autenticar em APIs do Google Cloud

Para autenticar nas APIs Google Cloud como a própria identidade do agente, ele pode usar um token de acesso de identidade do agente do servidor de metadados nos seus nós. As mudanças que talvez você precise fazer no código dependem de como você chama as APIs Google Cloud , conforme mostrado abaixo.

Usar as bibliotecas de cliente do Cloud

Se você usar uma versão das bibliotecas de cliente do Cloud que inclua a versão 2.61.0 ou mais recente da biblioteca google-auth, as Application Default Credentials (ADC) vão receber automaticamente um token de acesso de Identidade do Agente. Não é necessário fazer outras mudanças no código. Se você ativar a injeção de certificado para os pods definindo a anotação iam.gke.io/inject-podcertificates: "true", o token de acesso será vinculado ao certificado X.509 por padrão, a menos que você desative os tokens vinculados.

Para receber tokens de acesso não vinculados ao usar as bibliotecas de cliente do Cloud, faça uma das seguintes ações:

  • Ative a injeção de certificado no seu pod e defina a variável de ambiente GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN como false.
  • Não ative a injeção de certificado no seu pod.

Usar chamadas diretas para endpoints da API Google Cloud

Se você não usar as bibliotecas de cliente do Cloud para interagir com um serviço, poderá usar a identidade do agente para autenticar uma API Google Cloud fazendo o seguinte:

  1. Receba um token de acesso do servidor de metadados no nó. É possível receber um token usando um dos seguintes métodos:

    • Tokens de acesso vinculados: use a biblioteca Python google-auth, que descobre o certificado X.509 do pod e recebe automaticamente tokens de acesso vinculados por padrão. Para outras linguagens de programação, use tokens sem vinculação.

    • Tokens de acesso não vinculados: se o pod não tiver o pacote de credenciais de identidade do agente, use a biblioteca de autenticação do Google na sua linguagem de programação. A biblioteca de autenticação recebe automaticamente tokens de acesso não vinculados e atualiza os tokens expirados para você. Para aplicativos Python em pods que têm o pacote de credenciais, defina a variável de ambiente GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN na especificação do pod como false, como no exemplo a seguir:

      # Multiple lines are omitted here.
      spec:
        containers:
        - name: example-agent
          image: example-image
          env:
          - name: GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN
            value: "false"
      # Multiple lines are omitted here.
      

      Essa variável de ambiente impede que a biblioteca receba tokens de acesso vinculados e tokens de ID.

  2. Para tokens de acesso vinculados, envie a solicitação ao endpoint mTLS da API e inclua a cadeia de certificados X.509 de identidade do agente no transporte HTTP. Se você usar a biblioteca de autenticação do Google para Python, ela vai processar a configuração de transporte HTTP para você.

O exemplo a seguir demonstra como usar a biblioteca de autenticação do Google para Python a fim de receber um token de acesso vinculado e fazer uma solicitação ao endpoint mTLS do Cloud Storage:

import google.auth
from google.auth.transport.requests import AuthorizedSession


def call_storage_api_mtls(bucket_name: str) -> None:
    # Discover the Pod's X.509 certificate chain by using the auth library
    credentials, project = google.auth.default(
        scopes=["https://www.googleapis.com/auth/cloud-platform"]
    )
    # Configure the mTLS session by using the Pod's certificate chain
    session = AuthorizedSession(credentials)
    session.configure_mtls_channel()
    # Call the Google Cloud mTLS endpoint
    mtls_url = f"https://storage.mtls.googleapis.com/storage/v1/b/{bucket_name}/o"
    response = session.get(mtls_url)
    response.raise_for_status()
    print(response.json())

Autenticar em ferramentas e serviços externos

Para se autenticar em ferramentas e serviços externos, configure o agente para receber as credenciais necessárias do gerenciador de autenticação de identidade do agente. Um administrador da plataforma configura vários provedores de autenticação no gerenciador de autenticação, cada um dos quais gerencia fluxos de trabalho e credenciais de autenticação específicos. Você modifica o código do aplicativo para chamar um provedor de autenticação específico e, dependendo do fluxo de trabalho de autenticação, para processar o consentimento do usuário e a retomada da conversa. As mudanças específicas que você faz no seu agente dependem do que você precisa acessar, da seguinte forma:

O gerenciador de autenticação processa os fluxos de trabalho de autenticação correspondentes e dá ao agente acesso às credenciais criptografadas, que podem ser incluídas em solicitações ao serviço externo. Para mais informações sobre o que o administrador da plataforma precisa fazer para configurar esses provedores de autenticação e conceder acesso à identidade do agente, consulte Fluxos de trabalho de autenticação para agentes.

Autenticar outros agentes

Em arquiteturas multiagentes, os agentes colaboram com frequência invocando diretamente agentes semelhantes ou serviços downstream. É possível estabelecer comunicação direta entre cargas de trabalho de agentes usando tokens de identidade. É possível receber um token de ID vinculado ou não vinculado do servidor de metadados do GKE e usar esse token para autenticar diretamente outros agentes.

Para receber um token de ID e usá-lo em uma solicitação HTTP, use a biblioteca de autenticação do Google para Python. A biblioteca processa automaticamente a descoberta de certificados e a aquisição de tokens de ID. Se você usar outra linguagem de programação, a biblioteca de autenticação do Google talvez não receba tokens de ID vinculados. Mude para tokens de ID não vinculados.

Receber um token de ID

Para solicitar um token de ID no código do seu agente, use a biblioteca de autenticação do Google na sua linguagem de programação. É possível usar a biblioteca para solicitar tokens de ID vinculados ou não vinculados, da seguinte maneira:

  • Tokens de ID vinculados: use a anotação iam.gke.io/inject-podcertificates: "true" para ativar a injeção de certificado no seu pod. A biblioteca de autenticação para Python solicita automaticamente um token de ID vinculado a certificado do servidor de metadados do GKE. Use tokens de ID vinculados ao autenticar entre agentes que são executados no Google Cloud usando mTLS.
  • Tokens de ID não vinculados:

    • Ative a injeção de certificado para seu pod e faça uma destas ações:
      • No código do aplicativo, na função id_token.fetch_id_token, defina o argumento bind_id_token com o valor False. Esse argumento faz com que a biblioteca de autenticação solicite tokens de ID não vinculados. As solicitações de token de acesso não são afetadas.
      • Na especificação do pod, defina a variável de ambiente GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN como um valor de false. Essa variável de ambiente impede que a biblioteca solicite tokens de acesso vinculados e tokens de ID.
    • Não ative a injeção de certificado para seu pod. A biblioteca de autenticação recebe um token de ID não vinculado porque não há um pacote de credenciais no pod.

    Use tokens de ID não vinculados ao se autenticar em Google Cloud APIs, serviços externos ou outros agentes usando uma conexão não mTLS.

Os exemplos a seguir mostram como solicitar um token de ID vinculado ou não vinculado para um agente com a injeção de credenciais ativada:

  • Solicite um token de ID vinculado:

    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    # Application Default Credentials automatically requests a certificate-bound
    # ID token.
    def get_bound_id_token(target_audience: str) -> str:
        auth_req = google.auth.transport.requests.Request()
        return id_token.fetch_id_token(auth_req, audience=target_audience)
    

    O token de identidade vinculada inclui a impressão digital do certificado SHA-256 da cadeia de certificados X.509 do Pod no parâmetro cnf.x5t#S256.

  • Solicite um token de ID sem vinculação:

    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    def get_unbound_id_token(target_audience: str) -> str:
        auth_req = google.auth.transport.requests.Request()
        return id_token.fetch_id_token(
            auth_req,
            audience=target_audience,
            # Always get an unbound ID token, even if the Pod has a credential
            # bundle.
            bind_id_token=False,
        )
    

Usar o token de ID em uma solicitação para outro agente

Depois de receber um token de ID para seu agente, você pode usá-lo para autenticar diretamente em outro agente. A forma de autenticar a conexão depende de você usar um token de ID vinculado, da seguinte maneira:

  • Para tokens de ID vinculados, estabeleça uma conexão mTLS com o agente de recebimento e autentique a conexão usando as duas credenciais a seguir do diretório /var/run/secrets/workload-spiffe-credentials/ no pod:
    • O pacote de credenciais de identidade do agente que está no arquivo x509.credential-bundle.private-key.pem, que contém a cadeia de certificados folha para o pod.
    • O pacote de confiança do cluster que está no arquivo TRUST_DOMAIN.spiffe-trust-bundle.pem. Esse arquivo contém o certificado de CA raiz do agente de recebimento e é usado para validar a cadeia de certificados do agente de recebimento durante o handshake de mTLS. Os agentes de chamada e de recebimento precisam estar no mesmo pool de identidades de agente.
  • Para tokens de ID não vinculados, estabeleça uma conexão não mTLS com o agente de recebimento.

Os exemplos a seguir mostram como enviar uma solicitação para outro agente usando um token de ID vinculado ou não vinculado:

  • Token de ID vinculado: inclua o token de identidade vinculado no cabeçalho Authorization: Bearer da solicitação enviada ao endpoint mTLS do agente de recebimento. Autentique a conexão TLS usando o certificado X.509 e a chave privada do pod:

    import ssl
    import urllib3
    
    BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/x509.credential-bundle.private-key.pem"
    TRUST_BUNDLE_PATH = "/var/run/secrets/workload-spiffe-credentials/TRUST_DOMAIN.spiffe-trust-bundle.pem"
    
    def call_peer_agent_bound_mtls(target_mtls_url: str, target_audience: str) -> None:
    
        # Configure the mTLS context by using the certificate chain and trust
        # bundle from the Pod.
        ctx = ssl.create_default_context(cafile=TRUST_BUNDLE_PATH)
        ctx.load_cert_chain(BUNDLE_PATH)
        http = urllib3.PoolManager(ssl_context=ctx, assert_hostname=False)
    
        # Call a peer agent's mTLS endpoint by using the bound ID token and Pod
        # certificate chain.
        bound_id_token = get_bound_id_token(target_audience)
        response = http.request(
            "POST",
            target_mtls_url,
            headers={"Authorization": f"Bearer {bound_id_token}"},
            json={"task": "analyze_data"},
            timeout=10,
        )
        print(response.json())
    

    Substitua TRUST_DOMAIN pelo domínio de confiança do pool de identidades do agente.

  • Token de ID não vinculado: inclua o token no cabeçalho Authorization: Bearer da sua solicitação para o agente de mesmo nível:

    import requests
    
    def call_peer_agent_unbound(target_url: str, target_audience: str) -> None:
        unbound_id_token = get_unbound_id_token(target_audience)
        # Send the request by using a standard TLS connection or plain HTTP.
        response = requests.post(
            target_url,
            headers={"Authorization": f"Bearer {unbound_id_token}"},
            json={"task": "analyze_data"},
            timeout=10,
        )
        response.raise_for_status()
        print(response.json())
    

Validar a solicitação no agente de recebimento

No agente de recebimento, valide o token de ID na solicitação recebida fazendo o seguinte: É possível usar bibliotecas criptográficas como Tink para realizar essas etapas de verificação em vez de escrever um código personalizado.

  1. Extraia o token de identidade do cabeçalho Authorization: Bearer da solicitação.
  2. Verifique se a declaração iss (emissor) no token de ID é o pool de identidade do agente para o agente de chamada. O emissor é um dos seguintes, dependendo se o agente de chamada está em um projeto que faz parte de uma organização:
    • Projeto em uma organização: https://sts.googleapis.com/v1/organizations/ORGANIZATION_ID/locations/global/workloadIdentityPools/agents.global.org-ORGANIZATION_ID.system.id.goog, em que ORGANIZATION_ID é o ID da organização que contém o projeto do agente de chamada.
    • Projeto que não está em uma organização: https://sts.googleapis.com/v1/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/agents.global.proj-PROJECT_NUMBER.system.id.goog, em que PROJECT_NUMBER é o número do projeto do cluster do GKE do agente de chamada.
  3. Descubra o URI do conjunto de chaves da Web JSON (JWKS) para o emissor e armazene em cache as chaves públicas da Web JSON (JWKs). O endpoint para o JWKS tem o formato ISSUER_URL/openid/jwks, em que ISSUER_URL é o URL do emissor.
  4. Valide a assinatura do token usando as seguintes informações do cabeçalho JOSE do token de ID:
    • O JWK público que corresponde ao parâmetro de cabeçalho kid.
    • O algoritmo criptográfico que corresponde ao parâmetro de cabeçalho alg, como RS256.
  5. Verifique se a impressão digital do certificado SHA-256 no parâmetro cnf.x5t#S256 corresponde à impressão digital do certificado X.509 que o agente de chamada usou para autenticar a conexão mTLS.
  6. Verifique as seguintes declarações no token de ID:
    • O tempo de expiração na declaração exp está no futuro.
    • O público-alvo na declaração aud é o agente receptor.
  7. Autorize a solicitação com base no ID do SPIFFE na declaração sub (assunto) do token.

A seguir