Desativar a porta somente leitura do kubelet em clusters do GKE

Nesta página, mostramos como desativar a porta somente leitura do kubelet não segura em clusters do Google Kubernetes Engine (GKE) para reduzir o risco de acesso não autorizado ao kubelet e como migrar aplicativos para uma porta mais segura.

Em clusters do Kubernetes, incluindo o GKE, o processo kubelet do kubelet em execução nos nós exibe uma API somente leitura usando a porta não segura 10255. O Kubernetes não realiza nenhuma verificação de autenticação ou autorização nessa porta. O kubelet serve aos mesmos endpoints na porta 10250 mais segura e autenticada.

Desative a porta somente leitura do kubelet e mude todas as cargas de trabalho que usam a 10255 para usar a 10250, que é mais segura.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a CLI do Google Cloud para essa tarefa, instale e inicialize a gcloud CLI. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando o comando gcloud components update. Talvez as versões anteriores da CLI gcloud não sejam compatíveis com a execução dos comandos neste documento.

Requisitos

  • Só é possível desativar a porta somente leitura do kubelet não segura no GKE versão 1.26.4-gke.500 ou mais recente.

Verificar o uso de portas não seguras e migrar aplicativos

Antes de desativar a porta somente leitura não segura, migre todos os aplicativos em execução que usam a porta para a porta somente leitura mais segura. As cargas de trabalho que podem precisar de migração incluem pipelines de métricas personalizadas e cargas de trabalho que acessam endpoints do kubelet.

  • Para cargas de trabalho que precisam acessar as informações fornecidas pela API kubelet no nó, como métricas, use a porta 10250.
  • Para cargas de trabalho que recebem informações do Kubernetes usando a API kubelet no nó, como listar pods no nó, use a API Kubernetes.

Verificar se os aplicativos usam a porta somente leitura do kubelet não segura

Esta seção mostra como verificar o uso de portas não seguras no cluster.

Verificar o uso da porta no modo Autopilot

Para verificar o uso da porta em um cluster do Autopilot, verifique se há no mínimo uma carga de trabalho que não seja um DaemonSet em execução no cluster. Se você realizar as etapas a seguir em um cluster do Autopilot vazio, os resultados poderão ser inválidos.

  1. Salve o seguinte manifesto como read-only-port-metrics.yaml:

    # Create a namespace for the DaemonSet that checks for port usage.
    apiVersion: v1
    kind: Namespace
    metadata:
      name: node-metrics-printer-namespace
    ---
    # Grant access to read node metrics in the cluster.
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: node-metrics-printer-role
    rules:
    - apiGroups:
      - ""
      resources:
      - nodes/metrics
      verbs:
      - get
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: node-metrics-printer-binding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: node-metrics-printer-role
    # Bind the ClusterRole to the ServiceAccount that the DaemonSet will use.
    subjects:
    - kind: ServiceAccount
      name: node-metrics-printer-sa
      namespace: node-metrics-printer-namespace
    ---
    # Create a ServiceAccount for the DaemonSet.
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: node-metrics-printer-sa
      namespace: node-metrics-printer-namespace
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: node-metrics-printer
      namespace: node-metrics-printer-namespace
    spec:
      selector:
        matchLabels:
          app: node-metrics-printer
      template:
        metadata:
          labels:
            app: node-metrics-printer
        spec:
          # Assign the ServiceAccount to the DaemonSet.
          serviceAccountName: node-metrics-printer-sa
          containers:
          - name: metrics-printer
            image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest
            command: ["sh", "-c"]
            # Call the /metrics endpoint using the insecure kubelet read-only
            # port.
            args:
            - 'while true; do curl -s --cacert "${CA_CERT}" -H "Authorization: Bearer $(cat ${TOKEN_FILE})" "https://${NODE_ADDRESS}:10250/metrics"|grep kubelet_http_requests_total; sleep 20; done'
            env:
            # Provide credentials and the IP address for the command.
            - name: CA_CERT
              value: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
            - name: TOKEN_FILE
              value: /var/run/secrets/kubernetes.io/serviceaccount/token
            - name: NODE_ADDRESS
              valueFrom:
                fieldRef:
                  fieldPath: status.hostIP
    

    Esse manifesto faz o seguinte:

    1. Cria um namespace e configura papéis do RBAC para permitir a leitura de métricas de nó.
    2. Implanta um DaemonSet que verifica as métricas do kubelet para a porta somente leitura não segura.
  2. Implante o manifesto:

    kubectl create -f read-only-port-metrics.yaml
    
  3. Verifique os registros do DaemonSet:

    kubectl logs --namespace=node-metrics-printer-namespace \
        --all-containers --prefix \
        --selector=app=node-metrics-printer
    

    Se a saída tiver resultados que contêm a string server_type=readonly, um aplicativo está usando a porta somente leitura não segura.

