Resolva problemas de erros 4xx


Esta página ajuda a resolver os erros 400, 401, 403 e 404 que pode encontrar quando usa o Google Kubernetes Engine (GKE).

Problema: erros de autenticação e autorização

Quando se liga a clusters do GKE, pode receber um erro de autenticação e autorização com o código de estado HTTP 401 (Unauthorized). Este problema pode ocorrer quando tenta executar um comando kubectl no cluster do GKE a partir de um ambiente local.

A causa deste problema pode ser uma das seguintes:

  • O plugin de autenticação gke-gcloud-auth-plugin não está instalado nem configurado corretamente.
  • Não tem as autorizações necessárias para se ligar ao servidor da API do cluster e executar comandos kubectl.

Para diagnosticar a causa, conclua os passos nas secções seguintes:

  1. Estabeleça ligação ao cluster através de curl
  2. Configure o plug-in no kubeconfig

Ligue-se ao cluster através de curl

Para diagnosticar a causa do erro de autenticação e autorização, ligue-se ao cluster através de curl. A utilização de curl ignora a ferramenta de linha de comandos kubectl e o plug-in gke-gcloud-auth-plugin.

  1. Defina variáveis de ambiente:

    APISERVER=https://$(gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION --format "value(endpoint)")
    TOKEN=$(gcloud auth print-access-token)
    
  2. Verifique se o token de acesso é válido:

    curl https://oauth2.googleapis.com/tokeninfo?access_token=$TOKEN
    

    Quando tem um token de acesso válido, este comando envia um pedido para o servidor OAuth 2.0 da Google, e o servidor responde com informações sobre o token.

  3. Tente estabelecer ligação ao ponto final da API principal no servidor da API:

    # Get cluster CA certificate
    gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --format "value(masterAuth.clusterCaCertificate)" | \
        base64 -d > /tmp/ca.crt
    
    # Make API call with authentication and CA certificate
    curl -s -X GET "${APISERVER}/api/v1/namespaces" \
        --header "Authorization: Bearer $TOKEN" \
        --cacert /tmp/ca.crt
    

    Se o comando curl for bem-sucedido, é apresentada uma lista de espaços de nomes. Proceda à verificação para saber se o plug-in é a causa através dos passos na secção Configure o plug-in no kubeconfig.

    Se o comando curl falhar com um resultado semelhante ao seguinte, não tem as autorizações corretas para aceder ao cluster:

    {
    "kind": "Status",
    "apiVersion": "v1",
    "metadata": {},
    "status": "Failure",
    "message": "Unauthorized",
    "reason": "Unauthorized",
    "code": 401
    }
    

    Para resolver este problema, consulte o seu administrador para obter as autorizações corretas para aceder ao cluster.

Configure a utilização do plug-in no kubeconfig

Se estiver a receber erros de autenticação e autorização ao estabelecer ligação aos seus clusters, mas conseguiu estabelecer ligação ao cluster através do curl, certifique-se de que consegue aceder ao cluster sem precisar do plug-in gke-gcloud-auth-plugin.

Para resolver este problema, configure o seu ambiente local para ignorar o ficheiro binário gke-gcloud-auth-plugin ao autenticar no cluster. Nos clientes do Kubernetes que executam a versão 1.25 e posteriores, o binário gke-gcloud-auth-plugin é obrigatório, pelo que tem de usar uma versão 1.24 ou anterior para a ferramenta de linha de comandos kubectl.

Siga estes passos para aceder ao cluster sem precisar do plug-in:

  1. Instale a ferramenta de linha de comandos kubectl com a versão 1.24 ou anterior através de curl. O exemplo seguinte instala a ferramenta com a versão 1.24:

    curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
    
  2. Abra o ficheiro de script de arranque da shell num editor de texto. Por exemplo, abra .bashrc para a shell Bash:

    vi ~/.bashrc
    

    Se estiver a usar o macOS, use ~/.bash_profile em vez de .bashrc nestas instruções.

  3. Adicione a seguinte linha ao ficheiro de script de arranque e guarde-o:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=False
    
  4. Execute o script de arranque:

    source ~/.bashrc
    
  5. Obtenha credenciais para o seu cluster, que configuram o ficheiro .kube/config:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION
    

    Substitua o seguinte:

  6. Executar um comando kubectl. Por exemplo:

    kubectl cluster-info
    

    Se receber um erro 401 ou um erro de autorização semelhante depois de executar estes comandos, certifique-se de que tem as autorizações corretas e, em seguida, volte a executar o passo que devolveu o erro.

Erro 400: o node pool requer recriação

O seguinte erro pode ocorrer quando tenta realizar uma ação que recria o plano de controlo e os nós:

ERROR: (gcloud.container.clusters.update) ResponseError: code=400, message=Node pool "test-pool-1" requires recreation.

Por exemplo, este erro pode ocorrer quando conclui uma rotação de credenciais em curso.

No back-end, os conjuntos de nós são marcados para recriação, mas a operação de recriação real pode demorar algum tempo a começar. Por este motivo, a operação falha porque o GKE ainda não recriou um ou mais conjuntos de nós no seu cluster.

