Soluciona problemas de autenticación de GKE

En esta página, se muestra cómo resolver problemas relacionados con las configuraciones de seguridad en los clústeres de Google Kubernetes Engine (GKE) Autopilot y Standard.

IAM y RBAC

Las cuentas autenticadas de IAM no pueden realizar acciones en el clúster

El siguiente problema ocurre cuando intentas realizar una acción en el clúster, pero GKE no puede encontrar una política de RBAC que autorice la acción. GKE intenta encontrar una política de permisos de IAM que otorgue el mismo permiso. Si eso falla, verás un mensaje de error similar al siguiente:

Error from server (Forbidden): roles.rbac.authorization.k8s.io is forbidden:
User "example-account@example-project.iam.gserviceaccount.com" cannot list resource "roles" in
API group "rbac.authorization.k8s.io" in the namespace "kube-system": requires
one of ["container.roles.list"] permission(s).

Para resolver este problema, usa una política de RBAC para otorgar los permisos de la acción que se intentó. Por ejemplo, para resolver el problema en la muestra anterior, otorga un rol que tenga el permiso list en los objetos roles del espacio de nombres kube-system. Para obtener instrucciones, consulta Autoriza acciones en clústeres mediante el control de acceso basado en roles.

Federación de identidades para cargas de trabajo para GKE

El Pod no se puede autenticar en Google Cloud

Si tu aplicación no puede autenticarse en Google Cloud, asegúrate de que los siguientes parámetros de configuración estén configurados correctamente:

  1. Verifica que hayas habilitado la API de Service Account Credentials de IAM en el proyecto que contiene el clúster de GKE.

    Habilitar la API de credenciales IAM

  2. Confirma que la federación de identidades para cargas de trabajo para GKE esté habilitada en el clúster mediante la verificación de que tiene un grupo de identidades para cargas de trabajo configurado:

    gcloud container clusters describe CLUSTER_NAME \
        --format="value(workloadIdentityConfig.workloadPool)"
    

    Reemplaza CLUSTER_NAME por el nombre de tu clúster de GKE.

    Si aún no especificaste una zona o región predeterminada para gcloud, es posible que también debas especificar una marca --region o --zone cuando ejecutes este comando.

  3. Asegúrate de que el servidor de metadatos de GKE esté configurado en el grupo de nodos en el que se ejecuta la aplicación:

    gcloud container node-pools describe NODEPOOL_NAME \
        --cluster=CLUSTER_NAME \
        --format="value(config.workloadMetadataConfig.mode)"
    

    Reemplaza lo siguiente:

    • NODEPOOL_NAME por el nombre de tu grupo de nodos.
    • CLUSTER_NAME por el nombre de tu clúster de GKE.
  4. Si tienes una política de red del clúster, debes permitir la salida a 169.254.169.252/32 en el puerto 988. Para los clústeres que ejecutan GKE Dataplane V2, debes permitir la salida a 169.254.169.254/32 en el puerto 80.

    kubectl describe networkpolicy NETWORK_POLICY_NAME
    

    Reemplaza NETWORK_POLICY_NAME por el nombre de tu política de red de GKE.

Si tu configuración vincula cuentas de servicio de Kubernetes a cuentas de servicio de IAM, verifica lo siguiente:

  1. Verifica que la cuenta de servicio de Kubernetes esté anotada de forma correcta:

    kubectl describe serviceaccount \
        --namespace NAMESPACE KSA_NAME
    

    Reemplaza lo siguiente:

    • NAMESPACE por el espacio de nombres del clúster de GKE.
    • KSA por el nombre de tu cuenta de servicio de Kubernetes.

    El resultado esperado contiene una anotación similar a la siguiente:

    iam.gke.io/gcp-service-account: GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
    
  2. Verifica que la cuenta de servicio de IAM esté configurada de forma correcta

    gcloud iam service-accounts get-iam-policy \
        GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com
    

    El resultado esperado contiene una vinculación similar a la siguiente:

    - members:
      - serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]
      role: roles/iam.workloadIdentityUser
    

Error: El formato del ID de la cuenta no es válido

El siguiente error ocurre cuando intentas realizar una operación que requiere una dirección de correo electrónico de la cuenta de servicio de IAM, como crear manualmente una URL firmada de Cloud Storage:

ERROR: Error: Invalid form of account ID test_account.svc.id.goog. Should be [Gaia ID |Email |Unique ID |] of the account
# Multiple lines are omitted here
command terminated with exit code 137

Este error se produce cuando usas una anotación para vincular cuentas de servicio de Kubernetes a cuentas de servicio de IAM en lugar de usar un identificador principal de IAM para configurar la federación de identidades para cargas de trabajo para GKE.