Verificar o uso da porta no modo padrão

Execute o comando a seguir em pelo menos um nó em cada pool de nós no cluster:

kubectl get --raw /api/v1/nodes/NODE_NAME/proxy/metrics | grep http_requests_total | grep readonly

Substitua NODE_NAME pelo nome do nó.

Se a saída contiver entradas com a string server_type="readonly", os seguintes cenários poderão ocorrer:

  • As cargas de trabalho no nó usam a porta somente leitura do kubelet não segura.
  • Depois de desativar a porta sem segurança, o comando ainda retorna a string server_type="readonly". Isso porque a métrica kubelet_http_requests_total representa o número cumulativo de solicitações HTTP recebidas pelo servidor kubelet desde a última reinicialização. Esse número não é redefinido quando a porta sem segurança é desativada. Esse número é redefinido depois que o GKE reinicia o servidor kubelet, como durante um upgrade de nó. Para saber mais, consulte Referência de métricas do Kubernetes.

Se a saída estiver vazia, nenhuma carga de trabalho nesse nó usará a porta somente leitura não segura.

Identificar as cargas de trabalho que estão usando a porta somente leitura do kubelet não segura

Para identificar as cargas de trabalho que estão usando a porta sem segurança, verifique os arquivos de configuração da carga de trabalho, como ConfigMaps e pods.

Execute os comandos a seguir:

kubectl get pods --all-namespaces -o yaml | grep 10255
kubectl get configmaps --all-namespaces -o yaml | grep 10255

Se a saída do comando não estiver vazia, use o seguinte script para identificar os nomes dos ConfigMaps ou pods que estão usando a porta sem segurança:

# This function checks if a Kubernetes resource is using the insecure port 10255.
#
# Arguments:
#  $1 - Resource type (e.g., pod, configmap, )
#  $2 - Resource name
#  $3 - Namespace
#
# Output:
#  Prints a message indicating whether the resource is using the insecure port.
isUsingInsecurePort() {
  resource_type=$1
  resource_name=$2
  namespace=$3

  config=$(kubectl get $resource_type $resource_name -n $namespace -o yaml)

  # Check if kubectl output is empty
  if [[ -z "$config" ]]; then
    echo "No configuration file detected for $resource_type: $resource_name (Namespace: $namespace)"
    return
  fi

  if echo "$config" | grep -q "10255"; then
    echo "Warning: The configuration file ($resource_type: $namespace/$resource_name) is using insecure port 10255. It is recommended to migrate to port 10250 for enhanced security."
  else
    echo "Info: The configuration file ($resource_type: $namespace/$resource_name) is not using insecure port 10255."
  fi
}

# Get the list of ConfigMaps with their namespaces
configmaps=$(kubectl get configmaps -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | tail -n +2 | awk '{print $1"/"$2}')

# Iterate over each ConfigMap
for configmap in $configmaps; do
  namespace=$(echo $configmap | cut -d/ -f1)
  configmap_name=$(echo $configmap | cut -d/ -f2)
  isUsingInsecurePort "configmap" "$configmap_name" "$namespace"
done

