Configurar el acceso basado en certificados para la federación de identidades de cargas de trabajo

En este documento se describe cómo configurar el acceso basado en certificados para la federación de identidades de cargas de trabajo mediante certificados X.509.

El acceso basado en certificados usa TLS mutuo (mTLS) para autenticar tanto al cliente como al servidor durante un handshake TLS. En este proceso, una vinculación mTLS incorpora políticas basadas en el contexto de transporte y usa el estado del certificado del cliente en la sesión TLS para tomar decisiones de autorización.

En la federación de identidades de cargas de trabajo X.509, un enlace mTLS asegura que todo el flujo de autenticación esté vinculado de forma segura a una carga de trabajo de confianza. De esta forma, se reduce el riesgo de robo de credenciales, ya que la autenticación está vinculada a un endpoint específico y de confianza.

Descripción general del acceso basado en certificados para la configuración de la federación de identidades de cargas de trabajo

A continuación, se ofrece una descripción general del proceso para configurar el acceso basado en certificados para la federación de identidades de cargas de trabajo:

  1. Establece una federación de identidades de cargas de trabajo configurando la confianza con el ancla de confianza de los certificados X.509.

  2. Crea un nivel de acceso para el acceso basado en certificados.

  3. Añade el nivel de acceso a una política de acceso contextual que aplique el enlace mTLS.

Antes de empezar

Verifica que cumples los siguientes requisitos previos:

Crear un nivel de acceso para certificados

  1. Crea un nivel de acceso mTLS. El nivel de acceso mTLS valida los certificados al determinar el acceso a los recursos.

    Consola

    En Administrador de contextos de acceso, crea un nivel de acceso personalizado e introduce la siguiente expresión en el campo de expresión CEL: request.auth.matchesMtlsTokens(origin) == true.

    gcloud

    Para crear un nivel de acceso personalizado, ejecuta el siguiente comando:

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

    Haz los cambios siguientes:

    • ACCESS_LEVEL_NAME: nombre del nivel de acceso.
    • TITLE: título del nivel de acceso.
    • FILE: un archivo YAML con el siguiente contenido: request.auth.matchesMtlsTokens(origin) == true.
    • DESCRIPTION: una descripción del nivel de acceso.
    • POLICY_NAME: el nombre de la política de acceso.
  2. Exporta el nivel de acceso que has creado a una variable de entorno. Esta variable se usa en los pasos posteriores.

      export ACCESS_LEVEL_ID=ACCESS_LEVEL_ID
      

    Sustituye ACCESS_LEVEL_ID por el nombre del nivel de acceso (por ejemplo, accessPolicies/12345/accessLevels/acl_1).

