Fehlerbehebung bei Dienstkonten in GKE

Falsch konfigurierte oder fehlende Berechtigungen für Google Kubernetes Engine-Dienstkonten (GKE) können zu verschiedenen Problemen führen, z. B. dazu, dass Knoten nicht registriert werden können oder Arbeitslasten nicht auf Dienste zugreifen können. Google Cloud

In diesem Dokument erfahren Sie, wie Sie Probleme beheben können, die durch falsch konfigurierte, deaktivierte oder gelöschte Dienstkonten verursacht werden.

Diese Informationen sind wichtig für Plattformadministratoren und ‑operatoren sowie für Sicherheitsingenieure, die IAM-Berechtigungen auf Projektebene für GKE-Knoten und GKE-Kernkomponenten konfigurieren und verwalten. Weitere Informationen zu den gängigen Rollen und Beispielaufgaben, auf die wir in Google Cloud Inhalten verweisen, finden Sie unter Häufig verwendete GKE-Nutzerrollen und -aufgaben.

Erforderliche Rolle für GKE für Knotendienstkonten zuweisen

Für GKE-Cluster mit Kubernetes-Version 1.33 oder niedriger müssen die IAM-Dienstkonten, die von Ihren GKE-Knoten verwendet werden, alle Berechtigungen haben, die in der IAM-Rolle „Kubernetes Engine Default Node Service Account“ (roles/container.defaultNodeServiceAccount) enthalten sind. Wenn einem GKE-Knotendienstkonto eine oder mehrere dieser Berechtigungen fehlen, kann GKE keine Systemaufgaben wie die folgenden ausführen:

Knotendienstkonten haben möglicherweise bestimmte erforderliche Berechtigungen aus folgenden Gründen nicht:

Wenn Ihrem Knotendienstkonto die von GKE benötigten Berechtigungen fehlen, werden möglicherweise Fehler und Hinweise wie die folgenden angezeigt:

  • In der Google Cloud Console wird auf der Seite Kubernetes-Cluster in der Spalte Benachrichtigungen für einen bestimmten Cluster die Fehlermeldung Grant critical permissions (Wichtige Berechtigungen erteilen) angezeigt.
  • In der Google Cloud Console wird auf der Detailseite des Clusters für einen bestimmten Cluster die folgende Fehlermeldung angezeigt:

    Grant roles/container.defaultNodeServiceAccount role to Node service account to allow for non-degraded operations.
    
  • In Cloud-Audit-Logs haben Administratoraktivitätslogs für Google Cloud APIs wie monitoring.googleapis.com die folgenden Werte, wenn dem Knotendienstkonto die entsprechenden Berechtigungen für den Zugriff auf diese APIs fehlen:

    • Schweregrad: ERROR
    • Nachricht: Permission denied (or the resource may not exist) (Berechtigung verweigert (oder die Ressource ist möglicherweise nicht vorhanden))
  • Logs für bestimmte Knoten fehlen in Cloud Logging und in den Pod-Logs für den Logging-Agent auf diesen Knoten werden 401-Fehler angezeigt. Führen Sie den folgenden Befehl aus, um diese Pod-Logs abzurufen:

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

    Wenn die Ausgabe true ist, treten bei der Systemarbeitslast 401-Fehler auf, die auf fehlende Berechtigungen hinweisen.

Um dieses Problem zu beheben, weisen Sie dem Dienstkonto, das die Fehler verursacht, die Rolle „Kubernetes Engine Default Node Service Account“ (roles/container.defaultNodeServiceAccount) im Projekt zu. Wählen Sie eine der folgenden Optionen aus:

Console

So finden Sie den Namen des Dienstkontos, das von Ihren Knoten verwendet wird:

  1. Rufen Sie die Seite Kubernetes-Cluster auf:

    Zur Seite "Kubernetes-Cluster"

  2. Klicken Sie in der Clusterliste auf den Namen des Clusters, den Sie untersuchen möchten.

  3. Suchen Sie den Namen des Knotendienstkontos. Sie benötigen diesen Namen später.

    • Suchen Sie bei Clustern im Autopilot-Modus im Bereich Sicherheit nach dem Feld Dienstkonto.
    • Führen Sie für Cluster im Standardmodus die folgenden Schritte aus:
    1. Klicken Sie auf den Tab Knoten.
    2. Klicken Sie in der Tabelle Knotenpools auf einen Knotenpoolnamen. Die Seite Knotenpooldetails wird geöffnet.
    3. Suchen Sie im Bereich Sicherheit nach dem Feld Dienstkonto.

    Wenn der Wert im Feld Dienstkonto default ist, verwenden Ihre Knoten das Compute Engine-Standarddienstkonto. Wenn der Wert in diesem Feld nicht default ist, verwenden Ihre Knoten ein benutzerdefiniertes Dienstkonto.