Para resolver este problema, escolha uma das seguintes soluções:

  • Aguarde que a recriação ocorra. Isto pode demorar horas, dias ou semanas, dependendo de fatores como as janelas de manutenção e as exclusões existentes.
  • Inicie manualmente uma recriação dos conjuntos de nós afetados iniciando uma atualização de versão para a mesma versão do plano de controlo.

    Para iniciar uma recriação, execute o seguinte comando:

    gcloud container clusters upgrade CLUSTER_NAME \
        --node-pool=POOL_NAME
    

    Após a conclusão da atualização, tente novamente a operação.

Erro 401: não autorizado

Identifique clusters com contas de serviço de nós que não têm autorizações críticas

Para identificar clusters com contas de serviço de nós em que faltam autorizações críticas, use as recomendações do GKE do NODE_SA_MISSING_PERMISSIONS subtipo de recomendador:

  • Use a Google Cloud consola. Aceda à página Clusters do Kubernetes e verifique se existe a recomendação Conceder autorizações críticas na coluna Notificações para clusters específicos.
  • Use a CLI gcloud ou a API Recommender, especificando o subtipo do recomendador NODE_SA_MISSING_PERMISSIONS.

    Para consultar recomendações, execute o seguinte comando:

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

Tenha em atenção que a recomendação pode demorar até 24 horas a ser apresentada. Para ver instruções detalhadas, saiba como ver estatísticas e recomendações.

Para implementar esta recomendação, conceda a função roles/container.defaultNodeServiceAccount à conta de serviço do nó.

Pode executar um script que procure pools de nós nos clusters padrão e do Autopilot do seu projeto para quaisquer contas de serviço de nós que não tenham as autorizações necessárias para o GKE. Este script usa a CLI gcloud e o utilitário jq. Para ver o script, expanda a secção seguinte:

Veja o guião

#!/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

Identifique contas de serviço de nós com autorizações críticas em falta num cluster

O GKE usa contas de serviço da IAM anexadas aos seus nós para executar tarefas do sistema, como registo e monitorização. No mínimo, estas contas de serviço de nós têm de ter a função Conta de serviço de nós predefinida do Kubernetes Engine (roles/container.defaultNodeServiceAccount) no seu projeto. Por predefinição, o GKE usa a conta de serviço predefinida do Compute Engine, que é criada automaticamente no seu projeto, como a conta de serviço do nó.

Se a sua organização aplicar a restrição da política da organização iam.automaticIamGrantsForDefaultServiceAccounts, a conta de serviço do Compute Engine predefinida no seu projeto pode não receber automaticamente as autorizações necessárias para o GKE.

  1. Encontre o nome da conta de serviço que os seus nós usam:

    Consola

    1. Aceda à página Clusters do Kubernetes:

      Aceda aos clusters do Kubernetes

    2. Na lista de clusters, clique no nome do cluster que quer inspecionar.
    3. Consoante o modo de funcionamento do cluster, faça uma das seguintes ações:
      • Para clusters do modo de piloto automático, na secção Segurança, encontre o campo Conta de serviço.
      • Para clusters do modo padrão, faça o seguinte:
        1. Clique no separador Nós.
        2. Na tabela Conjuntos de nós, clique no nome de um conjunto de nós. É apresentada a página Detalhes do conjunto de nós.
        3. Na secção Segurança, encontre o campo Conta de serviço.

    Se o valor no campo Conta de serviço for default, os seus nós usam a conta de serviço predefinida do Compute Engine. Se o valor neste campo não for default, os seus nós usam uma conta de serviço personalizada. Para conceder a função necessária a uma conta de serviço personalizada, consulte o artigo Use contas de serviço da IAM com o menor número de privilégios.

    gcloud

    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 o resultado for default, os seus nós usam a conta de serviço predefinida do Compute Engine. Se o resultado não for default, os seus nós usam uma conta de serviço personalizada. Para conceder a função necessária a uma conta de serviço personalizada, consulte o artigo Use contas de serviço da IAM com o menor número de privilégios.

  2. Para conceder a função roles/container.defaultNodeServiceAccount à conta de serviço predefinida do Compute Engine, conclua os passos seguintes:

    consola

    1. Aceda à página Boas-vindas:

      Aceder a Boas-vindas

    2. No campo Número do projeto, clique em Copiar para a área de transferência.
    3. Aceda à página IAM:

      Aceda ao IAM

    4. Clique em Conceder acesso.
    5. No campo Novos responsáveis, especifique o seguinte valor:
      PROJECT_NUMBER-compute@developer.gserviceaccount.com
      Substitua PROJECT_NUMBER pelo número do projeto que copiou.
    6. No menu Selecionar uma função, selecione a função Conta de serviço do nó predefinido do Kubernetes Engine.
    7. Clique em Guardar.

    gcloud

    1. Encontre o seu Google Cloud número do projeto:
      gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)"

      Substitua PROJECT_ID pelo ID do seu projeto.

      O resultado é semelhante ao seguinte:

      12345678901
      
    2. Conceda a função roles/container.defaultNodeServiceAccount à conta de serviço predefinida do Compute Engine:
      gcloud projects add-iam-policy-binding PROJECT_ID \
          --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
          --role="roles/container.defaultNodeServiceAccount"

      Substitua PROJECT_NUMBER pelo número do projeto do passo anterior.

