Résoudre les problèmes liés aux comptes de service dans GKE


Cette page explique comment résoudre les problèmes liés aux comptes de service Google Kubernetes Engine (GKE).

Attribuer le rôle requis pour GKE aux comptes de service de nœud

Les comptes de service IAM utilisés par vos nœuds GKE doivent disposer de toutes les autorisations incluses dans le rôle IAM Compte de service de nœud par défaut Kubernetes Engine (roles/container.defaultNodeServiceAccount). Si un compte de service de nœud GKE ne dispose pas d'une ou de plusieurs de ces autorisations, GKE ne peut pas effectuer les tâches système suivantes:

Il est possible que les comptes de service de nœud ne disposent pas de certaines autorisations requises pour des raisons telles que les suivantes:

Si les autorisations requises par GKE ne sont pas accordées à votre compte de service de nœud, des erreurs et des notifications semblables aux suivantes peuvent s'afficher:

  • Dans la console Google Cloud , sur la page Clusters Kubernetes, un message d'erreur Accorder des autorisations critiques s'affiche dans la colonne Notifications pour un cluster spécifique.
  • Dans la console Google Cloud , sur la page des détails d'un cluster spécifique, le message d'erreur suivant s'affiche:

    Grant roles/container.defaultNodeServiceAccount role to Node service account to allow for non-degraded operations.
    
  • Dans Cloud Audit Logs, les journaux des activités d'administration pour les API Google Cloud telles que monitoring.googleapis.com ont les valeurs suivantes si les autorisations correspondantes pour accéder à ces API sont manquantes dans le compte de service du nœud:

    • Gravité : ERROR
    • Message : Permission denied (or the resource may not exist)
  • Les journaux de nœuds spécifiques sont manquants dans Cloud Logging, et les journaux de pod pour l'agent de journalisation sur ces nœuds affichent des erreurs 401. Pour obtenir ces journaux de pod, exécutez la commande suivante:

    [[ $(kubectl logs -l k8s-app=fluentbit-gke -n kube-system -c fluentbit-gke | grep -cw "Received 401") -gt 0 ]] && echo "true" || echo "false"
    

    Si la sortie est true, la charge de travail du système rencontre des erreurs 401, ce qui indique un manque d'autorisations.

Pour résoudre ce problème, accordez le rôle de compte de service de nœud par défaut Kubernetes Engine (roles/container.defaultNodeServiceAccount) au projet au compte de service à l'origine des erreurs. Sélectionnez l'une des options suivantes :

Console

Pour trouver le nom du compte de service utilisé par vos nœuds, procédez comme suit:

  1. Accédez à la page Clusters Kubernetes:

    Accéder à la page "Clusters Kubernetes"

  2. Dans la liste des clusters, cliquez sur le nom du cluster que vous souhaitez inspecter.

  3. Recherchez le nom du compte de service de nœud. Vous aurez besoin de ce nom ultérieurement.

    • Pour les clusters en mode Autopilot, dans la section Sécurité, recherchez le champ Compte de service.
    • Pour les clusters en mode Standard, procédez comme suit:
    1. Cliquez sur l'onglet Nœuds.
    2. Dans le tableau Pools de nœuds, cliquez sur le nom d'un pool de nœuds. La page Détails du pool de nœuds s'affiche.
    3. Dans la section Sécurité, recherchez le champ Compte de service.

    Si la valeur du champ Compte de service est default, vos nœuds utilisent le compte de service Compute Engine par défaut. Si la valeur de ce champ n'est pas default, vos nœuds utilisent un compte de service personnalisé.

Pour attribuer le rôle Kubernetes Engine Default Node Service Account au compte de service, procédez comme suit:

  1. Accédez à la page Bienvenue:

    Accéder à la page d'accueil

  2. Dans le champ Numéro du projet, cliquez sur Copier dans le presse-papiers.

  3. Accédez à la page IAM :

    Accéder à IAM

  4. Cliquez sur Accorder l'accès.

  5. Dans le champ Nouveaux comptes principaux, spécifiez le nom de votre compte de service de nœud. Si vos nœuds utilisent le compte de service Compute Engine par défaut, spécifiez la valeur suivante:

    PROJECT_NUMBER[email protected]
    

    Remplacez PROJECT_NUMBER par le numéro de projet que vous avez copié.

  6. Dans le menu Sélectionner un rôle, sélectionnez le rôle Compte de service de nœud par défaut Kubernetes Engine.

  7. Cliquez sur Enregistrer.

Pour vérifier que le rôle a été attribué, procédez comme suit:

  1. Sur la page IAM, cliquez sur l'onglet Afficher par rôle.
  2. Développez la section Compte de service de nœud par défaut Kubernetes Engine. La liste des comptes principaux disposant de ce rôle s'affiche.
  3. Recherchez votre compte de service de nœud dans la liste des comptes principaux.

