Disattivare la porta di sola lettura di kubelet nei cluster GKE


Questa pagina mostra come disattivare la porta di sola lettura non sicura di kubelet nei cluster Google Kubernetes Engine (GKE) per ridurre il rischio di accesso non autorizzato al kubelet e come eseguire la migrazione delle applicazioni a una porta più sicura.

Nei cluster Kubernetes, incluso GKE, il processo kubelet in esecuzione sui nodi fornisce un'API di sola lettura utilizzando la porta non sicura 10255. Kubernetes non esegue controlli di autenticazione o autorizzazione su questa porta. Kubelet serve gli stessi endpoint sulla porta 10250 più sicura e autenticata.

Disattiva la porta di sola lettura di kubelet e imposta tutti i workload che utilizzano la porta10255 in modo che utilizzino invece la porta più sicura 10250.

Prima di iniziare

Prima di iniziare, assicurati di aver eseguito le seguenti operazioni:

  • Attiva l'API Google Kubernetes Engine.
  • Attiva l'API Google Kubernetes Engine
  • Se vuoi utilizzare Google Cloud CLI per questa attività, installa e poi inizializza gcloud CLI. Se hai già installato gcloud CLI, ottieni la versione più recente eseguendo gcloud components update.

Requisiti

  • Puoi disabilitare la porta in sola lettura non sicura di kubelet solo in GKE versione 1.26.4-gke.500 o successive.

Controlla se le porte sono usate in modo non sicuro ed esegui la migrazione delle applicazioni

Prima di disattivare la porta di sola lettura non sicura, esegui la migrazione di tutte le applicazioni in esecuzione che la utilizzano alla porta di sola lettura più sicura. I workload che potrebbero richiedere la migrazione includono le pipeline delle metriche personalizzate e i workload che accedono agli endpoint kubelet.

  • Per i carichi di lavoro che devono accedere alle informazioni fornite dall'API kubelet sul nodo, come le metriche, utilizza la porta 10250.
  • Per i workload che ricevono informazioni su Kubernetes utilizzando l'API kubelet sul nodo, ad esempio l'elenco dei pod sul nodo, utilizza l'API Kubernetes.

Controlla se le applicazioni utilizzano la porta di sola lettura non sicura di kubelet

Questa sezione mostra come verificare l'utilizzo di porte non sicure nel cluster.

Controllare l'utilizzo delle porte in modalità Autopilot

Per verificare l'utilizzo delle porte in un cluster Autopilot, assicurati di avere almeno un carico di lavoro che non sia un DaemonSet in esecuzione nel cluster. Se svolgi i passaggi che seguono su un cluster Autopilot vuoto, i risultati potrebbero non essere validi.

  1. Salva il seguente manifest come read-only-port-metrics.yaml:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: node-metrics-printer-namespace
    ---
    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
    subjects:
    - kind: ServiceAccount
      name: node-metrics-printer-sa
      namespace: node-metrics-printer-namespace
    ---
    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:
          serviceAccountName: node-metrics-printer-sa
          containers:
          - name: metrics-printer
            image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest
            command: ["sh", "-c"]
            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:
            - 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
    

    Questo manifest esegue le seguenti operazioni:

    1. Crea uno spazio dei nomi e configura i ruoli RBAC per consentire la lettura delle metriche del nodo.
    2. Esegue il deployment di un DaemonSet che controlla le metriche di kubelet per la porta di sola lettura non sicura.
  2. Esegui il deployment del manifest:

    kubectl create -f read-only-port-metrics.yaml
    
  3. Controlla i log di DaemonSet:

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

    Se l'output contiene risultati che contengono la stringa server_type=readonly, un'applicazione sta utilizzando la porta di sola lettura non sicura.

Controllare l'utilizzo delle porte in modalità standard

Esegui il seguente comando su almeno un nodo di ogni pool di nodi nel cluster:

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

Sostituisci NODE_NAME con il nome del nodo.

Se l'output contiene voci con la stringa server_type="readonly", possono verificarsi i seguenti scenari:

  • I carichi di lavoro sul nodo utilizzano la porta di sola lettura non sicura di kubelet.
  • Dopo aver disattivato la porta non sicura, il comando restituisce ancora la stringa server_type="readonly". Questo perché la metrica kubelet_http_requests_total rappresenta il numero cumulativo di richieste HTTP ricevute dal server kubelet dall'ultimo riavvio. Questo numero non viene reimpostato quando la porta non sicura è disattivata. Questo numero viene reimpostato dopo che GKE riavvia il server kubelet, ad esempio durante l'upgrade di un nodo. Per saperne di più, consulta la documentazione di riferimento sulle metriche Kubernetes.

