Configurar o acesso baseado em certificado para a federação de identidade da carga de trabalho

Este documento descreve como configurar o acesso baseado em certificado para a federação de identidade da carga de trabalho usando certificados X.509.

O acesso baseado em certificado usa o TLS mútuo (mTLS) para autenticar o cliente e o servidor durante um handshake de TLS. Nesse processo, uma vinculação mTLS incorpora políticas com base no contexto de transporte e usa o estado do certificado do cliente na sessão TLS para tomar decisões de autorização.

Para a federação de identidade da carga de trabalho X.509, uma vinculação mTLS garante que todo o fluxo de autenticação esteja vinculado com segurança a uma carga de trabalho confiável. Isso reduz o risco de roubo de credenciais, porque a autenticação está vinculada a um endpoint específico e confiável.

Visão geral da configuração do acesso baseado em certificado para a federação de identidade da carga de trabalho

A seguir, apresentamos uma visão geral do processo para configurar o acesso baseado em certificado para a federação de identidade da carga de trabalho:

  1. Estabeleça uma federação de identidade da carga de trabalho configurando a confiança com o ponto de confiança dos certificados X.509.

  2. Crie um nível de acesso para o acesso baseado em certificado.

  3. Adicione o nível de acesso a uma política de acesso baseado no contexto que aplique a vinculação mTLS.

Antes de começar

Verifique se você atende aos seguintes pré-requisitos:

Criar um nível de acesso para certificados

  1. Crie um nível de acesso mTLS. O nível de acesso do mTLS valida certificados ao determinar o acesso a recursos.

    Console

    No Access Context Manager, crie um nível de acesso personalizado e insira a seguinte expressão no campo de expressão CEL: request.auth.matchesMtlsTokens(origin) == true.

    gcloud

    Para criar um nível de acesso personalizado, execute o seguinte comando:

       gcloud access-context-manager levels create ACCESS_LEVEL_NAME 
    --title=TITLE
    --custom-level-spec=FILE
    --description=DESCRIPTION
    --policy=POLICY_NAME

    Substitua:

    • ACCESS_LEVEL_NAME: o nome do nível de acesso.
    • TITLE: o título do nível de acesso.
    • FILE: um arquivo YAML com o seguinte conteúdo: request.auth.matchesMtlsTokens(origin) == true.
    • DESCRIPTION: uma descrição do nível de acesso.
    • POLICY_NAME: o nome da política de acesso.
  2. Exporte o nível de acesso que você criou para uma variável de ambiente. Essa variável será usada nas etapas subsequentes.

      export ACCESS_LEVEL_ID=ACCESS_LEVEL_ID
      

    Substitua ACCESS_LEVEL_ID pelo nome do nível de acesso, por exemplo, accessPolicies/12345/accessLevels/acl_1.