gcloud

  1. Recherchez le nom du compte de service utilisé par vos nœuds:

    • Pour les clusters en mode Autopilot, exécutez la commande suivante:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --flatten=autoscaling.autoprovisioningNodePoolDefaults.serviceAccount
    
    • Pour les clusters en mode Standard, exécutez la commande suivante:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="table(nodePools.name,nodePools.config.serviceAccount)"
    

    Si la sortie est default, vos nœuds utilisent le compte de service Compute Engine par défaut. Si la sortie n'est pas default, vos nœuds utilisent un compte de service personnalisé.

  2. Recherchez le numéro de votre Google Cloud projet:

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

    Remplacez PROJECT_ID par l'ID du projet.

    Le résultat ressemble à ce qui suit :

    12345678901
    
  3. Attribuez le rôle roles/container.defaultNodeServiceAccount au compte de service:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member="SERVICE_ACCOUNT_NAME" \
        --role="roles/container.defaultNodeServiceAccount"
    

    Remplacez SERVICE_ACCOUNT_NAME par le nom du compte de service que vous avez trouvé à l'étape précédente. Si vos nœuds utilisent le compte de service Compute Engine par défaut, spécifiez la valeur suivante:

    serviceAccount:PROJECT_NUMBER[email protected]
    

    Remplacez PROJECT_NUMBER par le numéro de projet de l'étape précédente.

  4. Vérifiez que le rôle a bien été attribué:

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

    La sortie indique le nom de votre compte de service.

Identifier les comptes de service de nœud qui ne disposent pas des autorisations requises

Les sections suivantes décrivent comment identifier les comptes de service de nœud qui ne disposent pas des autorisations requises pour GKE.

Identifier les clusters dont les comptes de service de nœud ne disposent pas des autorisations nécessaires

Utilisez les recommandations GKE du sous-type de recommandateur NODE_SA_MISSING_PERMISSIONS pour identifier les clusters Autopilot et standards dont les comptes de service de nœuds ne disposent pas d'autorisations. Le recommender n'identifie que les clusters créés à compter du 1er janvier 2024. Pour rechercher et corriger les autorisations manquantes à l'aide de l'outil de recommandation, procédez comme suit:

  1. Recherchez les recommandations actives dans votre projet pour le sous-type de recommandateur NODE_SA_MISSING_PERMISSIONS:

    gcloud recommender recommendations list \
        --recommender=google.container.DiagnosisRecommender \
        --location LOCATION \
        --project PROJECT_ID \
        --format yaml \
        --filter="recommenderSubtype:NODE_SA_MISSING_PERMISSIONS"
    

    Remplacez les éléments suivants :

    • LOCATION: emplacement dans lequel trouver des recommandations.
    • PROJECT_ID: ID de votre Google Cloud projet.

    Le résultat ressemble à ce qui suit, ce qui indique qu'un cluster dispose d'un compte de service de nœud dont les autorisations sont manquantes:

    associatedInsights:
    # lines omitted for clarity
    recommenderSubtype: NODE_SA_MISSING_PERMISSIONS
    stateInfo:
      state: ACTIVE
    targetResources:
    - //container.googleapis.com/projects/12345678901/locations/us-central1/clusters/cluster-1
    

    L'affichage de la recommandation peut prendre jusqu'à 24 heures. Pour obtenir des instructions détaillées, consultez la section Afficher les insights et les recommandations.

  2. Pour chaque cluster figurant dans la sortie de l'étape précédente, recherchez les comptes de service de nœud associés et accordez-leur le rôle requis. Pour en savoir plus, consultez les instructions de la section Attribuer le rôle requis aux comptes de service de nœud pour GKE.

    Une fois que vous avez attribué le rôle requis aux comptes de service de nœud identifiés, la recommandation peut persister jusqu'à 24 heures, sauf si vous la fermez manuellement.

Identifier tous les comptes de service de nœud dont les autorisations sont manquantes

Vous pouvez exécuter un script qui recherche dans les pools de nœuds des clusters Standard et Autopilot de votre projet tous les comptes de service de nœuds qui ne disposent pas des autorisations requises pour GKE. Ce script utilise gcloud CLI et l'utilitaire jq. Pour afficher le script, développez la section suivante:

Afficher le script

#!/bin/bash

# Set your project ID
project_id=PROJECT_ID
project_number=$(gcloud projects describe "$project_id" --format="value(projectNumber)")
declare -a all_service_accounts
declare -a sa_missing_permissions

# Function to check if a service account has a specific permission
# $1: project_id
# $2: service_account
# $3: permission
service_account_has_permission() {
  local project_id="$1"
  local service_account="$2"
  local permission="$3"

  local roles=$(gcloud projects get-iam-policy "$project_id" \
          --flatten="bindings[].members" \
          --format="table[no-heading](bindings.role)" \
          --filter="bindings.members:\"$service_account\"")

  for role in $roles; do
    if role_has_permission "$role" "$permission"; then
      echo "Yes" # Has permission
      return
    fi
  done

  echo "No" # Does not have permission
}

