Solucionar errores 4xx


En esta página se explica cómo resolver los errores 400, 401, 403 y 404 que pueden producirse al usar Google Kubernetes Engine (GKE).

Problema: errores de autenticación y autorización

Al conectarte a clústeres de GKE, puedes recibir un error de autenticación y autorización con el código de estado HTTP 401 (Unauthorized). Este problema puede producirse cuando intentas ejecutar un comando kubectl en tu clúster de GKE desde un entorno local.

Este problema puede deberse a uno de los siguientes motivos:

  • El complemento de autenticación gke-gcloud-auth-plugin no se ha instalado o configurado correctamente.
  • No tienes los permisos necesarios para conectarte al servidor de la API del clúster y ejecutar comandos kubectl.

Para diagnosticar la causa, sigue los pasos que se indican en las siguientes secciones:

  1. Conéctate al clúster mediante curl.
  2. Configurar el complemento en kubeconfig

Conéctate al clúster mediante curl.

Para diagnosticar la causa del error de autenticación y autorización, conéctate al clúster mediante curl. Si usas curl, no tendrás que usar la herramienta de línea de comandos kubectl ni el complemento gke-gcloud-auth-plugin.

  1. Define las variables de entorno:

    APISERVER=https://$(gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION --format "value(endpoint)")
    TOKEN=$(gcloud auth print-access-token)
    
  2. Comprueba que tu token de acceso sea válido:

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

    Cuando tienes un token de acceso válido, este comando envía una solicitud al servidor OAuth 2.0 de Google y el servidor responde con información sobre el token.

  3. Intenta conectarte al endpoint de la API principal en el servidor de la 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
    

    Si el comando curl se ejecuta correctamente, verás una lista de espacios de nombres. Sigue los pasos de la sección Configurar el complemento en kubeconfig para comprobar si el complemento es la causa.

    Si el comando curl falla y se muestra un resultado similar al siguiente, significa que no tienes los permisos correctos para acceder al clúster:

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

    Para solucionar este problema, ponte en contacto con tu administrador para obtener los permisos correctos y acceder al clúster.

Configurar el uso del complemento en kubeconfig

Si recibes errores de autenticación y autorización al conectarte a tus clústeres, pero has podido conectarte al clúster con curl, asegúrate de que puedes acceder a tu clúster sin necesidad del complemento gke-gcloud-auth-plugin.

Para solucionar este problema, configure su entorno local para que ignore el archivo binario gke-gcloud-auth-plugin al autenticarse en el clúster. En los clientes de Kubernetes que ejecutan la versión 1.25 y posteriores, el binario gke-gcloud-auth-plugin es obligatorio, por lo que debes usar una versión 1.24 o anterior de la herramienta de línea de comandos kubectl.

Sigue estos pasos para acceder a tu clúster sin necesidad del complemento:

  1. Instala la herramienta de línea de comandos kubectl con la versión 1.24 o una anterior mediante curl. En el siguiente ejemplo se instala la herramienta con la versión 1.24:

    curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
    
  2. Abre el archivo de secuencia de comandos de inicio de shell en un editor de texto. Por ejemplo, abre .bashrc para el shell de Bash:

    vi ~/.bashrc
    

    Si usas macOS, utiliza ~/.bash_profile en lugar de .bashrc en estas instrucciones.

  3. Añade la siguiente línea al archivo de secuencia de comandos de inicio y guárdalo:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=False
    
  4. Ejecuta la secuencia de comandos de inicio:

    source ~/.bashrc
    
  5. Obtén las credenciales de tu clúster, lo que configurará tu archivo .kube/config:

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

    Haz los cambios siguientes:

  6. Ejecuta un comando kubectl. Por ejemplo:

    kubectl cluster-info
    

    Si aparece un error 401 o un error de autorización similar después de ejecutar estos comandos, comprueba que tienes los permisos correctos y vuelve a ejecutar el paso que ha devuelto el error.

Error 400: Node pool requires recreation

Puede producirse el siguiente error al intentar realizar una acción que recree el plano de control y los nodos:

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

Por ejemplo, este error puede producirse cuando completa una rotación de credenciales en curso.

En el backend, los grupos de nodos se marcan para recrearse, pero la operación de recreación real puede tardar un tiempo en iniciarse. Por este motivo, la operación falla porque GKE aún no ha recreado uno o varios grupos de nodos en tu clúster.

Para solucionar este problema, elige una de las siguientes opciones:

  • Espera a que se vuelva a crear. Este proceso puede tardar horas, días o semanas en función de factores como las ventanas de mantenimiento y las exclusiones.
  • Inicia manualmente una recreación de los grupos de nodos afectados iniciando una actualización de versión a la misma versión que el plano de control.

    Para iniciar una recreación, ejecuta el siguiente comando:

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

    Una vez que se haya completado la actualización, vuelve a intentar la operación.

Error 401: no autorizado

Identificar clústeres a los que les faltan permisos críticos de cuentas de servicio de nodos

