Résoudre les problèmes d'authentification de GKE


Cette page explique comment résoudre les problèmes liés aux configurations de sécurité dans vos clusters Google Kubernetes Engine (GKE) Autopilot et Standard.

Si vous avez besoin d'une aide supplémentaire, contactez Cloud Customer Care.

RBAC et IAM

Les comptes IAM authentifiés ne parviennent pas à effectuer des actions dans le cluster

Le problème suivant se produit lorsque vous essayez d'effectuer une action dans le cluster, mais que GKE ne trouve pas de stratégie RBAC autorisant cette action. GKE tente de trouver une stratégie d'autorisation IAM qui accorde la même autorisation. Si cette opération échoue, un message d'erreur semblable à celui-ci s'affiche :

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).

Pour résoudre ce problème, utilisez une stratégie RBAC afin d'accorder les autorisations pour l'action tentée. Par exemple, pour résoudre le problème dans l'exemple précédent, attribuez un rôle disposant de l'autorisation list sur les objets roles de l'espace de noms kube-system. Pour obtenir des instructions, consultez la page Autoriser les actions dans les clusters à l'aide du contrôle des accès basé sur les rôles.

Workload Identity Federation for GKE

Le pod ne peut pas s'authentifier auprès de Google Cloud

Si votre application ne peut pas s'authentifier auprès de Google Cloud, assurez-vous que les paramètres suivants sont correctement configurés:

  1. Assurez-vous d'avoir activé l'API IAM Service Account Credentials dans le projet contenant le cluster GKE.

    Activer l'API des identifiants IAM

  2. Vérifiez que la fédération d'identité de charge de travail pour GKE est activée sur le cluster en vérifiant qu'un pool d'identités de charge de travail est défini :

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

    Remplacez CLUSTER_NAME par le nom de votre cluster GKE.

    Si vous n'avez pas encore spécifié une zone ou une région par défaut pour gcloud, vous devrez peut-être également spécifier une option --region ou --zone lors de l'exécution de cette commande.

  3. Assurez-vous que le serveur de métadonnées GKE est configuré sur le pool de nœuds dans lequel votre application s'exécute :

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

    Remplacez les éléments suivants :

    • NODEPOOL_NAME par le nom de votre pool de nœuds.
    • CLUSTER_NAME par le nom de votre cluster GKE.
  4. Assurez-vous que le compte de service Kubernetes est correctement annoté :

    kubectl describe serviceaccount \
        --namespace NAMESPACE KSA_NAME
    

    Remplacez les éléments suivants :

    • NAMESPACE par l'espace de noms de votre cluster GKE.
    • KSA par le nom de votre compte de service Kubernetes.

    Le résultat attendu contient une annotation semblable à celle-ci :

    iam.gke.io/gcp-service-account: GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
    
  5. Vérifiez que le compte de service IAM est correctement configuré :

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

    Le résultat attendu contient une liaison semblable à celle-ci :

    - members:
      - serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]
      role: roles/iam.workloadIdentityUser
    
  6. Si vous disposez d'une règle de réseau de cluster, vous devez autoriser la sortie vers 127.0.0.1/32 sur le port 988 pour les clusters exécutant des versions GKE antérieures à 1.21.0-gke.1000, ou 169.254.169.252/32 sur le port 988 pour les clusters exécutant une version GKE 1.21.0-gke.1000 ou ultérieure. Pour les clusters exécutant GKE Dataplane V2, vous devez autoriser la sortie vers 169.254.169.254/32 sur le port 80.

    kubectl describe networkpolicy NETWORK_POLICY_NAME
    

    Remplacez NETWORK_POLICY_NAME par le nom de votre règle de réseau GKE.

Accès au compte de service IAM refusé

Il est possible que les pods ne parviennent pas à accéder à une ressource avec la fédération d'identité de charge de travail pour GKE immédiatement après avoir ajouté des liaisons de rôle IAM. L'échec de l'accès est plus susceptible de se produire dans les pipelines de déploiement ou dans les configurations déclaratives où des ressources telles que les stratégies d'autorisation IAM, les liaisons de rôle et les pods Kubernetes sont créées ensemble. Google Cloud Le message d'erreur suivant s'affiche dans les journaux du pod:

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).

Cette erreur peut être due à la propagation des modifications d'accès dans IAM, ce qui signifie que la propagation des modifications d'accès telles que les autorisations de rôle prend du temps dans le système. Pour les autorisations de rôle, la propagation prend généralement environ deux minutes, mais peut parfois prendre sept minutes ou plus. Pour en savoir plus, consultez la page Propagation des modifications d'accès.

Pour résoudre cette erreur, envisagez d'ajouter un délai avant que vos pods ne tentent d'accéder aux ressources Google Cloud après leur création.

