Parar de usar a porta somente leitura do kubelet não segura 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 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.

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 Google Cloud CLI para essa tarefa, instale e, em seguida, inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando gcloud components update.

Verificar se os aplicativos estão usando a porta

Antes de desativar a porta, verifique se os aplicativos no cluster não estão acessando a porta somente leitura. Se você desativar a porta enquanto uma carga de trabalho ainda precisar de acesso a um endpoint, a carga de trabalho poderá falhar.

  1. Obtenha uma lista de nós no cluster:

    kubectl get nodes
    
  2. Para cada nó, verifique as métricas do servidor HTTP kubelet:

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

    Se um aplicativo estiver enviando solicitações para a porta somente leitura, a saída será semelhante a esta:

    kubelet_http_requests_total{long_running="false",method="GET",path="metrics",server_type="readonly"} 2549
    kubelet_http_requests_total{long_running="false",method="GET",path="metrics/probes",server_type="readonly"} 2546
    kubelet_http_requests_total{long_running="false",method="GET",path="pods",server_type="readonly"} 1
    

    Para interromper esse uso, consulte Impedir que os aplicativos usem a porta somente leitura.

    Se a saída estiver em branco, pule para Desativar a porta somente leitura no cluster.

Impedir que os aplicativos usem a porta somente leitura

Se você tiver um aplicativo de terceiros que usa a porta somente leitura, verifique na documentação do fornecedor uma opção para usar a porta kubelet autenticada.