Para identificar los clústeres a los que les faltan permisos críticos de cuentas de servicio de nodos, usa las recomendaciones de GKE del NODE_SA_MISSING_PERMISSIONS subtipo de recomendador:

  • Usa la consola Google Cloud . Ve a la página Clústeres de Kubernetes y busca la recomendación Conceder permisos críticos en la columna Notificaciones de clústeres específicos.
  • Usa la CLI de gcloud o la API Recommender especificando el subtipo de recomendador NODE_SA_MISSING_PERMISSIONS.

    Para consultar las recomendaciones, ejecuta el siguiente comando:

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

Ten en cuenta que la recomendación puede tardar hasta 24 horas en aparecer. Para obtener instrucciones detalladas, consulta cómo ver estadísticas y recomendaciones.

Para implementar esta recomendación, concede el rol roles/container.defaultNodeServiceAccount a la cuenta de servicio del nodo.

Puedes ejecutar una secuencia de comandos que busque en los grupos de nodos de los clústeres Estándar y Autopilot de tu proyecto las cuentas de servicio de nodos que no tengan los permisos necesarios para GKE. Esta secuencia de comandos usa la CLI de gcloud y la utilidad jq. Para ver la secuencia de comandos, despliega la siguiente sección:

Ver la secuencia de comandos

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

Identificar las cuentas de servicio de nodos a las que les faltan permisos críticos en un clúster

GKE usa cuentas de servicio de gestión de identidades y accesos que están asociadas a tus nodos para ejecutar tareas del sistema, como el registro y la monitorización. Como mínimo, estas cuentas de servicio de nodo deben tener el rol Cuenta de servicio de nodo predeterminada de Kubernetes Engine (roles/container.defaultNodeServiceAccount) en tu proyecto. De forma predeterminada, GKE usa la cuenta de servicio predeterminada de Compute Engine, que se crea automáticamente en tu proyecto, como cuenta de servicio del nodo.

Si tu organización aplica la restricción de política de organización iam.automaticIamGrantsForDefaultServiceAccounts, es posible que la cuenta de servicio predeterminada de Compute Engine de tu proyecto no obtenga automáticamente los permisos necesarios para GKE.

  1. Busca el nombre de la cuenta de servicio que usan tus nodos:

    Consola

    1. Ve a la página Clústeres de Kubernetes:

      Ir a clústeres de Kubernetes

    2. En la lista de clústeres, haga clic en el nombre del clúster que quiera inspeccionar.
    3. En función del modo de funcionamiento del clúster, haz una de las siguientes acciones:
      • En el caso de los clústeres en modo Autopilot, ve a la sección Seguridad y busca el campo Cuenta de servicio.
      • En los clústeres del modo Estándar, haga lo siguiente:
        1. Haz clic en la pestaña Nodos.
        2. En la tabla Grupos de nodos, haz clic en el nombre de un grupo de nodos. Se abrirá la página Detalles del grupo de nodos.
        3. En la sección Seguridad, busca el campo Cuenta de servicio.

    Si el valor del campo Cuenta de servicio es default, tus nodos usarán la cuenta de servicio predeterminada de Compute Engine. Si el valor de este campo no es default, tus nodos usan una cuenta de servicio personalizada. Para asignar el rol necesario a una cuenta de servicio personalizada, consulta Usar cuentas de servicio de IAM con el mínimo de privilegios.

    gcloud

    En los clústeres del modo Autopilot, ejecuta el siguiente comando:

    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --flatten=autoscaling.autoprovisioningNodePoolDefaults.serviceAccount

    En los clústeres en modo Estándar, ejecuta el siguiente comando:

    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="table(nodePools.name,nodePools.config.serviceAccount)"

    Si el resultado es default, tus nodos usan la cuenta de servicio predeterminada de Compute Engine. Si el resultado no es default, tus nodos usan una cuenta de servicio personalizada. Para conceder el rol necesario a una cuenta de servicio personalizada, consulta Usar cuentas de servicio de IAM con el mínimo de privilegios.

  2. Para asignar el rol roles/container.defaultNodeServiceAccount a la cuenta de servicio predeterminada de Compute Engine, sigue estos pasos:

    consola

    1. Ve a la página Bienvenida:

      Ir a Bienvenida

    2. En el campo Número de proyecto, haz clic en Copiar en el portapapeles.
    3. Ve a la página Gestión de identidades y accesos:

      Ir a IAM

    4. Haz clic en Conceder acceso.
    5. En el campo Nuevos principales, especifique el siguiente valor:
      PROJECT_NUMBER-compute@developer.gserviceaccount.com
      Sustituye PROJECT_NUMBER por el número de proyecto que has copiado.
    6. En el menú Seleccionar un rol, elige el rol Cuenta de servicio de nodo predeterminada de Kubernetes Engine.
    7. Haz clic en Guardar.

    gcloud

    1. Busca tu Google Cloud número de proyecto:
      gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)"

      Sustituye PROJECT_ID por el ID del proyecto.

      El resultado debería ser similar al siguiente:

      12345678901
      
    2. Asigna el rol roles/container.defaultNodeServiceAccount a la cuenta de servicio predeterminada de Compute Engine:
      gcloud projects add-iam-policy-binding PROJECT_ID \
          --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
          --role="roles/container.defaultNodeServiceAccount"

      Sustituye PROJECT_NUMBER por el número de proyecto del paso anterior.