De forma predeterminada, el servidor de metadatos de GKE devuelve un valor de SERVICEACCOUNT_NAME.svc.id.goog como identificador de la cuenta de servicio para las cuentas de servicio vinculadas. Este identificador no usa la sintaxis del identificador principal de IAM.

Para resolver este error, agrega la anotación iam.gke.io/return-principal-id-as-email="true" a la ServiceAccount de Kubernetes del Pod:

kubectl annotate serviceaccount KSA_NAME \
    --namespace=NAMESPACE \
    iam.gke.io/return-principal-id-as-email="true"

Reemplaza lo siguiente:

  • KSA_NAME: Es el nombre de la ServiceAccount de Kubernetes.
  • NAMESPACE: Es el espacio de nombres de la ServiceAccount.

Se denegó el acceso a la cuenta de servicio de IAM

Es posible que los Pods no puedan acceder a un recurso con Workload Identity Federation for GKE inmediatamente después de agregar vinculaciones de roles de IAM. Es más probable que se produzca un error de acceso en las canalizaciones de implementación o en las configuraciones declarativas de Google Cloud , en las que se crean juntos recursos como políticas de permiso de IAM, vinculaciones de roles y Pods de Kubernetes. En los registros del Pod, aparece el siguiente mensaje de error:

HTTP/403: generic::permission_denied: loading: GenerateAccessToken("SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com", ""): googleapi: Error 403: Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).

Este error puede deberse a la propagación de cambios de acceso en IAM, lo que significa que los cambios de acceso, como las concesiones de roles, tardan en propagarse por el sistema. En el caso de las concesiones de roles, la propagación suele tardar unos dos minutos, pero a veces puede tardar siete minutos o más. Para obtener más detalles, consulta Propagación de cambios de acceso.

Para resolver este error, considera agregar una demora antes de que tus Pods intenten acceder a los recursos de Google Cloud después de crearse.

Problemas con la resolución de DNS

En esta sección, se describe cómo identificar y resolver errores de conexión de Pods a las APIs de Google Cloud que se deben a problemas de resolución de DNS. Si los pasos de esta sección no resuelven los errores de conexión, consulta la sección Errores de tiempo de espera al iniciar el Pod.

Algunas Google Cloud bibliotecas cliente están configuradas para conectarse a los servidores de metadatos de GKE y Compute Engine resolviendo el nombre de DNS metadata.google.internal; para estas bibliotecas, la resolución de DNS en buen estado en el clúster es una dependencia crítica para que tus cargas de trabajo se autentiquen en los servicios deGoogle Cloud .

La detección de este problema depende de los detalles de la aplicación implementada, incluida su configuración de registro. Busca mensajes de error que te indiquen que configures GOOGLE_APPLICATION_CREDENTIALS, que tus solicitudes a un servicio deGoogle Cloud se rechazaron porque la solicitud no tenía credenciales o que no se pudo encontrar el servidor de metadatos.

Por ejemplo, el siguiente mensaje de error podría indicar que hay un problema de resolución de DNS:

ComputeEngineCredentials cannot find the metadata server. This is likely because code is not running on Google Compute Engine

Si tienes problemas con la resolución de DNS de metadata.google.internal, se puede indicar a algunas bibliotecas cliente de Google Cloud que omitan la resolución de DNS estableciendo la variable de entorno GCE_METADATA_HOST en 169.254.169.254:

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
  namespace: default
spec:
  containers:
  - image: debian
    name: main
    command: ["sleep", "infinity"]
    env:
    - name: GCE_METADATA_HOST
      value: "169.254.169.254"

Esta es la dirección IP codificada en la que el servicio de metadatos siempre está disponible en las plataformas de procesamiento de Google Cloud .

Se admiten las siguientes bibliotecas de Google Cloud :

  • Python
  • Java
  • Node.js
  • Golang

    De forma predeterminada, la biblioteca cliente de Go se conecta a través de la dirección IP.

Errores de tiempo de espera en el inicio del Pod

El servidor de metadatos de GKE necesita unos segundos antes de poder comenzar a aceptar solicitudes en un pod nuevo. Los intentos de autenticarse con la federación de identidades para cargas de trabajo para GKE en los primeros segundos de la vida del Pod podrían fallar para aplicaciones y Google Cloud bibliotecas cliente configuradas con un tiempo de espera breve.