Na maioria dos cenários, é preciso fazer as seguintes alterações no aplicativo para impedir que ele use a porta somente leitura:

  1. Atualize o URL ou os endpoints que se referem à porta somente leitura. Por exemplo, é possível alterar as referências do endpoint do nó, como http://192.0.2.167:10255, para https://192.0.2.167:10250.
  2. Defina o certificado de CA do cliente HTTP como o certificado de CA do cluster. Para conseguir esse certificado de CA, use um dos seguintes métodos:

  3. Atualize o mecanismo de autorização no cluster, como as regras do RBAC, para que o aplicativo conceda as permissões apropriadas no recurso nodes/* ou para sub-recursos específicos. Para ver uma lista de sub-recursos, consulte a autorização do kubelet.

Depois de atualizar seus aplicativos, verifique novamente o uso da porta somente leitura para verificar se a saída está em branco. Em seguida, desative a porta somente leitura no cluster.

Exemplo de migração de aplicativos

O exemplo a seguir modifica um pod que consulta métricas a partir da porta somente leitura do kubelet. Essas solicitações não são autenticadas, portanto, qualquer aplicativo que possa alcançar endpoints do nó também pode enviar qualquer consulta.

  1. Salve o seguinte manifesto como example-readonly.yaml:

    apiVersion: v1
    kind: Pod
    metadata:
      name: kubelet-readonly-example
    spec:
      restartPolicy: Never
      containers:
      - name: kubelet-readonly-example
        image: gcr.io/cloud-builders/curl:latest
        command:
          - curl
          - http://$(NODE_ADDRESS):10255/metrics
        env:
        - name: NODE_ADDRESS
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
    

    Esse pod executa um comando curl para receber o endpoint /metrics na porta somente leitura do kubelet.

  2. Aplique o manifesto:

    kubectl create -f example-readonly.yaml
    
  3. Verifique os registros do pod:

    kubectl logs -f kubelet-readonly-example
    

    A saída contém métricas de nó e é semelhante a esta:

    # HELP apiserver_audit_event_total [ALPHA] Counter of audit events generated and sent to the audit backend.
    # TYPE apiserver_audit_event_total counter
    ...
    kubelet_runtime_operations_total{operation_type="container_status"} 93
    ...
    
  4. Crie um ClusterRole que conceda acesso get às métricas do nó:

    1. Salve o seguinte manifesto como metrics-role.yaml:

      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: curl-authenticated-role
      rules:
      - apiGroups:
        - ""
        resources:
        - nodes/metrics
        verbs:
        - get
      
    2. Aplique o manifesto:

      kubectl create -f metrics-role.yaml
      
  5. Vincule o ClusterRole à identidade do aplicativo, como a ServiceAccount:

    1. Salve o seguinte manifesto como metrics-binding.yaml:

      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
      subjects:
      - kind: ServiceAccount
        name: default
        namespace: default
      

      Neste exemplo, o ClusterRole é vinculado ao ServiceAccount default no namespace default.

    2. Aplique o manifesto:

      kubectl create -f metrics-binding.yaml
      
  6. Modifique o manifesto example-readonly.yaml da seguinte maneira:

    apiVersion: v1
    kind: Pod
    metadata:
      name: kubelet-authenticated-example
    spec:
      restartPolicy: Never
      containers:
      - name: kubelet-readonly-example
        image: gcr.io/cloud-builders/curl:latest
        env:
        - name: NODE_ADDRESS
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        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'
    

    O comando que o pod envia para a API kubelet inclui o seguinte:

    • O certificado de CA do cluster localizado em /var/run/secrets/kubernetes.io/ca.crt para autenticar a solicitação.
    • O token do portador ServiceAccount localizado em /var/run/secrets/kubernetes.io/serviceaccount/token para autorizar a solicitação.
  7. Implante o manifesto atualizado:

    kubectl apply -f example-readonly.yaml
    

Desative a porta somente leitura no cluster

É possível desativar a porta somente leitura do kubelet não segura em clusters padrão novos ou atuais e em novos clusters do Autopilot. Não é possível desativar a porta em clusters do Autopilot atuais.

Os seguintes requisitos de versão são aplicáveis:

  • Só é possível desativar a porta no nível do cluster nas versões 1.26.4-gke.500 e posteriores do GKE e 1.27 e posteriores.
  • Use a versão 439 ou posterior da CLI gcloud.
  1. Verifique se você tem a versão mais recente da CLI gcloud. Para atualizar a CLI gcloud, consulte Instalar a CLI gcloud.

  2. Desative a porta para todos os nós no cluster:

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

    Substitua:

    • CLUSTER_NAME: o nome do cluster.
    • LOCATION_NAME: a região ou zona do Compute Engine do cluster, como us-central1.

    Esse comando substitui todas as configurações no nível do nó da porta somente leitura, incluindo aquelas especificadas no arquivo de configuração do kubelet.

    Para desativar a porta ao criar um novo cluster, especifique o flag --no-enable-insecure-kubelet-readonly-port no comando de criação.

Verifique se a porta está desativada

Para verificar se a porta está desativada, use o manifesto da seção "Migração de exemplo".

  1. Salve o seguinte manifesto como readonly-verify.yaml:

    apiVersion: v1
    kind: Pod
    metadata:
      name: kubelet-readonly-verify
    spec:
      restartPolicy: Never
      containers:
      - name: kubelet-readonly-verify
        image: gcr.io/cloud-builders/curl:latest
        command:
          - curl
          - http://$(NODE_ADDRESS):10255/metrics
        env:
        - name: NODE_ADDRESS
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
    
  2. Aplique o manifesto:

    kubectl create -f readonly-verify.yaml
    
  3. Verifique os registros do pod:

    kubectl logs -f kubelet-readonly-verify
    

Se a porta estiver desativada, você verá um erro semelhante a este:

curl: (7) Failed to connect to NODE_ADDRESS port 10255: Connection refused

Se a porta ainda estiver ativada, você verá um resultado de métricas de nó semelhante a este:

# HELP apiserver_audit_event_total [ALPHA] Counter of audit events generated and sent to the audit backend.
# TYPE apiserver_audit_event_total counter
...
kubelet_runtime_operations_total{operation_type="container_status"} 93
...

Nesse caso, verifique se o cluster atende aos requisitos de versão e se você está usando a versão mais recente da CLI gcloud.

A seguir