Se l'output è vuoto, nessun carico di lavoro su quel nodo utilizza la porta di sola lettura non sicura.

Identificare i workload che utilizzano la porta di sola lettura non sicura di kubelet

Per identificare i carichi di lavoro che utilizzano la porta non sicura, controlla i file di configurazione del carico di lavoro, ad esempio ConfigMap e pod.

Esegui questi comandi:

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

Se l'output del comando non è vuoto, utilizza lo script seguente per identificare i nomi dei ConfigMap o dei pod che utilizzano la porta non sicura:

# 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

Una volta identificati i carichi di lavoro pertinenti, esegui la migrazione in modo che utilizzino la porta sicura 10250 completando i passaggi descritti nella sezione seguente.

Eseguire la migrazione dalla porta di sola lettura non sicura di kubelet

In genere, la migrazione di un'applicazione alla porta sicura prevede i seguenti passaggi:

  1. Aggiorna gli URL o gli endpoint che fanno riferimento alla porta di sola lettura non sicura in modo da utilizzare la porta di sola lettura sicura. Ad esempio, cambia http://203.0.113.104:10255 in http://203.0.113.104:10250.

  2. Imposta il certificato dell'autorità di certificazione (CA) del client HTTP sul certificato CA del cluster. Per trovare questo certificato, esegui il seguente comando:

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

    Sostituisci quanto segue:

    • CLUSTER_NAME: il nome del tuo cluster.
    • LOCATION: la posizione del cluster.

La porta autenticata 10250 richiede di concedere all'oggetto i ruoli RBAC appropriati per accedere alle risorse specifiche. Per maggiori dettagli, consulta la documentazione di Kubernetes sull'autorizzazione kubelet.

Se il tuo carico di lavoro utilizza l'endpoint /pods sulla porta di sola lettura non sicura di kubelet, devi concedere l'autorizzazione RBAC nodes/proxy per accedere all'endpoint sulla porta di kubelet sicura. nodes/proxy è un'autorizzazione potente che non puoi concedere nei cluster GKE Autopilot e che non dovresti concedere nei cluster GKE Standard. Utilizza l'API Kubernetes con un fieldSelector per il nome del nodo.

Se utilizzi applicazioni di terze parti che dipendono dalla porta di sola lettura non sicura di kubelet, rivolgiti al fornitore dell'applicazione per istruzioni sulla migrazione alla porta sicura 10250.

Esempio di migrazione

Considera un pod che esegue query sulle metriche dalla porta di sola lettura non sicura di Kubelet.

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

Questa applicazione esegue le seguenti operazioni:

  • Utilizza l'account di servizio default nello spazio dei nomi default
  • Esegue il comando curl sull'endpoint /metrics sul nodo.

Per aggiornare questo pod in modo che utilizzi la porta sicura 10250:

  1. Crea un ClusterRole con accesso per ottenere le metriche del nodo:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: curl-authenticated-role
    rules:
    - apiGroups:
      - ""
      resources:
      - nodes/metrics
      verbs:
      - get
    
  2. Associa ClusterRole all'identità della tua applicazione:

    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
    
  3. Aggiorna il comando curl per utilizzare l'endpoint della porta sicura con le intestazioni di autorizzazione corrispondenti:

    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
        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'
    

Modificare le regole firewall VPC

Se aggiorni i carichi di lavoro in modo che utilizzino la porta 10250, crea regole firewall in modo che i pod nel cluster possano raggiungere la porta negli intervalli di indirizzi IP dei nodi. Le regole del firewall devono:

  • Consenti il traffico in entrata alla porta TCP 10250 negli intervalli di indirizzi IP dei nodi dagli intervalli di indirizzi IP dei pod interni
  • Rifiuta il traffico in entrata alla porta TCP 10250 sugli intervalli di indirizzi IP del tuo nodo provenienti dalla rete internet pubblica.

Puoi utilizzare le seguenti regole firewall GKE predefinite come modello per i parametri da specificare nelle nuove regole:

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

Disattivare la porta di sola lettura non sicura sui cluster Autopilot

Puoi disattivare la porta di sola lettura non sicura di kubelet per i cluster Autopilot nuovi ed esistenti.

Disattivare la porta in sola lettura non sicura sui nuovi cluster Autopilot

Per disattivare la porta di sola lettura non sicura di kubelet quando crei un nuovo cluster Autopilot, utilizza il --no-autoprovisioning-enable-insecure-kubelet-readonly-port flag, come nel seguente comando:

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

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del nuovo cluster Autopilot.
  • LOCATION: la posizione del nuovo cluster Autopilot.

Disattivare la porta di sola lettura non sicura sui cluster Autopilot esistenti