# Get the list of Pods with their namespaces
pods=$(kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | tail -n +2 | awk '{print $1"/"$2}')

# Iterate over each Pod
for pod in $pods; do
  namespace=$(echo $pod | cut -d/ -f1)
  pod_name=$(echo $pod | cut -d/ -f2)
  isUsingInsecurePort "pod" "$pod_name" "$namespace"
done

Depois de identificar as cargas de trabalho relevantes, migre-as para usar a porta segura 10250 seguindo as etapas na seção abaixo.

Migrar da porta somente leitura do kubelet não segura

Normalmente, a migração de um aplicativo para a porta segura envolve as seguintes etapas:

  1. Atualize URLs ou endpoints que se referem à porta somente leitura não segura para usar a porta somente leitura segura. Por exemplo, altere http://203.0.113.104:10255 para http://203.0.113.104:10250.

  2. Defina o certificado de autoridade de certificação (CA) do cliente HTTP como o certificado de CA do cluster. Para encontrar esse certificado, execute o seguinte comando:

    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="value(masterAuth.clusterCaCertificate)"
    

    Substitua:

    • CLUSTER_NAME: o nome do cluster.
    • LOCATION: o local do cluster.

A porta autenticada 10250 exige que você conceda papéis RBAC adequados ao sujeito para acessar os recursos específicos. Para mais detalhes, consulte a documentação do Kubernetes em autorização do kubelet.

Se a carga de trabalho usar o endpoint /pods na porta somente leitura do kubelet não segura, será necessário conceder a permissão RBAC nodes/proxy para acessar o endpoint na porta segura do kubelet. nodes/proxy é uma permissão poderosa que não pode ser concedida em clusters do GKE Autopilot e não deve ser concedida em clusters do GKE Standard. Use a API Kubernetes com um fieldSelector para o nome do nó.

Se usar aplicativos de terceiros que dependem da porta somente leitura do kubelet não segura, consulte o fornecedor do aplicativo para saber como migrar para a porta segura 10250.

Exemplo de migração

Considere um pod que consulta métricas da porta somente leitura do kubelet não segura.

apiVersion: v1
kind: Pod
metadata:
  name: kubelet-readonly-example
spec:
  restartPolicy: Never
  containers:
  - name: kubelet-readonly-example
    image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest
    command:
      - curl
      - http://${NODE_ADDRESS}:10255/metrics
    env:
    - name: NODE_ADDRESS
      valueFrom:
        fieldRef:
          fieldPath: status.hostIP

Este aplicativo faz o seguinte:

  • Usa a conta de serviço default no namespace default
  • Executa o comando curl no endpoint /metrics do nó.

Para atualizar esse pod para usar a porta segura 10250, siga estas etapas:

  1. Crie um ClusterRole com acesso para receber as métricas do nó:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: curl-authenticated-role
    rules:
    # Grant access to read node metrics in the cluster.
    - apiGroups:
      - ""
      resources:
      - nodes/metrics
      verbs:
      - get
    
  2. Vincule o ClusterRole à identidade do aplicativo:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: curl-authenticated-role-binding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: curl-authenticated-role
    # Bind the ClusterRole to the default ServiceAccount in the default
    # namespace.
    subjects:
    - kind: ServiceAccount
      name: default
      namespace: default
    
  3. Atualize o comando curl para usar o endpoint de porta seguro com os cabeçalhos de autorização correspondentes:

    apiVersion: v1
    kind: Pod
    metadata:
      name: kubelet-authenticated-example
    spec:
      restartPolicy: Never
      containers:
      - name: kubelet-readonly-example
        image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest
        env:
        - name: NODE_ADDRESS
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        # Update the command to send a request with the ServiceAccount
        # credentials in the header.
        command:
        - sh
        - -c
        - 'curl -s --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization:
          Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://${NODE_ADDRESS}:10250/metrics'
    

Modificar regras de firewall da VPC