Crear una vinculación de acceso contextual para un grupo de identidades de carga de trabajo

  1. Define las siguientes variables de entorno.

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

    Haz los cambios siguientes:

    • ORG_ID: el ID de tu organización.
    • CALLER_PROJECT_ID: el ID del proyecto que se va a usar para llamar a las APIs.
    • FEDERATED_PRINCIPAL: el nombre de la identidad principal del grupo de identidades de carga de trabajo que cumple la política de acceso contextual. Puedes usar una de las siguientes opciones:

      una sola identidad con el formato - principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE

      O

      todas las identidades de un grupo con el 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
    

    Haz los cambios siguientes:

    • ACCESS_LEVEL_ID: nombre del nivel de acceso.
    • DRY_RUN_ACCESS_LEVEL_ID: el nombre del nivel de acceso de la prueba de funcionamiento. Te recomendamos que primero habilites un enlace de política de prueba para conocer el posible impacto en el tráfico actual.

    curl

    1. Crea un archivo JSON con la vinculación de acceso contextual.

      Solo puedes proporcionar un nivel de acceso en una solicitud, aunque el campo se repita. Puedes usar los siguientes tipos de principales federados:

      • Una sola identidad: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT_ATTRIBUTE_VALUE
      • Todas las identidades de un grupo: principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/*
      echo { \
        \"principal\": { \
          \"federatedPrincipal\": \"${FEDERATED_PRINCIPAL:?}\" \
        },\
        \"accessLevels\": [\"${ACCESS_LEVEL_ID:?}\"] \
      } \
      >> request.json
      
    2. Usa curl para enviar la siguiente solicitud 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 mediante las Google Cloud bibliotecas de cliente

Para autorizar cargas de trabajo de la federación de identidades de Workforce mediante lasGoogle Cloud bibliotecas de cliente, sigue estos pasos.

  1. Crea un archivo de credenciales predeterminadas de la aplicación (ADC) configurado para la autenticación de federación de identidades de los empleados.

    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
    

    Haz los cambios siguientes:

    • IDENTITY_POOL_ID: el ID de tu grupo de identidades de carga de trabajo.
    • WORKLOAD_CERTIFICATE_PATH: la ruta al archivo de certificado de tu carga de trabajo.
    • WORKLOAD_KEY_PATH: la ruta al archivo de clave privada de tu carga de trabajo.
    • ADC_FILE_OUTPUT_PATH: la ruta de salida del archivo ADC.

    Este comando también genera un archivo de configuración de certificado en el directorio de configuración predeterminado de la CLI de gcloud. El archivo de configuración del certificado admite la autenticación inicial y establece las negociaciones de mTLS para las solicitudes posteriores a los recursos de Google Cloud .

  2. Define una variable de entorno para que apunte al archivo ADC. De esta forma, las bibliotecas de cliente de Google podrán detectar tus credenciales.

    export GOOGLE_APPLICATION_CREDENTIALS=${application_default_credentials.json}
    

    Este paso es opcional si omite el argumento --output-file al generar el archivo ADC. Si omite el argumento, el archivo ADC se crea y se lee desde el directorio de configuración predeterminado de la CLI de gcloud.

  3. Para establecer y probar el acceso a las APIs de Google Cloud , sigue estos pasos. Puedes usar Go o Python.

    Go

    1. Usa el siguiente ejemplo para crear un archivo 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))
      }
      

      Sustituye PROJECT_ID por el ID de tu proyecto de la CLI de gcloud.

    2. Para ejecutar una prueba en una VM de Compute Engine, usa el siguiente comando.

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

    Python

    1. Usa el siguiente ejemplo para crear un archivo de prueba, 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()
      

      Sustituye PROJECT_ID por el ID de tu proyecto de la CLI de gcloud.

    2. Para ejecutar una prueba en una VM de Compute Engine, sigue estos pasos.

      1. Configura un entorno virtual de Python.
      2. Instala las bibliotecas necesarias.

        pip install google-auth google-auth-httplib2 requests
        
      3. Ejecuta la prueba:

        python3 python_test.py
        

Autorizar con solicitudes HTTP estándar

Para autorizar cargas de trabajo de Workforce Identity Federation mediante solicitudes HTTP sin cifrar, sigue estos pasos.

  1. Obtén un token de acceso enlazado a un certificado del Google Cloud servicio de token de seguridad mediante un handshake mTLS estándar.

  2. Llama a los Google Cloud servicios con el token de acceso que has obtenido del servicio de token de seguridad. En este ejemplo se consulta 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. El enlace mTLS obliga a usar mTLS. Ejecuta el siguiente comando para verificar que una conexión que no es mTLS falla con un error de autorización.

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

Mostrar la vinculación de la política

Para enumerar la vinculación de políticas de la federación de identidades de cargas de trabajo, ejecuta el siguiente comando.

gcloud

El siguiente comando muestra las vinculaciones específicas de una organización determinada y filtra las que se aplican a las entidades federadas.

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"

Actualizar un enlace de política

Para actualizar un enlace de política, añade el nuevo nivel de acceso a un archivo JSON y ejecuta el siguiente 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"

Eliminar una vinculación de política

Para eliminar un enlace de política, ejecuta el siguiente 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:?}"

Solución de problemas

A continuación, se indican algunos problemas habituales y las acciones que puedes llevar a cabo para solucionarlos:

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

    Acción: comprueba la política de IAM para verificar que el pool de identidades de carga de trabajo tiene acceso a tu recurso de Google Cloud .

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

    Acción: el backend no ha podido extraer un valor para google.subject de tu certificado de cliente en función de la asignación de atributos. Comprueba tu certificado de cliente para verificar que el campo que usas para hacer la asignación tiene un valor.

  • Si se deniega el acceso de forma inesperada después de habilitar el acceso contextual, puedes desbloquear rápidamente el tráfico quitando la vinculación del acceso contextual con el siguiente comando:

    gcloud alpha access-context-manager cloud-bindings delete
    

    Una vez que se haya restaurado el acceso, consulta el registro de auditoría para determinar por qué se han denegado las solicitudes.