Resolver problemas de contas de serviço no GKE

Nesta página, mostramos como resolver problemas com contas de serviço do Google Kubernetes Engine (GKE).

Conceda o papel necessário para o GKE às contas de serviço do nó

Para clusters do GKE que usam a versão 1.33 ou anterior do Kubernetes, as contas de serviço do IAM usadas pelos nós do GKE precisam ter todas as permissões incluídas no papel do IAM Conta de serviço de nó padrão do Kubernetes Engine (roles/container.defaultNodeServiceAccount). Se uma conta de serviço do nó do GKE não tiver uma ou mais dessas permissões, o GKE não poderá realizar tarefas do sistema como:

As contas de serviço do nó podem não ter determinadas permissões necessárias por motivos como:

Se a conta de serviço do nó não tiver as permissões exigidas pelo GKE, você poderá encontrar erros e avisos como estes:

  • No console Google Cloud , na página Clusters do Kubernetes, uma mensagem de erro Conceder permissões críticas aparece na coluna Notificações de um cluster específico.
  • No console Google Cloud , na página de detalhes de um cluster específico, aparece a seguinte mensagem de erro:

    Grant roles/container.defaultNodeServiceAccount role to Node service account to allow for non-degraded operations.
    
  • Nos registros de auditoria do Cloud, os registros de atividade do administrador para APIs Google Cloud , como monitoring.googleapis.com, têm os seguintes valores se as permissões correspondentes para acessar essas APIs estiverem faltando na conta de serviço do nó:

    • Gravidade: ERROR
    • Mensagem: Permission denied (or the resource may not exist)
  • Os registros de nós específicos estão ausentes do Cloud Logging, e os registros de pod do agente de geração de registros nesses nós mostram erros 401. Para receber esses registros do pod, execute o seguinte 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 a saída for true, a carga de trabalho do sistema estará apresentando erros de 401, o que indica falta de permissões.

Para resolver esse problema, conceda o papel de conta de serviço de nó padrão do Kubernetes Engine (roles/container.defaultNodeServiceAccount) no projeto à conta de serviço que está causando os erros. Selecione uma das seguintes opções:

Console

Para encontrar o nome da conta de serviço usada pelos nós, faça o seguinte:

  1. Acesse a página Clusters do Kubernetes:

    Acessar os clusters do Kubernetes

  2. Na lista de clusters, clique no nome do cluster que você quer inspecionar.

  3. Encontre o nome da conta de serviço do nó. Você vai precisar desse nome mais tarde.

    • Para clusters no modo Autopilot, na seção Segurança, encontre o campo Conta de serviço.
    • Para clusters no modo padrão, faça o seguinte:
    1. Clique na guia Nós.
    2. Na tabela Pools de nós, clique no nome de um pool de nós. A página Detalhes do pool de nós é aberta.
    3. Na seção Segurança, encontre o campo Conta de serviço.

    Se o valor no campo Conta de serviço for default, os nós usarão a conta de serviço padrão do Compute Engine. Se o valor nesse campo não for default, seus nós usarão uma conta de serviço personalizada.

Para conceder o papel Kubernetes Engine Default Node Service Account à conta de serviço, faça o seguinte:

  1. Acesse a página Boas-vindas:

    Acessar "Boas-vindas"

  2. No campo Número do projeto, clique em Copiar para a área de transferência.

  3. Acesse a página do IAM:

    Acessar IAM

  4. Clique em CONCEDER ACESSO.

  5. No campo Novos principais, especifique o nome da conta de serviço do nó. Se os nós usarem a conta de serviço padrão do Compute Engine, especifique o seguinte valor:

    PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Substitua PROJECT_NUMBER pelo número do projeto que você copiou.

  6. No menu Selecionar um papel, escolha o papel Conta de serviço do nó padrão do Kubernetes Engine.

  7. Clique em Salvar.

Para verificar se a função foi concedida, faça o seguinte:

  1. Na página IAM, clique na guia Visualizar por papéis.
  2. Expanda a seção Conta de serviço do nó padrão do Kubernetes Engine. Uma lista de principais que têm essa função é exibida.
  3. Encontre a conta de serviço do nó na lista de principais.

gcloud

  1. Encontre o nome da conta de serviço usada pelos seus nós:

    • Para clusters no modo Autopilot, execute o seguinte comando:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --flatten=autoscaling.autoprovisioningNodePoolDefaults.serviceAccount
    
    • Para clusters no modo padrão, execute o seguinte comando:
    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="table(nodePools.name,nodePools.config.serviceAccount)"
    

    Se a saída for default, os nós usarão a conta de serviço padrão do Compute Engine. Se a saída não for default, seus nós usarão uma conta de serviço personalizada.

  2. Encontre o número do seu projeto Google Cloud :

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

    Substitua PROJECT_ID pela ID do seu projeto.

    O resultado será assim:

    12345678901
    
  3. Conceda o papel roles/container.defaultNodeServiceAccount à conta de serviço:

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

    Substitua SERVICE_ACCOUNT_NAME pelo nome da conta de serviço, que você encontrou na etapa anterior. Se os nós usarem a conta de serviço padrão do Compute Engine, especifique o valor a seguir:

    serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Substitua PROJECT_NUMBER pelo número do projeto da etapa anterior.

  4. Verifique se a função foi concedida:

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

    A saída é o nome da sua conta de serviço.

