Garantire la compatibilità dei certificati webhook prima di eseguire l'upgrade alla versione 1.23

A partire dalla versione 1.23, Kubernetes non supporta più la convalida dell'identità del server utilizzando il campo Common Name (CN) X.509 nei certificati. Kubernetes si baserà solo sulle informazioni contenute nei campi SAN (Subject Alternative Name) X.509.

Per evitare problemi ai tuoi cluster, devi sostituire i certificati incompatibili senza SAN per i backend di webhook e server API aggregati prima di eseguire l'upgrade dei cluster a Kubernetes versione 1.23.

Perché Kubernetes non supporta più i certificati di backend senza SAN

GKE utilizza Kubernetes open source, che utilizza il componente kube-apiserver per contattare i backend del webhook e del server API aggregato utilizzando Transport Layer Security (TLS). Il componente kube-apiserver è scritto nel linguaggio di programmazione Go.

Prima di Go 1.15, i client TLS convalidavano l'identità dei server a cui si connettevano utilizzando una procedura in due passaggi:

  1. Controlla se il nome DNS (o l'indirizzo IP) del server è presente come uno dei SAN nel certificato del server.
  2. In alternativa, verifica se il nome DNS (o l'indirizzo IP) del server è uguale al nome comune (CN) del certificato del server.

Il documento RFC 6125 ha ritirato completamente la convalida dell'identità del server basata sul campo CN nel 2011. I browser e altre applicazioni critiche per la sicurezza non utilizzano più il campo.

Per allinearsi all'ecosistema TLS più ampio, Go 1.15 ha rimosso il passaggio 2 dal processo di convalida, ma ha lasciato un'opzione di debug (x509ignoreCN=0) per attivare il vecchio comportamento per semplificare il processo di migrazione. Kubernetes versione 1.19 è stata la prima versione creata utilizzando Go 1.15. I cluster GKE sulle versioni da 1.19 a 1.22 hanno abilitato l'opzione di debug per impostazione predefinita per fornire ai clienti più tempo per sostituire i certificati per i backend webhook e server API aggregati interessati.

Kubernetes versione 1.23 è creato con Go 1.17, che rimuove l'opzione di debug. Una volta che GKE esegue l'upgrade dei cluster alla versione 1.23, le chiamate non riusciranno a connettersi dal control plane del cluster ai webhook o ai servizi API aggregati che non forniscono un certificato X.509 valido con SAN appropriato.

Identificazione dei cluster interessati

Per i cluster che eseguono versioni patch almeno 1.21.9 o 1.22.3

Per i cluster sulle versioni patch 1.21.9 e 1.22.3 o successive con Cloud Logging abilitato, GKE fornisce un log Cloud Audit Logs per identificare le chiamate ai backend interessati dal tuo cluster. Puoi utilizzare il seguente filtro per cercare i log:

logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"

Se i tuoi cluster non hanno richiamato i backend con i certificati interessati, non vedrai alcun log. Se visualizzi un log di controllo di questo tipo, includerà il nome host del backend interessato.

Di seguito è riportato un esempio di voce di log per un backend webhook ospitato da un servizio denominato example-webhook nello spazio dei nomi default:

{
  ...
  resource {
    type: "k8s_cluster",
    "labels": {
      "location": "us-central1-c",
      "cluster_name": "example-cluster",
      "project_id": "example-project"
    }
  },
  labels: {
    invalid-cert.webhook.gke.io/example-webhook.default.svc: "No subjectAltNames returned from example-webhook.default.svc:8443",
    ...
  },
  logName: "projects/example-project/logs/cloudaudit.googleapis.com%2Factivity",
  operation: {
    ...
    producer: "k8s.io",
    ...
  },
  ...
}

I nomi host dei servizi interessati (ad es. example-webhook.default.svc) sono inclusi come suffissi nei nomi delle etichette che iniziano con invalid-cert.webhook.gke.io/. Puoi anche ottenere il nome del cluster che ha effettuato la chiamata dall'etichetta resource.labels.cluster_name, che ha il valore example-cluster in questo esempio.

Approfondimenti sul ritiro

Puoi scoprire quali cluster utilizzano certificati incompatibili dagli approfondimenti sul ritiro. Gli approfondimenti sono disponibili per i cluster che eseguono la versione 1.22.6-gke.1000 o successive.

Altre versioni del cluster

Se hai un cluster con una versione patch precedente alla 1.22.3 nella versione secondaria 1.22 o una versione patch precedente alla 1.21.9, hai due opzioni per determinare se il tuo cluster è interessato da questo ritiro:

Opzione 1 (consigliata): Esegui l'upgrade del cluster a una versione patch che supporta l'identificazione dei certificati interessati con i log. Assicurati che Cloud Logging sia abilitato per il tuo cluster. Dopo l'upgrade del cluster, i log di Cloud Audit Logs identificativi verranno generati ogni volta che il cluster tenta di chiamare un servizio che non fornisce un certificato con un SAN appropriato. Poiché i log verranno prodotti solo in caso di tentativo di chiamata, ti consigliamo di attendere 30 giorni dopo un upgrade per consentire l'invocazione di tutti i percorsi di chiamata.

L'utilizzo dei log per identificare i servizi interessati è consigliato perché questo approccio riduce al minimo l'intervento manuale producendo automaticamente i log per mostrare i servizi interessati.

Opzione 2: esamina i certificati utilizzati dai webhook o dai server API aggregati nei tuoi cluster per determinare se sono interessati perché non hanno SAN:

  1. Ottieni l'elenco di webhook e server API aggregati nel tuo cluster e identifica i relativi backend (servizi o URL).
  2. Ispeziona i certificati utilizzati dai servizi di backend.

Considerando l'impegno manuale necessario per ispezionare tutti i certificati in questo modo, questo metodo deve essere seguito solo se devi valutare l'impatto dei ritiri nella versione 1.23 di Kubernetes prima di eseguire l'upgrade del cluster alla versione 1.21. Se puoi eseguire l'upgrade del cluster alla versione 1.21, ti consigliamo di farlo prima e poi seguire le istruzioni dell'opzione 1 per evitare l'intervento manuale.

Identificazione dei servizi di backend da esaminare

Per identificare i backend che potrebbero essere interessati dal ritiro, recupera l'elenco di webhook e servizi API aggregati e i relativi backend nel cluster.

Per elencare tutti i webhook pertinenti nel cluster, utilizza i seguenti comandi kubectl:

kubectl get mutatingwebhookconfigurations -A   # mutating admission webhooks

kubectl get validatingwebhookconfigurations -A # validating admission webhooks

Puoi ottenere un servizio o un URL di backend associato per un determinato webhook esaminando il campo clientConfig.service o il campo webhooks.clientConfig.url nella configurazione del webhook:

kubectl get mutatingwebhookconfigurations example-webhook -o yaml

L'output di questo comando è simile al seguente:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- admissionReviewVersions:
  clientConfig:
    service:
        name: example-service
        namespace: default
        port: 443

Tieni presente che clientConfig può specificare il backend come servizio Kubernetes (clientConfig.service) o come URL (clientConfig.url).

Per elencare tutti i servizi API aggregati pertinenti nel cluster, utilizza il seguente comando kubectl:

kubectl get apiservices -A |grep -v Local      # aggregated API services

L'output di questo comando è simile al seguente:

NAME                     SERVICE                      AVAILABLE   AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   True        237d

Questo esempio restituisce il servizio metric-server dallo spazio dei nomi kube-system.

Puoi ottenere un servizio associato per una determinata API aggregata esaminando il campo spec.service:

kubectl get apiservices v1beta1.metrics.k8s.io -o yaml

L'output di questo comando è simile al seguente:

...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
  service:
    name: metrics-server
    namespace: kube-system
    port: 443

Ispezione del certificato di un servizio

Una volta identificati i servizi di backend pertinenti da esaminare, puoi esaminare il certificato di ogni servizio specifico, ad esempio example-service:

  1. Trova il selettore e la porta di destinazione del servizio:

    kubectl describe service example-service
    

    L'output di questo comando è simile al seguente:

    Name: example-service
    Namespace: default
    Labels: run=nginx
    Selector: run=nginx
    Type: ClusterIP
    IP: 172.21.xxx.xxx
    Port: 443
    TargetPort: 444
    

    In questo esempio, example-service ha il selettore run=nginx e la porta di destinazione 444.

  2. Trova un pod corrispondente al selettore:

    kubectl get pods --selector=run=nginx
    

    L'output di questo comando è simile al seguente:

    NAME          READY   STATUS    RESTARTS   AGE
    example-pod   1/1     Running   0          21m
    
  3. Configura un port forwarding

    dal tuo localhost kubectl al pod.

    kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
    

    Sostituisci quanto segue nel comando:

    • LOCALHOST_PORT: l'indirizzo da ascoltare.
    • TARGET_PORT il TargetPort del passaggio 1.
  4. Utilizza openssl per stampare il certificato utilizzato dal servizio:

    openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
    

    Questo output di esempio mostra un certificato valido (con voci SAN):

    Subject: CN = example-service.default.svc
    X509v3 extensions:
      X509v3 Subject Alternative Name:
        DNS:example-service.default.svc
    

    Questo output di esempio mostra un certificato con un SAN mancante:

    Subject: CN = example-service.default.svc
      X509v3 extensions:
          X509v3 Key Usage: critical
              Digital Signature, Key Encipherment
          X509v3 Extended Key Usage:
              TLS Web Server Authentication
          X509v3 Authority Key Identifier:
              keyid:1A:5F:29:D8:E9:3C:54:3C:35:CC:D8:AB:D1:21:FD:C3:56:25:C0:74
    
  5. Rimuovi l'inoltro delle porte dall'esecuzione in background con i seguenti comandi:

    $ jobs
    [1]+  Running                 kubectl port-forward pods/example-pod 8888:444 &
    $ kill %1
    [1]+  Terminated              kubectl port-forward pods/example 8888:444
    

Ispezione del certificato di un backend URL

Se il webhook utilizza un url backend, connettiti direttamente al nome host specificato nell'URL. Ad esempio, se l'URL è https://example.com:123/foo/bar, utilizza il seguente comando openssl per stampare il certificato utilizzato dal backend:

  openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text

Mitigazione del rischio di upgrade alla versione 1.23

Dopo aver identificato i cluster interessati e i relativi servizi di backend che utilizzano certificati senza SAN, devi aggiornare i webhook e i backend del server API aggregato in modo che utilizzino certificati con SAN appropriate prima di eseguire l'upgrade dei cluster alla versione 1.23.

GKE non eseguirà automaticamente l'upgrade dei cluster nelle versioni 1.22.6-gke.1000 o successive con backend che utilizzano certificati incompatibili finché non sostituisci i certificati o finché la versione 1.22 non raggiunge la fine del supporto standard.

Se il cluster utilizza una versione di GKE precedente alla 1.22.6-gke.1000, puoi impedire temporaneamente gli upgrade automatici configurando un'esclusione della manutenzione per impedire gli upgrade secondari.

Risorse

Per ulteriori informazioni su questa modifica, consulta le seguenti risorse:

  • Note di rilascio di Kubernetes 1.23
    • Kubernetes è creato utilizzando Go 1.17. Questa versione di Go rimuove la possibilità di utilizzare un'impostazione dell'ambiente GODEBUG=x509ignoreCN=0 per riattivare il comportamento legacy deprecato di considerare il CN dei certificati di servizio X.509 come nome host.
  • Note di rilascio di Kubernetes 1.19 e Kubernetes 1.20
    • Il comportamento precedente e deprecato di considerare il campo CN dei certificati di servizio X.509 come nome host quando non sono presenti SAN è ora disattivato per impostazione predefinita.
  • Note di rilascio di Go 1.17
    • Il contrassegno temporaneo GODEBUG=x509ignoreCN=0 è stato rimosso.
  • Note di rilascio di Go 1.15
    • Il comportamento legacy deprecato di considerare il campo CN dei certificati X.509 come host quando non sono presenti SAN è ora disattivato per impostazione predefinita.
  • RFC 6125 (pagina 46)
    • Sebbene l'utilizzo del valore CN sia una pratica esistente, è deprecato e le autorità di certificazione sono invitate a fornire invece valori subjectAltName.
  • Webhook di ammissione