# Function to check if a role has the specific permission
# $1: role
# $2: permission
role_has_permission() {
  local role="$1"
  local permission="$2"
  gcloud iam roles describe "$role" --format="json" | \
  jq -r ".includedPermissions" | \
  grep -q "$permission"
}

# Function to add $1 into the service account array all_service_accounts
# $1: service account
add_service_account() {
  local service_account="$1"
  all_service_accounts+=( ${service_account} )
}

# Function to add service accounts into the global array all_service_accounts for a Standard GKE cluster
# $1: project_id
# $2: location
# $3: cluster_name
add_service_accounts_for_standard() {
  local project_id="$1"
  local cluster_location="$2"
  local cluster_name="$3"

  while read nodepool; do
    nodepool_name=$(echo "$nodepool" | awk '{print $1}')
    if [[ "$nodepool_name" == "" ]]; then
      # skip the empty line which is from running `gcloud container node-pools list` in GCP console
      continue
    fi
    while read nodepool_details; do
      service_account=$(echo "$nodepool_details" | awk '{print $1}')

      if [[ "$service_account" == "default" ]]; then
        service_account="${project_number}[email protected]"
      fi
      if [[ -n "$service_account" ]]; then
        printf "%-60s| %-40s| %-40s| %-10s| %-20s\n" $service_account $project_id  $cluster_name $cluster_location $nodepool_name
        add_service_account "${service_account}"
      else
        echo "cannot find service account for node pool $project_id\t$cluster_name\t$cluster_location\t$nodepool_details"
      fi
    done <<< "$(gcloud container node-pools describe "$nodepool_name" --cluster "$cluster_name" --zone "$cluster_location" --project "$project_id" --format="table[no-heading](config.serviceAccount)")"
  done <<< "$(gcloud container node-pools list --cluster "$cluster_name" --zone "$cluster_location" --project "$project_id" --format="table[no-heading](name)")"

}

# Function to add service accounts into the global array all_service_accounts for an Autopilot GKE cluster
# Autopilot cluster only has one node service account.
# $1: project_id
# $2: location
# $3: cluster_name
add_service_account_for_autopilot(){
  local project_id="$1"
  local cluster_location="$2"
  local cluster_name="$3"

  while read service_account; do
      if [[ "$service_account" == "default" ]]; then
        service_account="${project_number}[email protected]"
      fi
      if [[ -n "$service_account" ]]; then
        printf "%-60s| %-40s| %-40s| %-10s| %-20s\n" $service_account $project_id  $cluster_name $cluster_location $nodepool_name
        add_service_account "${service_account}"
      else
        echo "cannot find service account" for cluster  "$project_id\t$cluster_name\t$cluster_location\t"
      fi
  done <<< "$(gcloud container clusters describe "$cluster_name" --location "$cluster_location" --project "$project_id" --format="table[no-heading](autoscaling.autoprovisioningNodePoolDefaults.serviceAccount)")"
}


# Function to check whether the cluster is an Autopilot cluster or not
# $1: project_id
# $2: location
# $3: cluster_name
is_autopilot_cluster() {
  local project_id="$1"
  local cluster_location="$2"
  local cluster_name="$3"
  autopilot=$(gcloud container clusters describe "$cluster_name" --location "$cluster_location" --format="table[no-heading](autopilot.enabled)")
  echo "$autopilot"
}


echo "--- 1. List all service accounts in all GKE node pools"
printf "%-60s| %-40s| %-40s| %-10s| %-20s\n" "service_account" "project_id" "cluster_name" "cluster_location" "nodepool_name"
while read cluster; do
  cluster_name=$(echo "$cluster" | awk '{print $1}')
  cluster_location=$(echo "$cluster" | awk '{print $2}')
  # how to find a cluster is a Standard cluster or an Autopilot cluster
  autopilot=$(is_autopilot_cluster "$project_id" "$cluster_location" "$cluster_name")
  if [[ "$autopilot" == "True" ]]; then
    add_service_account_for_autopilot "$project_id" "$cluster_location"  "$cluster_name"
  else
    add_service_accounts_for_standard "$project_id" "$cluster_location"  "$cluster_name"
  fi
done <<< "$(gcloud container clusters list --project "$project_id" --format="value(name,location)")"