Se você atualizar os workloads para usar a porta 10250, crie regras de firewall para que os pods no cluster possam acessar a porta nos intervalos de endereços IP do nó. As regras do firewall precisam fazer o seguinte:

  • Permitir o tráfego de entrada na porta TCP 10250 nos intervalos de endereços IP do nó dos intervalos de endereços IP internos do pod
  • Negar o tráfego de entrada para a porta TCP 10250 nos intervalos de endereço IP do nó da Internet pública.

É possível usar as regras de firewall padrão do GKE a seguir como modelo para os parâmetros a serem especificados nas novas regras:

  • gke-[cluster-name]-[cluster-hash]-inkubelet
  • gke-[cluster-name]-[cluster-hash]-exkubelet

Desativar a porta somente leitura não segura em clusters do Autopilot

É possível desativar a porta somente leitura do kubelet não segura para clusters novos e atualizados do Autopilot.

Para desativar a porta somente leitura do kubelet não segura em um cluster do Autopilot, use a flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port, como no seguinte comando: Todos os nós novos e existentes no cluster param de usar a porta.

gcloud container clusters update CLUSTER_NAME \
    --location=LOCATION \
    --no-autoprovisioning-enable-insecure-kubelet-readonly-port

Substitua:

  • CLUSTER_NAME: o nome do cluster atual.
  • LOCATION: o local do cluster atual.

Também é possível usar a flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port ao criar um cluster com o comando gcloud container clusters create-auto.

Desativar a porta somente leitura não segura em clusters padrão

É possível desativar a porta somente leitura do kubelet não segura para clusters padrão inteiros ou para pools de nós individuais. Recomendamos desativar a porta para todo o cluster.

Se você usar o provisionamento automático de nós, os pools de nós provisionados automaticamente herdarão a configuração de porta especificada no nível do cluster. Você pode especificar uma configuração diferente para pools de nós provisionados automaticamente, mas recomendamos desativar a porta em todos os nós do cluster.

Também é possível usar um arquivo de configuração do sistema de nó para desativar de forma declarativa a porta somente leitura do kubelet não segura. Se você usar esse arquivo, não poderá usar os comandos nas seções a seguir para controlar a configuração do kubelet.

Desativar a porta somente leitura não segura em clusters padrão atuais

Para desativar a porta somente leitura do kubelet não segura em um cluster padrão atual, use a flag --no-enable-insecure-kubelet-readonly-port, como no comando abaixo. Os novos pools de nós não vão usar a porta não segura. O GKE não atualiza os pools de nós automaticamente.

gcloud container clusters update CLUSTER_NAME \
    --location=LOCATION \
    --no-enable-insecure-kubelet-readonly-port

Substitua:

  • CLUSTER_NAME: o nome do cluster padrão atual.
  • LOCATION: o local do cluster padrão atual.

Também é possível usar a flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port ao criar um cluster com o comando gcloud container clusters create.

Desativar a porta somente leitura não segura em pools de nós padrão

Recomendamos definir a configuração da porta somente leitura no nível do cluster em todos os casos. Se você desativou a porta somente leitura em um cluster que já tinha pools de nós em execução, use o comando a seguir para desativar a porta nesses pools de nós.

gcloud container node-pools update NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --no-enable-insecure-kubelet-readonly-port

Substitua:

  • NODE_POOL_NAME: o nome do pool de nós.
  • CLUSTER_NAME: o nome do cluster.
  • LOCATION: O local do cluster.

Verifique se a porta está desativada

Para verificar se a porta somente leitura do kubelet não segura está desativada, descreva o recurso do GKE.

Verificar o status da porta em clusters do Autopilot

Execute este comando:

gcloud container clusters describe CLUSTER_NAME \
    --location=LOCATION \
    --flatten=nodePoolAutoConfig \
    --format="value(nodeKubeletConfig)"

Substitua:

  • CLUSTER_NAME: o nome do cluster do Autopilot.
  • LOCATION: o local do cluster do Autopilot.

Se a porta estiver desativada, a saída será a seguinte:

