Desative a porta só de leitura do kubelet em clusters do GKE

Esta página mostra como desativar a porta só de 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 aplicações para uma porta mais segura.

Nos clusters do Kubernetes, incluindo o GKE, o processo kubelet em execução nos nós disponibiliza uma API só de leitura através da porta não segura 10255. O Kubernetes não realiza verificações de autenticação nem autorização nesta porta. O kubelet serve os mesmos pontos finais na porta 10250 autenticada e mais segura.

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

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize-a. Se instalou anteriormente a CLI gcloud, execute gcloud components update para obter a versão mais recente.
  • Certifique-se de que tem um cluster do Autopilot ou Standard existente. Para criar um novo cluster, consulte o artigo Crie um cluster do Autopilot.

Requisitos

  • Só pode desativar a porta só de leitura do kubelet não segura no GKE versão 1.26.4-gke.500 ou posterior.

Verifique a utilização de portas não seguras e migre aplicações

Antes de desativar a porta de leitura apenas insegura, migre todas as aplicações em execução que usam a porta para a porta de leitura apenas mais segura. As cargas de trabalho que podem precisar de migração incluem pipelines de métricas personalizadas e cargas de trabalho que acedem a endpoints kubelet.

  • Para cargas de trabalho que precisam de acesso às informações disponibilizadas pela API kubelet no nó, como métricas, use a porta 10250.
  • Para cargas de trabalho que recebem informações do Kubernetes através da API kubelet no nó, como a listagem de pods no nó, use a API Kubernetes.

Verifique se as aplicações usam a porta só de leitura do kubelet insegura

Esta secção mostra-lhe como verificar a utilização de portas não seguras no seu cluster.

Verifique a utilização de portas no modo de piloto automático

Para verificar a utilização de portas num cluster do Autopilot, certifique-se de que tem, pelo menos, uma carga de trabalho que não seja um DaemonSet em execução no cluster. Se executar os seguintes passos num cluster do Autopilot vazio, os resultados podem ser inválidos.

  1. Guarde 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
    

    Este manifesto faz o seguinte:

    1. Cria um espaço de nomes e configura funções RBAC para permitir a leitura de métricas de nós.
    2. Implementa um DaemonSet que verifica as métricas do kubelet para a porta só de leitura não segura.
  2. Implemente o manifesto:

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

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

    Se o resultado tiver resultados que contenham a string server_type=readonly, uma aplicação está a usar a porta só de leitura não segura.

Verifique a utilização de portas no modo padrão

Execute o seguinte comando, pelo menos, num nó de cada conjunto de nós no seu 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", podem ocorrer os seguintes cenários:

  • As cargas de trabalho no nó usam a porta só de leitura do kubelet não segura.
  • Depois de desativar a porta não segura, o comando continua a devolver a string server_type="readonly". Isto deve-se ao facto de a métrica kubelet_http_requests_total representar o número cumulativo de pedidos HTTP recebidos pelo servidor kubelet desde o último reinício. Este número não é reposto quando a porta não segura é desativada. Este número é reposto depois de o GKE reiniciar o servidor kubelet, como durante uma atualização de nós. Para saber mais, consulte a referência de métricas do Kubernetes.

Se o resultado estiver vazio, nenhuma carga de trabalho nesse nó usa a porta só de leitura não segura.

Identifique as cargas de trabalho que estão a usar a porta só de leitura do kubelet não segura

Para identificar as cargas de trabalho que estão a usar a porta não segura, verifique os ficheiros de configuração da carga de trabalho, como ConfigMaps e pods.

Execute os seguintes comandos:

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

Se o resultado do comando não estiver vazio, use o seguinte script para identificar os nomes dos ConfigMaps ou dos Pods que estão a usar a porta não segura:

# 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 concluindo os passos na secção seguinte.

Migre da porta só de leitura do kubelet não segura

Normalmente, a migração de uma aplicação para a porta segura envolve os seguintes passos:

  1. Atualize os URLs ou os pontos finais que fazem referência à porta só de leitura não segura para usar, em alternativa, a porta só de leitura segura. Por exemplo, altere http://203.0.113.104:10255 para http://203.0.113.104:10250.

  2. Defina o certificado da autoridade de certificação (AC) do cliente HTTP para o certificado da AC do cluster. Para encontrar este certificado, execute o seguinte comando:

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

    Substitua o seguinte:

    • CLUSTER_NAME: o nome do cluster.
    • LOCATION: a localização do seu cluster.

A porta autenticada 10250 requer que conceda funções RBAC adequadas ao assunto para aceder aos recursos específicos. Para ver detalhes, na documentação do Kubernetes, consulte o artigo Autorização do Kubelet.

Se a sua carga de trabalho usar o ponto final /pods na porta só de leitura do kubelet não segura, tem de conceder a autorização nodes/proxy RBAC para aceder ao ponto final na porta segura do kubelet. nodes/proxy é uma autorização poderosa que não pode conceder em clusters do GKE Autopilot e que não deve conceder em clusters do GKE Standard. Em alternativa, use a API Kubernetes com um fieldSelector para o nome do nó.

Se usar aplicações de terceiros que dependam da porta de leitura exclusiva do kubelet não segura, consulte o fornecedor da aplicação para obter instruções sobre como migrar para a porta segura 10250.

Exemplo de migração

Considere um Pod que consulte métricas da porta só de 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

Esta aplicação faz o seguinte:

  • Usa a default ServiceAccount no espaço de nomes default
  • Executa o comando curl no ponto final /metrics no nó.

Para atualizar este Pod para usar a porta segura 10250, siga estes passos:

  1. Crie um ClusterRole com acesso para obter métricas de nós:

    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. Associe o ClusterRole à identidade da sua aplicação:

    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 ponto final da porta segura 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'
    

Modifique as regras de firewall da VPC

Se atualizar as cargas de trabalho para usar a porta 10250, crie regras de firewall para que os pods no cluster possam alcançar a porta nos intervalos de endereços IP dos nós. As regras da firewall devem fazer o seguinte:

  • Permita o tráfego de entrada para a porta TCP 10250 nos intervalos de endereços IP do nó a partir dos intervalos de endereços IP do pod interno
  • Recuse o tráfego de entrada para a porta TCP 10250 nos intervalos de endereços IP do nó a partir da Internet pública.

Pode usar as regras de firewall do GKE predefinidas seguintes como um modelo para os parâmetros a especificar nas novas regras:

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

Desative a porta de leitura só de escrita não segura em clusters do Autopilot

Pode desativar a porta só de leitura do kubelet não segura para clusters do Autopilot novos e existentes.

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

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

Substitua o seguinte:

  • CLUSTER_NAME: o nome do seu cluster existente.
  • LOCATION: a localização do cluster existente.

Também pode usar a flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port quando criar um novo cluster usando o comando gcloud container clusters create-auto.

Desative a porta de leitura só de escrita não segura em clusters padrão

Pode desativar a porta só de leitura do kubelet não segura para clusters padrão completos ou para pools de nós individuais. Recomendamos que desative a porta para todo o cluster.

Se usar o aprovisionamento automático de nós, os conjuntos de nós aprovisionados automaticamente herdam a definição de porta especificada ao nível do cluster. Opcionalmente, pode especificar uma definição diferente para os conjuntos de nós aprovisionados automaticamente, mas recomendamos que desative a porta em todos os nós no cluster.

Também pode usar um ficheiro de configuração do sistema de nós para desativar declarativamente a porta só de leitura do kubelet insegura. Se usar este ficheiro, não pode usar os comandos nas secções seguintes para controlar a definição do kubelet.

Desative a porta de leitura insegura nos clusters padrão existentes

Para desativar a porta só de leitura do kubelet não segura num cluster Standard existente, use o sinalizador --no-enable-insecure-kubelet-readonly-port, como no comando seguinte. Todos os conjuntos de nós novos não usam a porta não segura. O GKE não atualiza automaticamente os conjuntos de nós existentes.

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

Substitua o seguinte:

  • CLUSTER_NAME: o nome do seu cluster padrão existente.
  • LOCATION: a localização do seu cluster padrão existente.

Também pode usar a flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port quando criar um novo cluster com o comando gcloud container clusters create.

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

Recomendamos que defina a definição de porta só de leitura ao nível do cluster em todos os casos. Se desativou a porta só de leitura num cluster existente que já tinha pools de nós em execução, use o seguinte comando 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 o seguinte:

  • NODE_POOL_NAME: o nome do seu node pool.
  • CLUSTER_NAME: o nome do cluster.
  • LOCATION: a localização do cluster.

Verifique se a porta está desativada

Para verificar se a porta só de leitura do kubelet insegura está desativada, descreva o recurso do GKE.

Verifique o estado da porta em clusters do Autopilot

Execute o seguinte comando:

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

Substitua o seguinte:

  • CLUSTER_NAME: o nome do seu cluster do Autopilot.
  • LOCATION: a localização do seu cluster do Autopilot.

Se a porta estiver desativada, a saída é a seguinte:

insecureKubeletReadonlyPortEnabled: false

Verifique o estado da porta em clusters padrão

O estado da porta está disponível no campo nodePoolDefaults.nodeConfigDefaults.nodeKubeletConfig quando descreve o cluster através da API GKE.

Nos clusters padrão, também é apresentado um campo nodeConfig que define um valor para o estado da porta só de leitura do kubelet. O campo nodeConfig está obsoleto e aplica-se apenas ao conjunto de nós predefinido que o GKE cria quando cria um novo cluster no modo Standard. O estado da porta no campo nodeConfig obsoleto não se aplica a outros conjuntos de nós no cluster.

Execute o seguinte comando:

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

Substitua o seguinte:

  • CLUSTER_NAME: o nome do seu cluster padrão.
  • LOCATION: a localização do seu cluster padrão.

Se a porta estiver desativada, a saída é a seguinte:

insecureKubeletReadonlyPortEnabled: false

Se o resultado deste comando estiver em branco, a porta kubelet só de leitura não segura pode ainda estar ativada. Para desativar a porta, execute o comando na secção Desative a porta de leitura insegura nos clusters padrão existentes.

Verifique o estado da porta nos conjuntos de nós padrão

Execute o seguinte comando:

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

Substitua o seguinte:

  • NODE_POOL_NAME: o nome do seu node pool.
  • CLUSTER_NAME: o nome do cluster.
  • LOCATION: a localização do cluster.

Se a porta estiver desativada, a saída é a seguinte:

insecureKubeletReadonlyPortEnabled: false