Problèmes de résolution DNS

Certaines bibliothèques clientes Google Cloud sont configurées pour se connecter aux serveurs de métadonnées GKE et Compute Engine en résolvant le nom DNS metadata.google.internal. Pour ces bibliothèques, la résolution DNS opérationnelle interne au cluster est une dépendance critique pour que vos charges de travail s'authentifient auprès des servicesGoogle Cloud .

La méthode de détection de ce problème dépend des détails de votre application déployée, y compris la configuration de sa journalisation. Recherchez les messages d'erreur qui :

  • vous indiquent de configurer GOOGLE_APPLICATION_CREDENTIALS ; ou
  • vous indiquent que vos requêtes adressées à un service Google Cloud ont été refusées du fait que la requête ne contenait pas d'identifiants.

Si vous rencontrez des problèmes avec la résolution DNS de metadata.google.internal, certaines bibliothèques clientes Google Cloud peuvent être invitées à ignorer la résolution DNS en définissant la variable d'environnement GCE_METADATA_HOST sur 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"

Il s'agit de l'adresse IP codée en dur sur laquelle le service de métadonnées est toujours disponible sur les plates-formes de calcul Google Cloud .

Bibliothèques Google Cloud compatibles:

  • Python
  • Java
  • Node.js
  • Golang (Notez cependant que la bibliothèque cliente Golang préfère déjà se connecter par adresse IP plutôt que par nom DNS.)

Erreurs d'expiration au démarrage du pod

Le serveur de métadonnées GKE a besoin de quelques secondes pour pouvoir commencer à accepter des requêtes sur un nouveau pod. Les tentatives d'authentification à l'aide de la fédération d'identité de charge de travail pour GKE dans les premières secondes de la vie d'un pod peuvent échouer pour les applications et les bibliothèques clientes Google Cloud configurées avec un délai avant expiration court.

Si vous rencontrez des erreurs d'expiration de délai, procédez comme suit :

  • Mettez à jour les bibliothèques clientes Google Cloud utilisées par vos charges de travail.
  • Modifiez le code d'application pendant quelques secondes, puis réessayez.
  • Déployez un conteneur initContainer qui attend que le serveur de métadonnées GKE soit prêt avant d'exécuter le conteneur principal du pod.

    Par exemple, le fichier manifeste suivant concerne un pod avec un conteneur 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
    

Échec de la fédération d'identité de charge de travail pour GKE en raison de l'indisponibilité du plan de contrôle

Le serveur de métadonnées ne peut pas renvoyer la fédération d'identité de charge de travail pour GKE lorsque le plan de contrôle du cluster n'est pas disponible. Les appels au serveur de métadonnées renvoient le code d'état 500.

Une entrée de journal peut ressembler à l'exemple suivant dans l'explorateur de journaux :

dial tcp 35.232.136.58:443: connect: connection refused

Ce comportement entraîne une indisponibilité de la fédération d'identité de charge de travail pour GKE.

Le plan de contrôle peut être indisponible sur les clusters zonaux pendant les opérations de maintenance du cluster, telles que le renouvellement des adresses IP, la mise à niveau des VM du plan de contrôle, ou le redimensionnement des clusters ou des pools de nœuds. Pour en savoir plus sur la disponibilité du plan de contrôle, consultez la page Choisir un plan de contrôle régional ou zonal. Le passage à un cluster régional élimine ce problème.

Échec de l'authentification de la fédération d'identité de charge de travail pour GKE dans les clusters utilisant Istio

Des erreurs semblables à celles-ci peuvent s'afficher lorsque votre application démarre et tente de communiquer avec un point de terminaison:

Connection refused (169.254.169.254:80)
Connection timeout

Ces erreurs peuvent se produire lorsque votre application tente d'établir une connexion réseau avant que le conteneur istio-proxy ne soit prêt. Par défaut, Istio et Cloud Service Mesh autorisent les charges de travail à envoyer des requêtes dès qu'elles démarrent, que la charge de travail du proxy de service mesh qui intercepte et redirige le trafic soit en cours d'exécution ou non. Pour les pods qui utilisent la fédération d'identité de charge de travail pour GKE, ces requêtes initiales qui se produisent avant le démarrage du proxy peuvent ne pas atteindre le serveur de métadonnées GKE. Par conséquent, l'authentification aux API Google Cloud échoue. Si vous ne configurez pas vos applications pour qu'elles relancent les requêtes, vos charges de travail risquent d'échouer.