Identificar clusters com contas de serviço de nós sem permissões

Use as recomendações do GKE do NODE_SA_MISSING_PERMISSIONS subtipo de recomendador para identificar clusters do Autopilot e do Standard que têm contas de serviço de nós com permissões ausentes. O Recommender identifica apenas clusters criados a partir de 1º de janeiro de 2024. Para encontrar e corrigir as permissões ausentes usando o Recomendador, faça o seguinte:

  1. Encontre recomendações ativas no seu projeto para o subtipo de recomendador 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"
    

    Substitua:

    • LOCATION: o local em que as recomendações serão encontradas.
    • PROJECT_ID: o ID do projeto Google Cloud .

    A saída é semelhante à seguinte, que indica que um cluster tem uma conta de serviço de nó com permissões ausentes:

    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
    

    A recomendação pode levar até 24 horas para aparecer. Para instruções detalhadas, consulte ver insights e recomendações.

  2. Para cada cluster na saída da etapa anterior, encontre as contas de serviço de nó associadas e conceda a função necessária a elas. Para detalhes, consulte as instruções na seção Conceder às contas de serviço do nó o papel necessário para o GKE.

    Depois de conceder o papel necessário às contas de serviço do nó identificadas, a recomendação pode persistir por até 24 horas, a menos que você a dispense manualmente.

Identificar todas as contas de serviço de nó com permissões ausentes

É possível executar um script que pesquisa pools de nós nos clusters Standard e Autopilot do projeto para encontrar contas de serviço de nós que não têm as permissões necessárias para o GKE. Esse script usa a CLI gcloud e o utilitário jq. Para ver o script, expanda a seção a seguir:

Ver o 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}-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

Esse script se aplica a todos os clusters do GKE no seu projeto.

Depois de identificar os nomes das contas de serviço com permissões ausentes, conceda a elas o papel necessário. Para mais detalhes, consulte as instruções na seção Conceder às contas de serviço do nó o papel necessário para o GKE.

Restaurar a conta de serviço padrão para seu projeto Google Cloud

A conta de serviço padrão do GKE, container-engine-robot, pode ser acidentalmente desassociada de um projeto. O papel de agente de serviço do Kubernetes Engine (roles/container.serviceAgent) é um papel de Identity and Access Management (IAM) que concede à conta de serviço as permissões para gerenciar recursos de cluster. Se você remover essa vinculação de papel da conta de serviço, a conta de serviço padrão ficará desvinculada do projeto, o que poderá impedir a implantação de aplicativos e a execução de outras operações de cluster.

Para verificar se a conta de serviço foi removida do seu projeto, use o console Google Cloud ou a Google Cloud CLI.

Console

gcloud

  • Execute este comando:

    gcloud projects get-iam-policy PROJECT_ID
    

    Substitua PROJECT_ID pela ID do projeto.

Se o painel ou o comando não mostrar container-engine-robot entre suas contas de serviço, o papel está desvinculado.

Para restaurar a vinculação de papel de agente de serviço do Kubernetes Engine (roles/container.serviceAgent), execute os seguintes comandos:

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

Confirme se a vinculação de função foi restaurada:

gcloud projects get-iam-policy PROJECT_ID

Se o nome da conta de serviço estiver com a função container.serviceAgent, a vinculação de papel foi restaurada. Por exemplo:

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

Ativar a conta de serviço padrão do Compute Engine

A conta de serviço usada para o pool de nós geralmente é a conta de serviço padrão do Compute Engine. Se essa conta de serviço padrão for desativada, os nós poderão não ser registrados no cluster.

Para saber se a conta de serviço está desativada no seu projeto, use o console doGoogle Cloud ou a CLI gcloud.

Console

gcloud

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

Se a conta de serviço estiver desativada, execute os seguintes comandos para ativá-la:

  1. Encontre o número do seu projeto Google Cloud :

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

    Substitua PROJECT_ID pela ID do seu projeto.

    O resultado será assim:

    12345678901
    
  2. Ative a conta de serviço:

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

    Substitua PROJECT_NUMBER pelo número do projeto na saída da etapa anterior.

Para mais informações, consulte Resolver problemas no registro de nós.

Erro 400/403: permissões de edição ausentes na conta

Se a conta de serviço for excluída, talvez apareça um erro de permissões de edição ausentes. Para saber como resolver esse erro, consulte Erro 400/403: permissões de edição ausentes na conta.

A seguir

  • Se você não encontrar uma solução para seu problema na documentação, consulte Receber suporte para mais ajuda, incluindo conselhos sobre os seguintes tópicos: