Risolvere i problemi relativi agli account di servizio in GKE


Questa pagina mostra come risolvere i problemi relativi agli account servizio di Google Kubernetes Engine (GKE).

Concedi il ruolo richiesto per GKE agli account di servizio dei nodi

I service account IAM utilizzati dai tuoi nodi GKE devono avere tutte le autorizzazioni incluse nel ruolo IAM Kubernetes Engine Default Node Service Account (roles/container.defaultNodeServiceAccount). Se un account di servizio del nodo GKE non dispone di una o più di queste autorizzazioni, GKE non può eseguire attività di sistema come le seguenti:

Gli account di servizio dei nodi potrebbero non disporre di alcune autorizzazioni richieste per motivi come i seguenti:

Se nell'account di servizio del tuo nodo mancano le autorizzazioni richieste da GKE, potresti visualizzare errori e avvisi come i seguenti:

  • Nella Google Cloud console, nella pagina Cluster Kubernetes, un messaggio di errore Concede autorizzazioni critiche viene visualizzato nella colonna Notifiche per un cluster specifico.
  • Nella Google Cloud console, nella pagina dei dettagli di un cluster specifico, viene visualizzato il seguente messaggio di errore:

    Grant roles/container.defaultNodeServiceAccount role to Node service account to allow for non-degraded operations.
    
  • In Audit log di Cloud, gli audit log Attività di amministrazione per Google Cloud API come monitoring.googleapis.com hanno i seguenti valori se le autorizzazioni corrispondenti per accedere a queste API non sono presenti nell'account di servizio del nodo:

    • Gravità: ERROR
    • Messaggio: Permission denied (or the resource may not exist)
  • I log per nodi specifici non sono presenti in Cloud Logging e i log dei pod per l'agente di logging su questi nodi mostrano errori 401. Per ottenere questi log del pod, esegui il seguente comando:

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

    Se l'output è true, significa che il carico di lavoro del sistema presenta errori 401, che indicano una mancanza di autorizzazioni.

Per risolvere il problema, concedi al service account che causa gli errori il ruolo Kubernetes Engine Default Node Service Account (roles/container.defaultNodeServiceAccount) nel progetto. Seleziona una delle seguenti opzioni:

console

Per trovare il nome dell'account di servizio utilizzato dai tuoi nodi:

  1. Vai alla pagina Cluster Kubernetes:

    Vai ai cluster Kubernetes

  2. Nell'elenco dei cluster, fai clic sul nome del cluster che vuoi controllare.

  3. Trova il nome dell'account di servizio del nodo. Ti servirà in un secondo momento.

    • Per i cluster in modalità Autopilot, nella sezione Sicurezza, trovate il campo Service account.
    • Per i cluster in modalità standard:
    1. Fai clic sulla scheda Nodi.
    2. Nella tabella Pool di nodi, fai clic sul nome di un pool di nodi. Viene visualizzata la pagina Dettagli del pool di nodi.
    3. Nella sezione Sicurezza, individua il campo Account di servizio.

    Se il valore nel campo Service account è default, i nodi utilizzano l'account di servizio predefinito di Compute Engine. Se il valore in questo campo non è default, i tuoi nodi utilizzano un account di servizio personalizzato.

Per concedere il ruolo Kubernetes Engine Default Node Service Account all'account di servizio:

  1. Vai alla pagina Welcome (Ti diamo il benvenuto):

    Vai a Benvenuto

  2. Nel campo Numero progetto, fai clic su Copia negli appunti.

  3. Vai alla pagina IAM:

    Vai a IAM

  4. Fai clic su Concedi l'accesso.

  5. Nel campo Nuove entità, specifica il nome dell'account di servizio del tuo node. Se i nodi utilizzano l'account di servizio Compute Engine predefinito, specifica il seguente valore:

    PROJECT_NUMBER[email protected]
    

    Sostituisci PROJECT_NUMBER con il numero del progetto che hai copiato.

  6. Nel menu Seleziona un ruolo, seleziona il ruolo Kubernetes Engine Default Node Service Account.

  7. Fai clic su Salva.

Per verificare che il ruolo sia stato concesso:

  1. Nella pagina IAM, fai clic sulla scheda Visualizza per ruoli.
  2. Espandi la sezione Kubernetes Engine Default Node Service Account. Viene visualizzato un elenco di entità che dispongono di questo ruolo.
  3. Trova l'account di servizio del tuo nodo nell'elenco delle entità.

gcloud

  1. Trova il nome dell'account di servizio utilizzato dai tuoi nodi:

    • Per i cluster in modalità Autopilot, esegui il seguente comando:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --flatten=autoscaling.autoprovisioningNodePoolDefaults.serviceAccount
    
    • Per i cluster in modalità standard, esegui il seguente comando:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="table(nodePools.name,nodePools.config.serviceAccount)"
    

    Se l'output è default, i nodi utilizzano il account di servizio predefinito di Compute Engine. Se l'output non è default, i tuoi nodi utilizzano un account di servizio personalizzato.

  2. Trova il Google Cloud numero del progetto:

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

    Sostituisci PROJECT_ID con l'ID progetto.

    L'output è simile al seguente:

    12345678901
    
  3. Concedi il ruolo roles/container.defaultNodeServiceAccount all'account di servizio:

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

    Sostituisci SERVICE_ACCOUNT_NAME con il nome dell'account di servizio che hai trovato nel passaggio precedente. Se i tuoi nodi utilizzano l'account di servizio predefinito di Compute Engine, specifica il seguente valore:

    serviceAccount:PROJECT_NUMBER[email protected]
    

    Sostituisci PROJECT_NUMBER con il numero del progetto del passaggio precedente.

  4. Verifica che il ruolo sia stato concesso correttamente:

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

    L'output è il nome del tuo account di servizio.

