À partir de la version 1.23, Kubernetes n'accepte plus la validation de l'identité du serveur à l'aide du champ X.509 Common Name (CN) des certificats. À la place, Kubernetes ne s'appuiera que sur les informations du champ X.509 Subject Alternative Name (SAN).
Pour éviter tout impact sur vos clusters, vous devez remplacer les certificats incompatibles sans SAN pour les backends de webhooks et de serveurs d'API agrégés avant de mettre à niveau vos clusters vers la version 1.23 de Kubernetes.
Pourquoi Kubernetes n'accepte plus les certificats de backend sans SAN ?
GKE utilise Kubernetes Open Source, qui utilise le composant kube-apiserver pour contacter votre webhook et les backends de serveur d'API agrégés à l'aide de TLS (Transport Layer Security). Le composant kube-apiserver est écrit dans le langage de programmation Go.
Avant la version 1.15 de Go, les clients TLS validaient l'identité des serveurs auxquels ils étaient connectés à l'aide d'un processus en deux étapes :
- Ils vérifiaient si le nom DNS (ou l'adresse IP) du serveur était présent en tant que l'un des SAN sur le certificat du serveur.
- Comme alternative, ils vérifiaient si le nom DNS (ou l'adresse IP) du serveur était égal au CN sur le certificat du serveur.
Dans le cadre de la norme RFC 6125, la validation d'identité du serveur basée sur le champ CN est devenue entièrement obsolète en 2011. Les navigateurs et autres applications stratégiques pour la sécurité n'utilisent plus le champ.
Pour respecter l'écosystème TLS plus large, l'étape 2 a été supprimée du processus de validation dans la version 1.15 de Go. Cependant, le commutateur de débogage (x509ignoreCN=0
) a été conservé pour permettre à l'ancien comportement de faciliter le processus de migration. La version 1.19 de Kubernetes est la première version créée à l'aide de Go 1.15. Les clusters GKE sur les versions 1.19 à 1.22 ont activé le commutateur de débogage par défaut afin de donner aux clients plus de temps pour remplacer les certificats des backends de webhooks et de serveurs d'API agrégés concernés.
La version 1.23 de Kubernetes a été créée à l'aide de la version 1.17 de Go, qui supprime le commutateur de débogage. Une fois que GKE met à jour vos clusters vers la version 1.23, les appels ne parviennent pas à se connecter, depuis le plan de contrôle de votre cluster, aux webhooks ou aux services d'API agrégés qui ne fournissent pas de certificat X.509 valide avec le SAN approprié.
Identifier les clusters concernés
Pour les clusters exécutant au moins des versions de correctif 1.21.9 ou 1.22.3
Pour les clusters utilisant les versions de correctifs 1.21.9 et 1.22.3 (ou version ultérieure) avec Cloud Logging activé, GKE fournit un journal Cloud Audit Logs pour identifier les appels aux backends concernés de votre cluster. Vous pouvez utiliser le filtre suivant pour rechercher les journaux :
logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"
Si vos clusters n'ont pas appelé de backends avec des certificats concernés, aucun journal ne s'affiche. Si un tel journal d'audit s'affiche, il inclut le nom d'hôte du backend concerné.
Voici un exemple d'entrée de journal, pour un backend de webhook hébergé par un service nommé example-webhook dans l'espace de noms 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",
...
},
...
}
Les noms d'hôte des services concernés (par exemple example-webhook.default.svc
) sont inclus en tant que suffixes dans les noms de libellés commençant par invalid-cert.webhook.gke.io/
. Vous pouvez également obtenir le nom du cluster qui a effectué l'appel à partir du libellé resource.labels.cluster_name
, qui possède la valeur example-cluster
dans cet exemple.
Insights sur les abandons
Les insights d'abandon vous permettent d'identifier les clusters qui utilisent des certificats incompatibles. Les insights sont disponibles pour les clusters exécutant la version 1.22.6-gke.1000 ou ultérieure.
Autres versions de cluster
Si vous disposez d'un cluster sur une version de correctif antérieure à 1.22.3 sur la version mineure 1.22 ou sur une version de correctif antérieure à 1.21.9, vous avez deux options pour déterminer si votre cluster est affecté par cet abandon :
Option 1 (recommandée) : mettez à niveau votre cluster vers une version de correctif permettant d'identifier les certificats concernés à l'aide de journaux. Assurez-vous que Cloud Logging est activé pour votre cluster. Une fois votre cluster mis à niveau, les journaux Cloud Audit Logs d'identification sont générés chaque fois que le cluster tente d'appeler un service qui ne fournit pas de certificat associé à un SAN approprié. Comme les journaux ne sont générés que lors d'une tentative d'appel, nous vous recommandons d'attendre 30 jours après une mise à niveau afin de laisser suffisamment de temps pour que tous les chemins d'appel soient appelés.
Il est recommandé d'utiliser des journaux pour identifier les services concernés, car cette approche réduit les efforts manuels en générant automatiquement des journaux pour afficher les services concernés.
Option 2 : inspectez tous les certificats utilisés par les webhooks ou les services d'API agrégés dans vos clusters pour déterminer s'ils sont affectés par l'absence de SAN :
- Obtenez la liste des webhooks et des serveurs d'API agrégés dans votre cluster, puis identifiez leurs backends (services ou URL).
- Inspectez les certificats utilisés par les services.
Compte tenu des efforts manuels nécessaires pour inspecter tous les certificats de cette manière, cette méthode ne doit être suivie que si vous devez évaluer l'impact des abandons dans la version 1.23 de Kubernetes avant de mettre à niveau votre cluster vers la version 1.21. Si vous pouvez mettre à niveau votre cluster vers la version 1.21, vous devez d'abord le mettre à niveau, puis suivre les instructions de l'option 1 pour éviter les efforts manuels.
Identifier les services de backend à inspecter
Pour identifier les backends susceptibles d'être concernés par l'abandon, obtenez la liste des webhooks et des services d'API agrégés, ainsi que les backends associés dans le cluster.
Pour répertorier tous les webhooks pertinents dans le cluster, utilisez les commandes kubectl
suivantes :
kubectl get mutatingwebhookconfigurations -A # mutating admission webhooks
kubectl get validatingwebhookconfigurations -A # validating admission webhooks
Vous pouvez obtenir un service de backend ou une URL associés pour un webhook donné en examinant le champ clientConfig.service
ou le champ webhooks.clientConfig.url
dans la configuration du webhook :
kubectl get mutatingwebhookconfigurations example-webhook -o yaml
La sortie de la commande ressemble à ceci :
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- admissionReviewVersions:
clientConfig:
service:
name: example-service
namespace: default
port: 443
Notez que clientConfig peut spécifier son backend en tant que service Kubernetes (clientConfig.service
) ou en tant qu'URL (clientConfig.url
).
Pour répertorier tous les services d'API agrégés pertinents dans le cluster, utilisez la commande kubectl
suivante :
kubectl get apiservices -A |grep -v Local # aggregated API services
La sortie de la commande ressemble à ceci :
NAME SERVICE AVAILABLE AGE
v1beta1.metrics.k8s.io kube-system/metrics-server True 237d
Cet exemple renvoie le service metric-server
à partir de l'espace de noms kube-system
.
Vous pouvez obtenir un service associé pour une API agrégée donnée en examinant le champ spec.service
:
kubectl get apiservices v1beta1.metrics.k8s.io -o yaml
La sortie de la commande ressemble à ceci :
...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
service:
name: metrics-server
namespace: kube-system
port: 443
Inspecter le certificat d'un service
Une fois que vous avez identifié les services de backend pertinents à inspecter, vous pouvez inspecter le certificat de chaque service, tel que example-service
:
Recherchez le sélecteur et le port cible du service :
kubectl describe service example-service
La sortie de la commande ressemble à ceci :
Name: example-service Namespace: default Labels: run=nginx Selector: run=nginx Type: ClusterIP IP: 172.21.xxx.xxx Port: 443 TargetPort: 444
Dans cet exemple,
example-service
dispose du sélecteurrun=nginx
et du port cible444
.Recherchez un pod correspondant au sélecteur :
kubectl get pods --selector=run=nginx
La sortie de la commande ressemble à ceci :
NAME READY STATUS RESTARTS AGE example-pod 1/1 Running 0 21m
Configurez un transfert de port
de votre localhost
kubectl
au pod.kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
Remplacez les éléments suivants dans la commande :
LOCALHOST_PORT
: adresse à écouter.TARGET_PORT
: port cible (TargetPort
) de l'étape 1.
Utilisez
openssl
pour imprimer le certificat utilisé par le service :openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
Cet exemple de résultat montre un certificat valide (avec des entrées SAN) :
Subject: CN = example-service.default.svc X509v3 extensions: X509v3 Subject Alternative Name: DNS:example-service.default.svc
Cet exemple de résultat montre un certificat avec un SAN manquant :
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
Empêchez le transfert de port de s'exécuter en arrière-plan à l'aide des commandes suivantes :
$ jobs [1]+ Running kubectl port-forward pods/example-pod 8888:444 & $ kill %1 [1]+ Terminated kubectl port-forward pods/example 8888:444
Inspecter le certificat d'un backend d'URL
Si le webhook utilise un backend url
, connectez-vous directement au nom d'hôte spécifié dans l'URL. Par exemple, si l'URL est https://example.com:123/foo/bar
, utilisez la commande openssl
suivante pour imprimer le certificat utilisé par le backend :
openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text
Atténuer le risque de mise à niveau vers la version 1.23
Une fois que vous avez identifié les clusters et les services de backend associés qui utilisent des certificats sans SAN, vous devez mettre à jour les webhooks et les backends de serveurs d'API agrégés pour utiliser des certificats avec les SAN appropriés avant de mettre à niveau les clusters vers la version 1.23.
GKE ne met pas automatiquement à niveau les clusters sur les versions 1.22.6-gke.1000 ou ultérieures avec des backends utilisant des certificats incompatibles tant que vous ne remplacez pas les certificats ou tant que la version 1.22 n'est pas en fin de vie.
Si votre cluster utilise une version de GKE antérieure à 1.22.6-gke.1000, vous pouvez temporairement empêcher les mises à niveau automatiques en configurant une exclusion de maintenance pour éviter les mises à niveau mineures.
Resources
Pour en savoir plus sur ce changement, consultez les ressources suivantes :
- Notes de version de Kubernetes 1.23
- Kubernetes est créé à l'aide de Go 1.17. Cette version de Go empêche d'utiliser un paramètre d'environnement
GODEBUG=x509ignoreCN=0
pour réactiver l'ancien comportement obsolète consistant à traiter le CN des certificats de diffusion X.509 comme un nom d'hôte.
- Kubernetes est créé à l'aide de Go 1.17. Cette version de Go empêche d'utiliser un paramètre d'environnement
- Notes de version de Kubernetes 1.19 et Kubernetes 1.20
- L'ancien comportement obsolète consistant à traiter le champ CN des certificats de diffusion X.509 comme un nom d'hôte lorsqu'aucun SAN n'est présent est désormais désactivé par défaut.
- Notes de version de Go 1.17
- L'option temporaire
GODEBUG=x509ignoreCN=0
a été supprimée.
- L'option temporaire
- Notes de version de Go 1.15
- L'ancien comportement obsolète consistant à traiter le champ CN des certificats X.509 comme hôte lorsqu'aucun SAN n'est présent est désormais désactivé par défaut.
- RFC 6125
(page 46)
- Bien que l'utilisation de la valeur CN soit une pratique existante, elle est obsolète, et les autorités de certification sont encouragées à fournir des valeurs
subjectAltName
à la place.
- Bien que l'utilisation de la valeur CN soit une pratique existante, elle est obsolète, et les autorités de certification sont encouragées à fournir des valeurs
- Webhooks d'admission