Erro 403: autorizações insuficientes

O seguinte erro ocorre quando tenta estabelecer ligação a um cluster do GKE usando o gcloud container clusters get-credentials, mas a conta não tem autorização para aceder ao servidor da API Kubernetes:

ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Required "container.clusters.get" permission(s) for "projects/<your-project>/locations/<region>/clusters/<your-cluster>".

Para resolver este problema, conclua os seguintes passos:

  1. Identifique a conta que tem o problema de acesso:

    gcloud auth list
    
  2. Conceda o acesso necessário à conta através das instruções em Autenticação no servidor da API Kubernetes.

Erro 403: limite de novas tentativas esgotado

O seguinte erro pode ocorrer quando tenta criar um cluster do GKE:

Error: googleapi: Error 403: Retry budget exhausted: Google Compute Engine:
Required permission 'PERMISSION_NAME' for 'RESOURCE_NAME'.

Nesta mensagem de erro, aplicam-se as seguintes variáveis:

  • PERMISSION_NAME: o nome de uma autorização, como compute.regions.get.
  • RESOURCE_NAME: o caminho para o recurso ao qual estava a tentar aceder, como uma região do Compute Engine. Google Cloud

Este erro ocorre se a conta de serviço do IAM associada ao cluster não tiver as autorizações mínimas necessárias para criar o cluster.

Para resolver este problema, faça o seguinte:

  1. Crie ou modifique uma conta de serviço do IAM para ter todas as autorizações necessárias para executar um cluster do GKE. Para obter instruções, consulte o artigo Use contas de serviço IAM com o menor número de privilégios.
  2. Especifique a conta de serviço do IAM atualizada no comando de criação do cluster com a flag --service-account. Para ver instruções, consulte o artigo Crie um cluster do Autopilot.

Em alternativa, omita a flag --service-account para permitir que o GKE use a conta de serviço predefinida do Compute Engine no projeto, que tem as autorizações necessárias por predefinição.

Erro 404: recurso não encontrado

Se receber um erro 404, recurso não encontrado, ao chamar comandos gcloud container, resolva o problema autenticando novamente na CLI Google Cloud:

gcloud auth login

Erro 400/403: autorizações de edição em falta na conta

Um erro de autorizações de edição em falta na conta (erro 400 ou 403) indica que um dos seguintes foi eliminado ou editado manualmente:

Quando ativa a API Compute Engine ou GKE, Google Cloud são criadas as seguintes contas de serviço e agentes:

  • Conta de serviço predefinida do Compute Engine no seu projeto. Por predefinição, o GKE anexa esta conta de serviço aos nós para tarefas do sistema, como o registo e a monitorização.
  • Agente do serviço de APIs Google num projeto gerido pela Google, com autorizações de edição no seu projeto.
  • Agente de serviço do Google Kubernetes Engine num projeto gerido pela Google, com a função de agente de serviço do Kubernetes Engine no seu projeto.

A criação do cluster e toda a gestão falham se, em qualquer altura, alguém editar essas autorizações, remover as associações de funções no projeto, remover a conta de serviço por completo ou desativar a API.

Valide as autorizações do agente de serviço do GKE

Para verificar se a conta de serviço do Google Kubernetes Engine tem a função Agente de serviço do Kubernetes Engine atribuída no projeto, conclua os seguintes passos:

  1. Determine o nome da sua conta de serviço do Google Kubernetes Engine. Todas as contas de serviço têm o seguinte formato:

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

    Substitua PROJECT_NUMBER pelo seu número do projeto.

  2. Verifique se a sua conta de serviço do Google Kubernetes Engine não tem a função de agente de serviço do Kubernetes Engine atribuída no projeto:

    gcloud projects get-iam-policy PROJECT_ID
    

    Substitua PROJECT_ID pelo ID do seu projeto.

Para corrigir o problema, se alguém tiver removido a função Agente de serviço do Kubernetes Engine da sua conta de serviço do Google Kubernetes Engine, adicione-a novamente. Caso contrário, use as seguintes instruções para reativar a API Kubernetes Engine, que restaura as contas de serviço e as autorizações:

Consola

  1. Aceda à página APIs e serviços na Google Cloud consola.

    Aceda a APIs e serviços

  2. Selecione o seu projeto.

  3. Clique em Ativar APIs e serviços.

  4. Pesquise Kubernetes e, em seguida, selecione a API nos resultados da pesquisa.

  5. Clique em Ativar. Se ativou a API anteriormente, tem de a desativar e, em seguida, ativá-la novamente. A ativação da API e dos serviços relacionados pode demorar alguns minutos.

gcloud

Execute os seguintes comandos na CLI gcloud:

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

O que se segue?