insecureKubeletReadonlyPortEnabled: false

Verificar o status da porta em clusters padrão

O status da porta está disponível no campo nodePoolDefaults.nodeConfigDefaults.nodeKubeletConfig ao descrever o cluster usando a API GKE.

Em clusters padrão, também há um campo nodeConfig que define um valor para o status da porta somente leitura do kubelet. O campo nodeConfig foi descontinuado e se aplica apenas ao pool de nós padrão criado pelo GKE quando você cria um novo cluster no modo Padrão. O status da porta no campo nodeConfig descontinuado não se aplica a outros pools de nós no cluster.

Execute este comando:

gcloud container clusters describe CLUSTER_NAME \
    --location=LOCATION \
    --flatten=nodePoolDefaults.nodeConfigDefaults \
    --format="value(nodeKubeletConfig)"

Substitua:

  • CLUSTER_NAME: o nome do cluster padrão.
  • LOCATION: o local do cluster padrão.

Se a porta estiver desativada, a saída será a seguinte:

insecureKubeletReadonlyPortEnabled: false

Se a saída desse comando estiver em branco, a porta somente leitura kubelet não segura ainda poderá estar ativada. Para desativar a porta, execute o comando na seção Desativar a porta somente leitura não segura em clusters padrão atuais.

Verificar o status da porta em pools de nós padrão

Execute este comando:

gcloud container node-pools describe NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --flatten=config \
    --format="value(kubeletConfig)"

Substitua:

  • NODE_POOL_NAME: o nome do pool de nós.
  • CLUSTER_NAME: o nome do cluster.
  • LOCATION: O local do cluster.

Se a porta estiver desativada, a saída será a seguinte:

insecureKubeletReadonlyPortEnabled: false

Impedir o uso de portas inseguras com uma política da organização

É possível usar o serviço de política da organização para exigir que os clusters na sua organização, pasta ou projeto desativem a porta somente leitura kubelet não segura. Para aplicar esse requisito, crie uma restrição personalizada e faça referência a ela em uma política da organização. Para negar operações de criação ou atualização quando a porta somente leitura kubelet não segura está ativada, consulte estes exemplos:

  • A seguinte restrição personalizada nega operações de criação ou atualização de cluster se a porta somente leitura kubelet não segura estiver ativada:

    name: organizations/ORGANIZATION_ID/customConstraints/custom.disableClusterInsecureKubeletReadOnlyPort
    resourceTypes:
    - container.googleapis.com/Cluster
    methodTypes:
    - CREATE
    - UPDATE
    condition:
      "resource.NodeKubeletConfig.insecureKubeletReadonlyPortEnabled == true ||
      resource.AutoprovisioningNodePoolDefaults.insecureKubeletReadonlyPortEnabled == true ||
      resource.NodePoolAutoConfig.NodeKubeletConfig.insecureKubeletReadonlyPortEnabled == true"
    actionType: DENY
    displayName: Disable insecure kubelet read-only port
    description: All new and existing clusters must disable the insecure kubelet read-only port.
    

    Substitua ORGANIZATION_ID pelo ID da organização.

  • A seguinte restrição personalizada nega operações de criação ou atualização de pool de nós se a porta somente leitura kubelet não segura estiver ativada:

    name: organizations/ORGANIZATION_ID/customConstraints/custom.disableNodePoolInsecureKubeletReadOnlyPort
    resourceTypes:
    - container.googleapis.com/NodePool
    methodTypes:
    - CREATE
    - UPDATE
    condition: "resource.NodeConfig.NodeKubeletConfig.insecureKubeletReadonlyPortEnabled == true"
    actionType: DENY
    displayName: Disable insecure kubelet read-only port
    description: All new and existing node pools must disable the insecure kubelet read-only port.
    

    Substitua ORGANIZATION_ID pelo ID da organização.

Para mais informações sobre como criar uma restrição personalizada e aplicá-la em uma política da organização, consulte Restringir ações em recursos do GKE usando políticas personalizadas da organização.