Si encuentras errores de tiempo de espera, intenta lo siguiente:

  • Actualiza las Google Cloud bibliotecas cliente que usan tus cargas de trabajo.
  • Cambia el código de la aplicación para que espere unos segundos y vuelve a intentarlo.
  • Implementa un initContainer que espere hasta que el servidor de metadatos de GKE esté listo antes de ejecutar el contenedor principal del Pod.

    Por ejemplo, el siguiente manifiesto es para un pod con un initContainer:

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-with-initcontainer
    spec:
      serviceAccountName: KSA_NAME
      initContainers:
      - image:  gcr.io/google.com/cloudsdktool/cloud-sdk:alpine
        name: workload-identity-initcontainer
        command:
        - '/bin/bash'
        - '-c'
        - |
          curl -sS -H 'Metadata-Flavor: Google' 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token' --retry 30 --retry-connrefused --retry-max-time 60 --connect-timeout 3 --fail --retry-all-errors > /dev/null && exit 0 || echo 'Retry limit exceeded. Failed to wait for metadata server to be available. Check if the gke-metadata-server Pod in the kube-system namespace is healthy.' >&2; exit 1
      containers:
      - image: gcr.io/your-project/your-image
        name: your-main-application-container
    

La federación de identidades para cargas de trabajo para GKE falla debido a la falta de disponibilidad del plano de control

El servidor de metadatos no puede mostrar la federación de identidades para cargas de trabajo para GKE cuando el plano de control del clúster no está disponible. Las llamadas al servidor de metadatos muestran el código de estado 500.

Una entrada de registro puede ser similar a la siguiente en el Explorador de registros:

dial tcp 35.232.136.58:443: connect: connection refused

Este comportamiento genera una falta de disponibilidad de la federación de identidades para cargas de trabajo para GKE.

Es posible que el plano de control no esté disponible en clústeres zonales durante el mantenimiento de los clústeres, como la rotación de las IPs, la actualización de las VMs del plano de control o el cambio de tamaño de clústeres o grupos de nodos. Consulta Elige un plano de control regional o zonal para obtener información sobre la disponibilidad del plano de control. Cambiar a un clúster regional elimina este problema.

La federación de identidades para cargas de trabajo para la autenticación de GKE falla en los clústeres con Istio

Es posible que veas errores similares a los siguientes cuando se inicie tu aplicación y esta intente comunicarse con un extremo:

Connection refused (169.254.169.254:80)
Connection timeout

Estos errores pueden ocurrir cuando tu aplicación intenta establecer una conexión de red antes de que el contenedor istio-proxy esté listo. De forma predeterminada, Istio y Cloud Service Mesh permiten que las cargas de trabajo envíen solicitudes en cuanto se inician, independientemente de si se está ejecutando la carga de trabajo del proxy de malla de servicios que intercepta y redirecciona el tráfico. En el caso de los Pods que usan la federación de identidades para cargas de trabajo para GKE, es posible que estas solicitudes iniciales que se realizan antes de que se inicie el proxy no lleguen al servidor de metadatos de GKE. Como resultado, falla la autenticación en las APIs de Google Cloud . Si no configuras tus aplicaciones para que reintenten las solicitudes, es posible que tus cargas de trabajo fallen.

Para confirmar que este problema es la causa de tus errores, consulta tus registros y verifica si el contenedor istio-proxy se inició correctamente:

  1. En la Google Cloud consola, ve a la página Explorador de registros.

    Ir al Explorador de registros

  2. En el panel de consultas, ingresa la siguiente consulta:

    (resource.type="k8s_container"
    resource.labels.pod_name="POD_NAME"
    textPayload:"Envoy proxy is ready" OR textPayload:"ERROR_MESSAGE")
    OR
    (resource.type="k8s_pod"
    logName:"events"
    jsonPayload.involvedObject.name="POD_NAME")
    

    Reemplaza lo siguiente:

    • POD_NAME: Es el nombre del Pod con la carga de trabajo afectada.
    • ERROR_MESSAGE: Es el error que recibió la aplicación (connection timeout o connection refused).
  3. Haz clic en Ejecutar consulta.

  4. Revisa el resultado y verifica cuándo estuvo listo el contenedor istio-proxy.

    En el siguiente ejemplo, la aplicación intentó realizar una llamada de gRPC. Sin embargo, dado que el contenedor istio-proxy aún se estaba inicializando, la aplicación recibió un error Connection refused. La marca de tiempo junto al mensaje Envoy proxy is ready indica cuándo el contenedor istio-proxy estuvo listo para las solicitudes de conexión:

    2024-11-11T18:37:03Z started container istio-init
    2024-11-11T18:37:12Z started container gcs-fetch
    2024-11-11T18:37:42Z Initializing environment
    2024-11-11T18:37:55Z Started container istio-proxy
    2024-11-11T18:38:06Z StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: Connection refused (169.254.169.254:80)
    2024-11-11T18:38:13Z Envoy proxy is ready
    

Para resolver este problema y evitar que se repita, prueba una de las siguientes opciones de configuración por carga de trabajo:

  • Evita que tus aplicaciones envíen solicitudes hasta que la carga de trabajo del proxy esté lista. Agrega la siguiente anotación al campo metadata.annotations en la especificación del Pod:

    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  • Configura Istio o Cloud Service Mesh para excluir la dirección IP del servidor de metadatos de GKE del redireccionamiento. Agrega la siguiente anotación al campo metadata.annotations de la especificación del Pod:

    traffic.sidecar.istio.io/excludeOutboundIPRanges: 169.254.169.254/32
    