Identificare gli account di servizio dei nodi che non dispongono delle autorizzazioni richieste

Le sezioni seguenti descrivono come identificare gli account di servizio dei nodi che non hanno le autorizzazioni richieste per GKE.

Identificare i cluster con service account del nodo con autorizzazioni mancanti

Utilizza i consigli GKE del NODE_SA_MISSING_PERMISSIONS sottotipo di recommender per identificare i cluster Autopilot e Standard con account di servizio dei nodi con autorizzazioni mancanti. Il Recommender identifica solo i cluster creati a partire dal 1° gennaio 2024. Per trovare e correggere le autorizzazioni mancanti utilizzando il Recommender, procedi nel seguente modo:

  1. Trova i consigli attivi nel tuo progetto per il NODE_SA_MISSING_PERMISSIONS sottotipo di consiglio:

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

    Sostituisci quanto segue:

    • LOCATION: la località in cui trovare i consigli.
    • PROJECT_ID: il tuo ID progetto Google Cloud .

    L'output è simile al seguente, che indica che un cluster ha un account di servizio del nodo con autorizzazioni mancanti:

    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
    

    Potrebbero essere necessarie fino a 24 ore prima che il consiglio venga visualizzato. Per istruzioni dettagliate, consulta la sezione Visualizzare approfondimenti e consigli.

  2. Per ogni cluster presente nell'output del passaggio precedente, individua gli account di servizio dei nodi associati e concedi il ruolo richiesto a questi account di servizio. Per maggiori dettagli, consulta le istruzioni nella sezione Assegnare agli account di servizio dei nodi il ruolo richiesto per GKE.

    Dopo aver concesso il ruolo richiesto agli account di servizio del nodo identificati, il consiglio potrebbe rimanere attivo per un massimo di 24 ore, a meno che non lo ignori manualmente.

Identifica tutti i service account del nodo con autorizzazioni mancanti

Puoi eseguire uno script che cerca gli account di servizio dei nodi nei cluster standard e Autopilot del tuo progetto per verificare la presenza di account di servizio dei nodi che non dispongono delle autorizzazioni necessarie per GKE. Questo script utilizza l'interfaccia alla gcloud CLI'utilità jq. Per visualizzare lo script, espandi la sezione seguente:

Visualizza lo 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

Questo script si applica a tutti i cluster GKE del progetto.

Dopo aver identificato i nomi degli account di servizio con le autorizzazioni mancanti, assegna loro il ruolo richiesto. Per maggiori dettagli, consulta le istruzioni nella sezione Assegnare agli account di servizio dei nodi il ruolo richiesto per GKE.

Ripristina l'account di servizio predefinito nel Google Cloud progetto

L'account di servizio predefinito di GKE, container-engine-robot, può essere sganciato accidentalmente da un progetto. Il ruolo Agente di servizio Kubernetes Engine (roles/container.serviceAgent) è un ruolo Identity and Access Management (IAM) che concede all'account di servizio le autorizzazioni per gestire le risorse del cluster. Serimuovi questa associazione di ruolo dall'account di servizio, l'account di servizio predefinito non sarà più associato al progetto, il che potrebbe impedirti di eseguire il deployment delle applicazioni e altre operazioni del cluster.

Per verificare se l'account di servizio è stato rimosso dal progetto, puoi utilizzare la Google Cloud console o Google Cloud CLI.

Console

gcloud

  • Esegui questo comando:

    gcloud projects get-iam-policy PROJECT_ID
    

    Sostituisci PROJECT_ID con l'ID progetto.

Se la dashboard o il comando non mostra container-engine-robot tra i tuoi account di servizio, il ruolo non è associato.

Per ripristinare l'associazione del ruolo dell'agente di servizio Kubernetes Engine (roles/container.serviceAgent), esegui i seguenti comandi:

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

Verifica che l'associazione del ruolo sia stata ripristinata:

gcloud projects get-iam-policy $PROJECT_ID

Se vedi il nome dell'account di servizio insieme al ruolo container.serviceAgent, l'associazione del ruolo è stata ripristinata. Ad esempio:

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

Abilita l'account di servizio predefinito Compute Engine

L'account di servizio utilizzato per il pool di nodi è in genere l'account di servizio predefinito di Compute Engine. Se questo account di servizio predefinito viene disattivato, la registrazione dei nodi al cluster potrebbe non riuscire.

Per verificare se l'account di servizio è disattivato nel tuo progetto, puoi utilizzare laGoogle Cloud console o l&#gcloud CLI.

Console

gcloud

  • Esegui questo comando:
gcloud iam service-accounts list  --filter="NAME~'compute' AND disabled=true"

Se l'account di servizio è disattivato, esegui il seguente comando per attivarlo:

gcloud iam service-accounts enable PROJECT_ID[email protected]

Sostituisci PROJECT_ID con l'ID progetto.

Per ulteriori informazioni, consulta la sezione Risolvere i problemi di registrazione dei nodi.

Errore 400/403: autorizzazioni di modifica mancanti nell'account

Se il tuo account di servizio viene eliminato, potresti visualizzare un errore relativo alle autorizzazioni di modifica mancanti. Per scoprire come risolvere questo problema, consulta Errore 400/403: autorizzazioni di modifica mancanti nell'account.

Passaggi successivi