Pour vérifier que ce problème est bien à l'origine de vos erreurs, consultez vos journaux et vérifiez si le conteneur istio-proxy a démarré correctement:

  1. Dans Google Cloud Console, accédez à la page Explorateur de journaux.

    Accéder à l'explorateur de journaux

  2. Dans le volet de requête, saisissez la requête suivante:

    (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")
    

    Remplacez les éléments suivants :

    • POD_NAME: nom du pod avec la charge de travail affectée.
    • ERROR_MESSAGE: erreur reçue par l'application (connection timeout ou connection refused).
  3. Cliquez sur Exécuter la requête.

  4. Examinez la sortie et vérifiez quand le conteneur istio-proxy est devenu prêt.

    Dans l'exemple suivant, l'application a tenté d'effectuer un appel gRPC. Toutefois, comme le conteneur istio-proxy était toujours en cours d'initialisation, l'application a reçu une erreur Connection refused. Le code temporel à côté du message Envoy proxy is ready indique à quel moment le conteneur istio-proxy est devenu prêt à recevoir des requêtes de connexion:

    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
    

Pour résoudre ce problème et l'empêcher de se reproduire, essayez l'une des options de configuration par charge de travail suivantes:

  • Empêchez vos applications d'envoyer des requêtes tant que la charge de travail du proxy n'est pas prête. Ajoutez l'annotation suivante au champ metadata.annotations dans la spécification de votre pod:

    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  • Configurez Istio ou Cloud Service Mesh pour exclure l'adresse IP du serveur de métadonnées GKE de la redirection. Ajoutez l'annotation suivante au champ metadata.annotations de la spécification de votre pod:

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

Dans Istio Open Source, vous pouvez atténuer ce problème pour tous les pods en définissant l'une des options de configuration globales suivantes:

  • Exclure l'adresse IP du serveur de métadonnées GKE de la redirection : modifiez l'option de configuration globale global.proxy.excludeIPRanges pour ajouter la plage d'adresses IP 169.254.169.254/32.

  • Empêcher les applications d'envoyer des requêtes jusqu'au démarrage du proxy : ajoutez l'option de configuration globale global.proxy.holdApplicationUntilProxyStarts avec une valeur de true à votre configuration Istio.

Plantage du pod gke-metadata-server

Le pod DaemonSet système gke-metadata-server facilite la fédération d'identité de charge de travail pour GKE sur vos nœuds. Le pod utilise des ressources de mémoire proportionnellement au nombre de comptes de service Kubernetes dans votre cluster.

Le problème suivant se produit lorsque l'utilisation des ressources du pod gke-metadata-server dépasse ses limites. Le kubelet supprime le pod avec une erreur de mémoire insuffisante. Vous pouvez rencontrer ce problème si votre cluster possède plus de 3 000 comptes de service Kubernetes.

Pour identifier le problème, procédez comme suit :

  1. Recherchez les pods gke-metadata-server qui plantent dans l'espace de noms kube-system :

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

    Le résultat ressemble à ce qui suit :

    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. Décrivez le pod qui plante pour vérifier que la cause était une suppression avec mémoire insuffisante :

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

    Remplacez POD_NAME par le nom du pod à vérifier.

Pour restaurer la fonctionnalité du serveur de métadonnées GKE, réduisez le nombre de comptes de service de votre cluster à moins de 3 000.

L'activation de la fédération d'identité de charge de travail pour GKE échoue avec le message d'erreur "DeployPatch failed"

GKE utilise l'agent de service Kubernetes Engine géré par Google Cloudpour faciliter la fédération d'identité de charge de travail pour GKE dans vos clusters. Google Cloud attribue automatiquement à cet agent de service le rôle d'agent de service Kubernetes Engine (roles/container.serviceAgent) sur votre projet lorsque vous activez l'API Google Kubernetes Engine.

Si vous essayez d'activer la fédération d'identité de charge de travail pour GKE sur des clusters dans un projet où l'agent de service ne dispose pas du rôle d'agent de service Kubernetes Engine, l'opération échoue avec un message d'erreur semblable à celui-ci :

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

Essayez les solutions suivantes pour résoudre ce problème :

  1. Vérifiez si l'agent de service existe dans votre projet et s'il est configuré correctement :

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

    Remplacez PROJECT_ID par l'ID de votre Google Cloudprojet.

    Si l'agent de service est correctement configuré, le résultat affiche l'identité complète de l'agent de service :

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

    Si le résultat n'affiche pas l'agent de service, vous devez lui attribuer le rôle d'agent de service Kubernetes Engine. Pour accorder ce rôle, suivez la procédure suivante.

  2. Obtenez votre numéro de projet Google Cloud :

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

    Le résultat ressemble à ce qui suit :

    123456789012
    
  3. Attribuez le rôle à l'agent de service :

    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
    

    Remplacez PROJECT_NUMBER par votre numéro de projet Google Cloud.

  4. Essayez d'activer à nouveau la fédération d'identité de charge de travail pour GKE.

Étapes suivantes

Si vous avez besoin d'une aide supplémentaire, contactez Cloud Customer Care.