So weisen Sie dem Dienstkonto die Rolle Kubernetes Engine Default Node Service Account zu:

  1. Rufen Sie die Seite Willkommen auf:

    Zur Seite „Willkommen“

  2. Klicken Sie im Feld Projektnummer auf In die Zwischenablage kopieren.

  3. Rufen Sie die Seite IAM auf:

    IAM aufrufen

  4. Klicken Sie auf Zugriffsrechte erteilen.

  5. Geben Sie im Feld Neue Hauptkonten den Namen Ihres Knotendienstkontos an. Wenn Ihre Knoten das Compute Engine-Standarddienstkonto verwenden, geben Sie den folgenden Wert an:

    PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Ersetzen Sie PROJECT_NUMBER durch die kopierte Projektnummer.

  6. Wählen Sie im Menü Rolle auswählen die Rolle Kubernetes Engine Default Node Service Account aus.

  7. Klicken Sie auf Speichern.

So prüfen Sie, ob die Rolle zugewiesen wurde:

  1. Klicken Sie auf der Seite IAM auf den Tab Nach Rollen ansehen.
  2. Maximieren Sie den Bereich Kubernetes Engine Default Node Service Account. Eine Liste der Hauptkonten mit dieser Rolle wird angezeigt.
  3. Suchen Sie Ihr Knotendienstkonto in der Liste der Hauptkonten.

gcloud

  1. Suchen Sie den Namen des Dienstkontos, das von Ihren Knoten verwendet wird:

    • Führen Sie für Cluster im Autopilot-Modus den folgenden Befehl aus:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --flatten=autoscaling.autoprovisioningNodePoolDefaults.serviceAccount
    
    • Führen Sie für Cluster im Standardmodus den folgenden Befehl aus:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="table(nodePools.name,nodePools.config.serviceAccount)"
    

    Wenn die Ausgabe default ist, verwenden Ihre Knoten das Compute Engine-Standarddienstkonto. Wenn die Ausgabe nicht default ist, verwenden Ihre Knoten ein benutzerdefiniertes Dienstkonto.

  2. Suchen Sie Ihre Google Cloud Projektnummer:

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

    Ersetzen Sie PROJECT_ID durch Ihre Projekt-ID.

    Die Ausgabe sieht etwa so aus:

    12345678901
    
  3. Weisen Sie dem Dienstkonto die Rolle roles/container.defaultNodeServiceAccount zu:

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

    Ersetzen Sie SERVICE_ACCOUNT_NAME durch den Namen des Dienstkontos, den Sie im vorherigen Schritt ermittelt haben. Wenn Ihre Knoten das Compute Engine-Standarddienstkonto verwenden, geben Sie den folgenden Wert an:

    serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Ersetzen Sie PROJECT_NUMBER durch die Projektnummer aus dem vorherigen Schritt.

  4. Prüfen Sie, ob die Rolle erfolgreich zugewiesen wurde:

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

    Die Ausgabe ist der Name Ihres Dienstkontos.

Cluster mit Knotendienstkonten mit fehlenden Berechtigungen identifizieren

Verwenden Sie GKE-Empfehlungen des NODE_SA_MISSING_PERMISSIONS Recommender-Subtyps, um Autopilot- und Standardcluster mit Knotendienstkonten mit fehlenden Berechtigungen zu identifizieren. Recommender identifiziert nur Cluster, die am oder nach dem 1. Januar 2024 erstellt wurden. So finden und beheben Sie die fehlenden Berechtigungen mit Recommender:

  1. Suchen Sie nach aktiven Empfehlungen in Ihrem Projekt für den Empfehlungssubtyp 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"
    

    Ersetzen Sie Folgendes:

    • LOCATION: der Standort, an dem Empfehlungen gesucht werden sollen.
    • PROJECT_ID: Ihre Google Cloud Projekt-ID.

    Die Ausgabe sieht etwa so aus und zeigt, dass ein Cluster ein Knotendienstkonto mit fehlenden Berechtigungen hat:

    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
    

    Es kann bis zu 24 Stunden dauern, bis die Empfehlung angezeigt wird. Eine detaillierte Anleitung finden Sie unter Insights und Empfehlungen anzeigen.

  2. Suchen Sie für jeden Cluster in der Ausgabe des vorherigen Schritts die zugehörigen Knotendienstkonten und weisen Sie diesen Dienstkonten die erforderliche Rolle zu. Weitere Informationen finden Sie in der Anleitung im Abschnitt Knotendienstkonten die erforderliche Rolle für GKE zuweisen.

    Nachdem Sie den identifizierten Knotendienstkonten die erforderliche Rolle zugewiesen haben, bleibt die Empfehlung möglicherweise bis zu 24 Stunden bestehen, es sei denn, Sie lehnen sie manuell ab.