Criar uma vinculação de acesso baseado no contexto para um pool de identidades da carga de trabalho

  1. Defina as seguintes variáveis de ambiente.

    export ORG_ID=ORG_ID
    export CALLER_PROJECT_ID=CALLER_PROJECT_ID
    export FEDERATED_PRINCIPAL=FEDERATED_PRINCIPAL
    

    Substitua:

    • ORG_ID: o ID da organização.
    • CALLER_PROJECT_ID: o ID do projeto a ser usado para chamar as APIs.
    • FEDERATED_PRINCIPAL: o nome do principal de identidade no pool de identidades da carga de trabalho que segue a política de acesso sensível ao contexto. É possível usar uma das seguintes opções:

      uma única identidade com o formato: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE

      OU

      todas as identidades em um pool com o formato - principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*

    gcloud

    gcloud alpha access-context-manager cloud-bindings create \
    --organization=ORG_ID \
    --federated-principal=FEDERATED_PRINCIPAL \
    --level=ACCESS_LEVEL_ID
    --dry-run-level=DRY_RUN_ACCESS_LEVEL_ID
    

    Substitua:

    • ACCESS_LEVEL_ID: o nome do nível de acesso.
    • DRY_RUN_ACCESS_LEVEL_ID: o nome do nível de acesso de simulação. Recomendamos que você ative uma vinculação de política de simulação primeiro para entender o impacto potencial no tráfego atual.

    curl

    1. Crie um arquivo JSON com a vinculação do Acesso baseado no contexto.

      Só é possível fornecer um nível de acesso em uma solicitação, mesmo que o campo seja repetido. É possível usar os seguintes tipos de principais federados:

      • Identidade única: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE
      • Todas as identidades em um pool: principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*
      echo { \
        \"principal\": { \
          \"federatedPrincipal\": \"${FEDERATED_PRINCIPAL:?}\" \
        },\
        \"accessLevels\": [\"${ACCESS_LEVEL_ID:?}\"] \
      } \
      >> request.json
      
    2. Use curl para enviar a seguinte solicitação HTTP.

      curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X POST \
         -H "Authorization: Bearer $(gcloud auth print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         -d @request.json \
       "https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings"
      

Autorizar usando as bibliotecas de cliente Google Cloud

Para autorizar cargas de trabalho da federação de identidade de colaboradores usando as bibliotecas de clienteGoogle Cloud , siga estas etapas.

  1. Crie um arquivo de Application Default Credentials (ADC) configurado para autenticação da federação de identidade da força de trabalho.

    gcloud iam workload-identity-pools create-cred-config IDENTITY_POOL_ID \
    --credential-cert-path WORKLOAD_CERTIFICATE_PATH \
    --credential-cert-private-key-path WORKLOAD_KEY_PATH \
    --output-file ADC_FILE_OUTPUT_PATH
    

    Substitua:

    • IDENTITY_POOL_ID: o ID do seu pool de identidades da carga de trabalho.
    • WORKLOAD_CERTIFICATE_PATH: o caminho para o arquivo de certificado da sua carga de trabalho.
    • WORKLOAD_KEY_PATH: o caminho para o arquivo de chave privada da sua carga de trabalho.
    • ADC_FILE_OUTPUT_PATH: o caminho de saída para o arquivo ADC.

    Esse comando também gera um arquivo de configuração de certificado no diretório de configuração padrão da CLI gcloud. O arquivo de configuração do certificado oferece suporte à autenticação inicial e estabelece handshakes mTLS para solicitações subsequentes aos recursos do Google Cloud .

  2. Defina uma variável de ambiente para apontar para o arquivo do ADC. Isso torna suas credenciais detectáveis pelas bibliotecas de cliente do Google.

    export GOOGLE_APPLICATION_CREDENTIALS=${application_default_credentials.json}
    

    Essa etapa é opcional se você omitir o argumento --output-file ao gerar o arquivo ADC. Se você omitir o argumento, o arquivo ADC será criado e lido do diretório de configuração padrão da CLI gcloud.

  3. Para estabelecer e testar o acesso às APIs Google Cloud , siga estas etapas. É possível usar Go ou Python.

    Go

    1. Use o exemplo a seguir para criar um arquivo Go, como golang_test.go.

      package golang_test
      
      import (
           "io"
           "log"
           "testing"
      
           "cloud.google.com/go/auth/credentials"
           "cloud.google.com/go/auth/httptransport"
      )
      
      func TestGoExample(t *testing.T) {
      
           scopes := []string{
                   "https://www.googleapis.com/auth/pubsub", // Scope for Pub/Sub access
                   // Add other scopes as needed
           }
      
           dopts := credentials.DetectOptions{
                   Scopes: scopes,
           }
      
           // Create httptransport.Options with the scopes
           opts := &httptransport.Options{
                   DetectOpts: &dopts,
           }
           hc, err := httptransport.NewClient(opts)
           if err != nil {
                   t.Fatalf("NewHTTPClient: %v", err)
           }
      
           resp, err := hc.Get("https://pubsub.mtls.googleapis.com/v1/projects/PROJECT_ID/topics")
           if err != nil {
                   t.Fatalf("Get: %v", err)
           }
           t.Logf("Status: %s", resp.Status)
      
           t.Cleanup(func() {
                  resp.Body.Close()
           })
      
           b, err := io.ReadAll(resp.Body)
           if err != nil {
                  t.Fatal(err)
           }
           log.Println(string(b))
      }
      

      Substitua PROJECT_ID pelo ID do projeto da CLI gcloud.

    2. Para executar um teste em uma VM do Compute Engine, use o seguinte comando.

    go mod init example.com
    go mod tidy
    go test -v golang_test.go --count=1
    

    Python

    1. Use o exemplo a seguir para criar um arquivo de teste, como python_test.py.

      import google.auth
      import google.auth.transport.requests
      import requests
      
      def test_go_example():
      # Define the required scopes for your application
      scopes = [
         "https://www.googleapis.com/auth/pubsub",  # Scope for Pub/Sub access
         # Add other scopes as needed
      ]
      
      # Obtain Application Default Credentials (ADC) with the specified scopes
      credentials, _ = google.auth.default(scopes=scopes)
      
      # Create an authorized HTTP session using the ADC credentials
      authed_session = google.auth.transport.requests.AuthorizedSession(credentials)
      
      try:
      # Make a GET request to the Pub/Sub API endpoint
      response = authed_session.get(
          "https://pubsub.mtls.googleapis.com/v1/projects/PROJECT_ID/topics"
      )
      
      # Check if the request was successful
      response.raise_for_status()  # Raise an exception for error statuses
      
      # Log the response status and content
      print(f"Status: {response.status_code}")
      print(response.text)
      
      except requests.exceptions.RequestException as e:
      print(f"Error making the request: {e}")
      
      if __name__ == "__main__":
      test_go_example()
      

      Substitua PROJECT_ID pelo ID do projeto da CLI gcloud.

    2. Para executar um teste em uma VM do Compute Engine, siga estas etapas.

      1. Configure um ambiente virtual em Python.
      2. Instale as bibliotecas necessárias.

        pip install google-auth google-auth-httplib2 requests
        
      3. Execute o teste:

        python3 python_test.py
        

Autorizar usando solicitações HTTP simples

Para autorizar cargas de trabalho da federação de identidade de colaboradores usando solicitações HTTP simples, siga estas etapas.

  1. Receba um token de acesso vinculado a certificado do Google Cloud Security Token Service por um handshake mTLS padrão.

  2. Chame os serviços Google Cloud com o token de acesso obtido do Security Token Service. Este exemplo consulta o Cloud Storage.

    $ curl --key ${workload_key.pem} --cert ${workload_cert.pem} -X GET 'https://storage.mtls.googleapis.com/{replace_with_your_resources}' -H "Authorization: Bearer $ACCESS_TOKEN"
    
  3. A vinculação mTLS exige o uso de mTLS. Execute o comando a seguir para verificar se uma conexão não mTLS falha com um erro de autorização.

    $ curl -X GET 'https://storage.googleapis.com/{replace_with_your_resources}' -H "Authorization: Bearer $ACCESS_TOKEN"
    

Listar a vinculação de política

Para listar a vinculação de política da federação de identidade da carga de trabalho, execute o comando a seguir.

gcloud

O comando a seguir lista vinculações específicas em uma determinada organização, filtrando aquelas que se aplicam a principais federados.

gcloud alpha access-context-manager cloud-bindings list \
--organization=ORG_ID \
--filter='principal:federatedPrincipal'

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings?filter=principal%3Afederated_principal"

Atualizar uma vinculação de política

Para atualizar uma vinculação de política, adicione o novo nível de acesso a um arquivo JSON e execute o seguinte comando.

gcloud

gcloud alpha access-context-manager cloud-bindings update \
--binding=BINDING_ID \
--level=NEW_ACCESS_LEVEL_ID

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X PATCH \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json; charset=utf-8" \
 -d @request.json \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings/${BINDING_ID:?}?updateMask=access_levels"

Excluir uma vinculação de política

Para excluir uma vinculação de política, execute o seguinte comando:

gcloud

gcloud alpha access-context-manager cloud-bindings delete \
--binding=BINDING_ID

curl

curl -H "X-Goog-User-Project: ${CALLER_PROJECT_ID:?}" -X DELETE \
   -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://accesscontextmanager.googleapis.com/v1alpha/organizations/${ORG_ID:?}/gcpUserAccessBindings/${BINDING_ID:?}"

Solução de problemas

Confira alguns problemas comuns e as ações sugeridas para resolvê-los:

  • Erro: 403 Forbidden, user does not have permission.

    Ação:verifique a política do IAM para confirmar se o pool de identidades de carga de trabalho tem acesso ao seu recurso Google Cloud .

  • Erro: Unauthorized_client: Could not obtain a value for google.subject from the given credential.

    Ação:o back-end não conseguiu extrair um valor para google.subject do certificado do cliente com base no mapeamento de atributos. Verifique seu certificado do cliente para confirmar se o campo usado para fazer o mapeamento tem um valor.

  • Se você encontrar negações de acesso inesperadas depois de ativar o acesso baseado no contexto, desbloqueie rapidamente o tráfego removendo a vinculação do acesso baseado no contexto usando o seguinte comando:

    gcloud alpha access-context-manager cloud-bindings delete
    

    Depois que o acesso for restaurado, analise o registro de auditoria para determinar por que os pedidos foram negados.