Error 403: permisos insuficientes

Se produce el siguiente error cuando intentas conectarte a un clúster de GKE mediante gcloud container clusters get-credentials, pero la cuenta no tiene permiso para acceder al servidor de la API de 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 solucionar este problema, siga estos pasos:

  1. Identifica la cuenta que tiene el problema de acceso:

    gcloud auth list
    
  2. Concede el acceso necesario a la cuenta siguiendo las instrucciones de Autenticar en el servidor de la API de Kubernetes.

Error 403: se ha agotado el presupuesto de reintentos

El siguiente error puede producirse al intentar crear un clúster de GKE:

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

En este mensaje de error, se aplican las siguientes variables:

  • PERMISSION_NAME: el nombre de un permiso, como compute.regions.get.
  • RESOURCE_NAME: la ruta al recurso Google Cloud al que intentabas acceder, como una región de Compute Engine.

Este error se produce si la cuenta de servicio de gestión de identidades y accesos asociada al clúster no tiene los permisos mínimos necesarios para crear el clúster.

Para solucionar este problema, sigue estos pasos:

  1. Crea o modifica una cuenta de servicio de gestión de identidades y accesos para que tenga todos los permisos necesarios para ejecutar un clúster de GKE. Para ver instrucciones, consulta Usar cuentas de servicio de IAM con el mínimo de privilegios.
  2. Especifica la cuenta de servicio de IAM actualizada en el comando de creación del clúster mediante la marca --service-account. Para obtener instrucciones, consulta Crear un clúster de Autopilot.

También puedes omitir la marca --service-account para que GKE use la cuenta de servicio predeterminada de Compute Engine en el proyecto, que tiene los permisos necesarios de forma predeterminada.

Error 404: recurso no encontrado

Si recibes un error 404 (recurso no encontrado) al llamar a gcloud container comandos, resuelve el problema volviendo a autenticarte en Google Cloud CLI:

gcloud auth login

Error 400/403: Faltan permisos de edición en la cuenta

Si aparece el error "La cuenta no tiene permisos de edición" (error 400 o 403), significa que se ha eliminado o editado manualmente uno de los siguientes elementos:

Cuando habilitas la API de Compute Engine o GKE, Google Cloud se crean las siguientes cuentas de servicio y agentes:

  • Cuenta de servicio predeterminada de Compute Engine en tu proyecto. GKE adjunta esta cuenta de servicio a los nodos de forma predeterminada para tareas del sistema, como el registro y la monitorización.
  • Agente de servicio de las APIs de Google en un proyecto gestionado por Google, con permisos de edición en tu proyecto.
  • Agente de servicio de Google Kubernetes Engine en un proyecto gestionado por Google, con el rol Agente de servicio de Kubernetes Engine en tu proyecto.

La creación de clústeres y toda la gestión fallarán si, en algún momento, alguien edita esos permisos, elimina las vinculaciones de roles del proyecto, elimina la cuenta de servicio por completo o inhabilita la API.

Verificar los permisos del agente de servicio de GKE

Para comprobar si la cuenta de servicio de Google Kubernetes Engine tiene asignado el rol Agente de servicio de Kubernetes Engine en el proyecto, sigue estos pasos:

  1. Determina el nombre de tu cuenta de servicio de Google Kubernetes Engine. Todas las cuentas de servicio tienen el siguiente formato:

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

    Sustituye PROJECT_NUMBER por tu número de proyecto.

  2. Verifica que tu cuenta de servicio de Google Kubernetes Engine no tenga asignado el rol Agente de servicio de Kubernetes Engine en el proyecto:

    gcloud projects get-iam-policy PROJECT_ID
    

    Sustituye PROJECT_ID por el ID del proyecto.

Para solucionar el problema, si alguien ha quitado el rol Agente de servicio de Kubernetes Engine de tu cuenta de servicio de Google Kubernetes Engine, vuelve a añadirlo. De lo contrario, sigue estas instrucciones para volver a habilitar la API Kubernetes Engine, lo que restaurará tus cuentas de servicio y permisos:

Consola

  1. Ve a la página APIs y servicios de la Google Cloud consola.

    Ir a APIs y servicios

  2. Selecciona el proyecto.

  3. Haz clic en Habilitar APIs y servicios.

  4. Busca Kubernetes y, a continuación, selecciona la API en los resultados de búsqueda.

  5. Haz clic en Enable (Habilitar). Si ya has habilitado la API, primero debes inhabilitarla y, después, volver a habilitarla. Las APIs y los servicios relacionados pueden tardar varios minutos en habilitarse.

gcloud

Ejecuta los siguientes comandos en gcloud CLI:

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

Siguientes pasos