Alle Knotendienstkonten mit fehlenden Berechtigungen identifizieren

Sie können ein Script ausführen, das in den Knotenpools der Standard- und Autopilot-Clustern Ihres Projekts nach Knotendienstkonten sucht, die nicht die erforderlichen Berechtigungen für GKE haben. Dieses Script verwendet die gcloud CLI und das jq Dienstprogramm. Maximieren Sie den folgenden Abschnitt, um das Script aufzurufen:

Script ansehen

#!/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}-compute@developer.gserviceaccount.com"
      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}-compute@developer.gserviceaccount.com"
      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

Dieses Script gilt für alle GKE-Cluster in Ihrem Projekt.

Nachdem Sie die Namen der Dienstkonten mit fehlenden Berechtigungen ermittelt haben, weisen Sie ihnen die erforderliche Rolle zu. Weitere Informationen finden Sie in der Anleitung im Abschnitt Knotendienstkonten die erforderliche Rolle für GKE zuweisen.

Standarddienstkonto für Ihr Google Cloud Projekt wiederherstellen

Die Verknüpfung des GKE-Standarddienstkontos container-engine-robot mit einem Projekt kann versehentlich aufgehoben werden. Die Rolle Kubernetes Engine-Dienst-Agent (roles/container.serviceAgent) ist eine IAM-Rolle (Identity and Access Management), mit der dem Dienstkonto Berechtigungen zum Verwalten von Clusterressourcen erteilt werden. Wenn Sie diese Rollenbindung aus dem Dienstkonto entfernen, wird die Verknüpfung des Standarddienstkontos mit dem Projekt aufgehoben. Dies kann verhindern, dass Anwendungen bereitgestellt und andere Clustervorgänge ausgeführt werden.

Mit der Console oder der Google Cloud CLI können Sie prüfen, ob das Dienstkonto aus Ihrem Projekt entfernt wurde. Google Cloud

Console

gcloud

  • Führen Sie dazu diesen Befehl aus:

    gcloud projects get-iam-policy PROJECT_ID
    

    Ersetzen Sie PROJECT_ID durch Ihre Projekt-ID.

Wenn im Dashboard oder im Befehl unter Ihren Dienstkonten container-engine-robot nicht angezeigt wird, wurde die Verknüpfung mit dem Dienstkonto aufgehoben.

Führen Sie die folgenden Befehle aus, um die Bindung der Rolle „Kubernetes Engine-Dienst-Agent (roles/container.serviceAgent)“ wiederherzustellen:

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

Prüfen Sie, ob die Rollenbindung wiederhergestellt wurde:

gcloud projects get-iam-policy PROJECT_ID

Wenn der Name des Dienstkontos zusammen mit der Rolle container.serviceAgent angezeigt wird, wurde die Rollenbindung wiederhergestellt. Beispiel:

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

Compute Engine-Standarddienstkonto aktivieren

Das für den Knotenpool verwendete Dienstkonto ist in der Regel das Compute Engine-Standarddienstkonto. Wenn dieses Standarddienstkonto deaktiviert ist, können Ihre Knoten möglicherweise nicht beim Cluster registriert werden.

Mit der Console oder der gcloud CLI können Sie prüfen, ob das Dienstkonto in Ihrem Projekt deaktiviert ist.Google Cloud

Console

gcloud

  • Führen Sie diesen Befehl aus:
gcloud iam service-accounts list  --filter="NAME~'compute' AND disabled=true"

Wenn das Dienstkonto deaktiviert ist, führen Sie die folgenden Befehle aus, um es zu aktivieren:

  1. Suchen Sie Ihre Google Cloud Projektnummer:

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

    Ersetzen Sie PROJECT_ID durch Ihre Projekt-ID.

    Die Ausgabe sieht etwa so aus:

    12345678901
    
  2. Aktivieren Sie das Dienstkonto:

    gcloud iam service-accounts enable PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Ersetzen Sie PROJECT_NUMBER durch Ihre Projektnummer aus der Ausgabe des vorherigen Schritts.

Weitere Informationen finden Sie unter Fehlerbehebung bei der Knotenregistrierung.

Fehler 400/403: Dem Konto fehlen Bearbeitungsberechtigungen

Wenn Ihr Dienstkonto gelöscht wird, wird möglicherweise der Fehler „Fehlende Bearbeitungsberechtigungen“ angezeigt. Informationen zum Beheben dieses Fehlers finden Sie unter Fehler 400/403: Dem Konto fehlen Bearbeitungsberechtigungen.

Nächste Schritte