Per disattivare la porta di sola lettura non sicura di kubelet in un cluster Autopilot esistente, utilizza il flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port, come nel comando seguente. Tutti i nodi nuovi ed esistenti nel cluster smettono di utilizzare la porta.

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

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del cluster esistente.
  • LOCATION: la posizione del cluster esistente.

Disattiva la porta di sola lettura non sicura sui cluster standard

Puoi disattivare la porta di sola lettura non sicura di kubelet per interi cluster standard o per singoli node pool. Ti consigliamo di disattivare la porta per l'intero cluster.

Se utilizzi il provisioning automatico dei nodi, i pool di nodi di cui è stato eseguito il provisioning automatico ereditano l'impostazione della porta specificata a livello di cluster. Se vuoi, puoi specificare un'impostazione diversa per i pool di nodi di cui è stato eseguito il provisioning automatico, ma ti consigliamo di disabilitare la porta su tutti i nodi del cluster.

Puoi anche utilizzare un file di configurazione di sistema del nodo per disattivare in modo dichiarativo la porta di sola lettura non sicura di kubelet. Se utilizzi questo file, non puoi utilizzare i comandi nelle sezioni seguenti per controllare l'impostazione di kubelet.

Disattivare la porta di sola lettura non sicura sui nuovi cluster standard

Per disattivare la porta di sola lettura non sicura di kubelet in un nuovo cluster Standard, utilizza il flag --no-enable-insecure-kubelet-readonly-port come nel seguente comando:

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

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del nuovo cluster standard.
  • LOCATION: la posizione del nuovo cluster standard.

Se vuoi, puoi aggiungere il flag --no-autoprovisioning-enable-insecure-kubelet-readonly-port per controllare separatamente l'impostazione di provisioning automatico dei nodi, ma sconsigliamo questo approccio. Questo flag avvia un aggiornamento graduale dei pool di nodi di cui è stato eseguito il provisioning automatico, che potrebbe causare interruzioni dei workload in esecuzione.

Disattivare la porta di sola lettura non sicura sui cluster standard esistenti

Per disattivare la porta di sola lettura non sicura di kubelet in un cluster Standard esistente, utilizza il flag --no-enable-insecure-kubelet-readonly-port come nel seguente comando. I nuovi node pool non utilizzeranno la porta non sicura. GKE non aggiorna automaticamente i pool di nodi esistenti.

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

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del cluster standard esistente.
  • LOCATION: la posizione del cluster standard esistente.

Disattivare la porta di sola lettura non sicura nei pool di nodi standard

Ti consigliamo di impostare l'impostazione della porta di sola lettura a livello di cluster in tutti i casi. Se hai disattivato la porta di sola lettura su un cluster esistente che aveva già dei node pool in esecuzione, utilizza il seguente comando per disattivare la porta su questi node pool.

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

Sostituisci quanto segue:

  • NODE_POOL_NAME: il nome del pool di nodi.
  • CLUSTER_NAME: il nome del cluster.
  • LOCATION: la posizione del cluster.

Verifica che la porta sia disattivata

Per verificare che la porta di sola lettura non sicura di kubelet sia disattivata, descrivi la risorsa GKE.

Controllare lo stato delle porte nei cluster Autopilot

Esegui questo comando:

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

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del tuo cluster Autopilot.
  • LOCATION: la posizione del tuo cluster Autopilot.

Se la porta è disabilitata, l'output è il seguente:

insecureKubeletReadonlyPortEnabled: false

Controllare lo stato della porta nei cluster standard

Lo stato della porta è disponibile nel campo nodePoolDefaults.nodeConfigDefaults.nodeKubeletConfig quando descrivi il tuo cluster utilizzando l'API GKE.

Nei cluster standard, vedrai anche un campo nodeConfig che imposta un valore per lo stato della porta di sola lettura di kubelet. Il campo nodeConfig è ritirato e si applica solo al pool di nodi predefinito creato da GKE quando crei un nuovo cluster in modalità standard. Lo stato della porta nel campo nodeConfig deprecato non si applica agli altri pool di nodi nel cluster.

Esegui questo comando:

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

Sostituisci quanto segue:

  • CLUSTER_NAME: il nome del tuo cluster standard.
  • LOCATION: la posizione del tuo cluster standard.

Se la porta è disabilitata, l'output è il seguente:

insecureKubeletReadonlyPortEnabled: false

Controllare lo stato della porta nei pool di nodi standard

Esegui questo comando:

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

Sostituisci quanto segue:

  • NODE_POOL_NAME: il nome del pool di nodi.
  • CLUSTER_NAME: il nome del cluster.
  • LOCATION: la posizione del cluster.

Se la porta è disabilitata, l'output è il seguente:

insecureKubeletReadonlyPortEnabled: false