En Istio de código abierto, puedes mitigar este problema para todos los Pods de forma opcional configurando una de las siguientes opciones de configuración global:

  • Excluye la dirección IP del servidor de metadatos de GKE del redireccionamiento: Actualiza la opción de configuración global global.proxy.excludeIPRanges para agregar el rango de direcciones IP 169.254.169.254/32.

  • Evita que las aplicaciones envíen solicitudes hasta que se inicie el proxy: Agrega la opción de configuración global global.proxy.holdApplicationUntilProxyStarts con un valor de true a tu configuración de Istio.

El pod gke-metadata-server falla

El Pod DaemonSet del sistema gke-metadata-server facilita la federación de identidades para cargas de trabajo para GKE en tus nodos. El pod usa recursos de memoria proporcionales a la cantidad de cuentas de servicio de Kubernetes en tu clúster.

El siguiente problema se produce cuando el uso de recursos del pod gke-metadata-server excede sus límites. kubelet expulsa el pod con un error de memoria insuficiente. Es posible que tengas este problema si el clúster tiene más de 3,000 cuentas de servicio de Kubernetes.

Para identificar el problema, haz lo siguiente:

  1. Busca Pods de gke-metadata-server con fallas en el espacio de nombres kube-system:

    kubectl get pods -n=kube-system | grep CrashLoopBackOff
    

    El resultado es similar a este:

    NAMESPACE     NAME                        READY     STATUS             RESTARTS   AGE
    kube-system   gke-metadata-server-8sm2l   0/1       CrashLoopBackOff   194        16h
    kube-system   gke-metadata-server-hfs6l   0/1       CrashLoopBackOff   1369       111d
    kube-system   gke-metadata-server-hvtzn   0/1       CrashLoopBackOff   669        111d
    kube-system   gke-metadata-server-swhbb   0/1       CrashLoopBackOff   30         136m
    kube-system   gke-metadata-server-x4bl4   0/1       CrashLoopBackOff   7          15m
    
  2. Describe el Pod que falla para confirmar que la causa fue una expulsión de memoria insuficiente:

    kubectl describe pod POD_NAME --namespace=kube-system | grep OOMKilled
    

    Reemplaza POD_NAME con el nombre del Pod que deseas verificar.

Para restablecer la funcionalidad en el servidor de metadatos de GKE, reduce la cantidad de cuentas de servicio en el clúster a menos de 3,000.

La federación de identidades para cargas de trabajo para GKE no se pudo habilitar con el mensaje de error de DeployPatch con errores

GKE usa el agente de servicio de Kubernetes Engine administrado por Google Cloudpara facilitar la federación de identidades para cargas de trabajo para GKE en tus clústeres. Google Cloud otorga automáticamente a este agente de servicio el rol de agente de servicio de Kubernetes Engine (roles/container.serviceAgent) en tu proyecto cuando habilitas la API de Google Kubernetes Engine.

Si intentas habilitar la federación de identidades para cargas de trabajo para GKE en clústeres en un proyecto en el que el agente de servicio no tiene el rol de agente de servicio de Kubernetes Engine, la operación falla con un mensaje de error similar al siguiente:

Error waiting for updating GKE cluster workload identity config: DeployPatch failed

Para resolver este problema, realiza las siguientes acciones:

  1. Comprueba si el agente de servicio existe en el proyecto y está configurado de forma correcta:

    gcloud projects get-iam-policy PROJECT_ID \
        --flatten=bindings \
        --filter=bindings.role=roles/container.serviceAgent \
        --format="value[delimiter='\\n'](bindings.members)"
    

    Reemplaza PROJECT_ID por el ID del proyecto Google Cloud.

    Si el agente de servicio está configurado de forma correcta, el resultado muestra la identidad completa del agente de servicio:

    serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
    

    Si el resultado no muestra el agente de servicio, debes otorgarle la función de agente de servicio de Kubernetes Engine. Para otorgar este rol, completa los siguientes pasos.

  2. Obtén tu Google Cloud número de proyecto:

    gcloud projects describe PROJECT_ID \
        --format="value(projectNumber)"
    

    El resultado es similar a este:

    123456789012
    
  3. Otorga el rol al agente de servicio:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com \
        --role=roles/container.serviceAgent \
        --condition=None
    

    Reemplaza PROJECT_NUMBER por el número de tu proyecto Google Cloud.

  4. Vuelve a habilitar la federación de identidades para cargas de trabajo para GKE.

¿Qué sigue?