echo "--- 2. Check if service accounts have permissions"
unique_service_accounts=($(echo "${all_service_accounts[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))

echo "Service accounts: ${unique_service_accounts[@]}"
printf "%-60s| %-40s| %-40s| %-20s\n" "service_account" "has_logging_permission" "has_monitoring_permission" "has_performance_hpa_metric_write_permission"
for sa in "${unique_service_accounts[@]}"; do
  logging_permission=$(service_account_has_permission "$project_id" "$sa" "logging.logEntries.create")
  time_series_create_permission=$(service_account_has_permission "$project_id" "$sa" "monitoring.timeSeries.create")
  metric_descriptors_create_permission=$(service_account_has_permission "$project_id" "$sa" "monitoring.metricDescriptors.create")
  if [[ "$time_series_create_permission" == "No" || "$metric_descriptors_create_permission" == "No" ]]; then
    monitoring_permission="No"
  else
    monitoring_permission="Yes"
  fi
  performance_hpa_metric_write_permission=$(service_account_has_permission "$project_id" "$sa" "autoscaling.sites.writeMetrics")
  printf "%-60s| %-40s| %-40s| %-20s\n" $sa $logging_permission $monitoring_permission $performance_hpa_metric_write_permission

  if [[ "$logging_permission" == "No" || "$monitoring_permission" == "No" || "$performance_hpa_metric_write_permission" == "No" ]]; then
    sa_missing_permissions+=( ${sa} )
  fi
done

echo "--- 3. List all service accounts that don't have the above permissions"
if [[ "${#sa_missing_permissions[@]}" -gt 0 ]]; then
  printf "Grant roles/container.defaultNodeServiceAccount to the following service accounts: %s\n" "${sa_missing_permissions[@]}"
else
  echo "All service accounts have the above permissions"
fi

Ce script s'applique à tous les clusters GKE de votre projet.

Après avoir identifié les noms des comptes de service dont les autorisations sont manquantes, attribuez-leur le rôle requis. Pour en savoir plus, consultez les instructions de la section Attribuer aux comptes de service de nœud le rôle requis pour GKE.

Restaurer le compte de service par défaut sur votre Google Cloud projet

Le compte de service par défaut de GKE, container-engine-robot, peut être dissocié accidentellement d'un projet. Le rôle d'agent de service Kubernetes Engine (roles/container.serviceAgent) est un rôle Identity and Access Management (IAM) qui accorde au compte de service les autorisations nécessaires pour gérer les ressources du cluster. Si vous supprimez cette liaison de rôle du compte de service, le compte de service par défaut est dissocié du projet, ce qui peut vous empêcher de déployer des applications et d'effectuer d'autres opérations sur le cluster.

Pour vérifier si le compte de service a été supprimé de votre projet, vous pouvez utiliser la console Google Cloud ou Google Cloud CLI.

Console

gcloud

  • Exécutez la commande suivante :

    gcloud projects get-iam-policy PROJECT_ID
    

    Remplacez PROJECT_ID par l'ID du projet.

Si le tableau de bord ou la commande n'affiche pas container-engine-robot parmi vos comptes de service, le rôle est dissocié.

Pour restaurer la liaison du rôle d'agent de service Kubernetes Engine (roles/container.serviceAgent), exécutez les commandes suivantes :

PROJECT_NUMBER=$(gcloud projects describe "PROJECT_ID" \
    --format 'get(projectNumber)') \
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:service-${PROJECT_NUMBER?}@container-engine-robot.iam.gserviceaccount.com" \
    --role roles/container.serviceAgent

Vérifiez que la liaison de rôle est restaurée :

gcloud projects get-iam-policy $PROJECT_ID

Si vous voyez le nom du compte de service avec le rôle container.serviceAgent, la liaison de rôle est restaurée. Par exemple :

- members:
  - serviceAccount:service-1234567890@container-engine-robot.iam.gserviceaccount.com
  role: roles/container.serviceAgent

Activer le compte de service Compute Engine par défaut

Le compte de service utilisé pour le pool de nœuds est généralement le compte de service Compute Engine par défaut. Si ce compte de service par défaut est désactivé, vos nœuds risquent de ne pas s'enregistrer auprès du cluster.

Pour vérifier si le compte de service est désactivé dans votre projet, vous pouvez utiliser la consoleGoogle Cloud ou gcloud CLI.

Console

gcloud

  • Exécutez la commande suivante :
gcloud iam service-accounts list  --filter="NAME~'compute' AND disabled=true"

Si le compte de service est désactivé, exécutez la commande suivante pour l'activer :

gcloud iam service-accounts enable PROJECT_ID[email protected]

Remplacez PROJECT_ID par l'ID du projet.

Pour en savoir plus, consultez Résoudre les problèmes d'enregistrement de nœuds.

Erreur 400/403 : le compte n'est pas autorisé à apporter des modifications

Si votre compte de service est supprimé, une erreur d'autorisation de modification peut s'afficher. Pour savoir comment résoudre ce problème, consultez Erreur 400/403 : le compte n'est pas autorisé à apporter des modifications.

Étapes suivantes