Les certificats SSL/TLS valides sont une exigence essentielle du paysage applicatif moderne. Malheureusement, la gestion des renouvellements de certificats (ou cert) est souvent une réflexion ultérieure lors du déploiement d'une application. Les certificats ont une durée de vie limitée, allant d'environ 13 mois pour les certificats de DigiCert à 90 jours pour les certificats Let's Encrypt . Pour maintenir un accès sécurisé, ces certificats doivent être renouvelés/réémis avant leur expiration. Compte tenu de la charge de travail importante de la plupart des équipes d’opérations, le renouvellement des certificats passe parfois inaperçu, ce qui entraîne une ruée lorsque les certificats approchent – ou pire, dépassent – leur date d’expiration.
Ce n’est pas forcément comme ça. Avec un peu de planification et de préparation, la gestion des certificats peut être automatisée et rationalisée. Ici, nous allons examiner une solution pour Kubernetes utilisant trois technologies :
Dans ce blog, vous apprendrez à simplifier la gestion des certificats en fournissant des certificats uniques, renouvelés et mis à jour automatiquement à vos points de terminaison.
Avant d’entrer dans les détails techniques, nous devons définir une certaine terminologie. Le terme « certificat TLS » fait référence à deux composants requis pour activer les connexions HTTPS sur notre contrôleur Ingress :
Le certificat et la clé privée sont tous deux émis par Let's Encrypt . Pour une explication complète du fonctionnement des certificats TLS, veuillez consulter l'article de DigiCert Comment fonctionnent les certificats TLS/SSL .
Dans Kubernetes, ces deux composants sont stockés sous forme de secrets . Les charges de travail Kubernetes, telles que NGINX Ingress Controller et cert-manager , peuvent écrire et lire ces secrets, qui peuvent également être gérés par les utilisateurs ayant accès à l'installation Kubernetes.
Le projet cert-manager est un contrôleur de certificat qui fonctionne avec Kubernetes et OpenShift. Lorsqu'il est déployé dans Kubernetes, cert-manager émettra automatiquement les certificats requis par les contrôleurs Ingress et garantira qu'ils sont valides et à jour. De plus, il suivra les dates d’expiration des certificats et tentera de les renouveler à un intervalle de temps configuré. Bien qu'il fonctionne avec de nombreux émetteurs publics et privés, nous montrerons son intégration avec Let's Encrypt.
Lorsque vous utilisez Let’s Encrypt, toute la gestion des certificats est gérée automatiquement. Bien que cela offre beaucoup de commodité, cela présente également un problème : Comment le service garantit-il que vous êtes propriétaire du nom de domaine complet (FQDN) en question ?
Ce problème est résolu à l'aide d'un défi , qui vous oblige à répondre à une demande de vérification que seule une personne ayant accès aux enregistrements DNS du domaine spécifique peut fournir. Les défis prennent deux formes :
HTTP-01 est le moyen le plus simple de générer un certificat, car il ne nécessite pas d'accès direct au fournisseur DNS. Ce type de défi est toujours effectué via le port 80 (HTTP). Notez que lorsque vous utilisez des défis HTTP-01, cert-manager utilisera le contrôleur Ingress pour servir le jeton de défi.
Un contrôleur d'entrée est un service spécialisé pour Kubernetes qui achemine le trafic depuis l'extérieur du cluster, équilibre la charge vers les pods internes (un groupe d'un ou plusieurs conteneurs) et gère le trafic de sortie. De plus, le contrôleur Ingress est contrôlé via l'API Kubernetes et surveillera et mettra à jour la configuration d'équilibrage de charge lorsque des pods sont ajoutés, supprimés ou échouent.
Pour en savoir plus sur les contrôleurs Ingress, lisez les blogs suivants :
Dans les exemples ci-dessous, nous utiliserons NGINX Ingress Controller développé et maintenu par F5 NGINX.
Ces exemples supposent que vous disposez d’une installation Kubernetes fonctionnelle avec laquelle vous pouvez effectuer des tests et que l’installation peut attribuer une adresse IP externe (objet Kubernetes LoadBalancer). De plus, il suppose que vous pouvez recevoir du trafic sur le port 80 et le port 443 (si vous utilisez le défi HTTP-01) ou uniquement sur le port 443 (si vous utilisez le défi DNS-01). Ces exemples sont illustrés à l'aide de Mac OS X, mais peuvent également être utilisés sous Linux ou WSL.
Vous aurez également besoin d’un fournisseur DNS et d’un FQDN pour lesquels vous pourrez ajuster l’enregistrement A. Si vous utilisez le défi HTTP-01, vous avez uniquement besoin de la possibilité d'ajouter un enregistrement A (ou d'en faire ajouter un pour vous). Si vous utilisez le défi DNS-01, vous aurez besoin d'un accès API à un fournisseur DNS pris en charge ou à un fournisseur de webhook pris en charge .
Le moyen le plus simple est de déployer via Helm . Ce déploiement vous permet d'utiliser à la fois Kubernetes Ingress et le CRD du serveur virtuel NGINX.
$ helm repo add nginx-stable https://helm.nginx.com/stable "nginx-stable" a été ajouté à vos référentiels
$ helm repo update Attendez un peu pendant que nous récupérons les dernières nouveautés de vos référentiels de graphiques...
...J'ai obtenu avec succès une mise à jour du référentiel de graphiques "nginx-stable"
Mise à jour terminée. ⎈Joyeux Helming !⎈
$ helm install nginx-kic nginx-stable/nginx-ingress \ --namespace nginx-ingress --set controller.enableCustomResources=true \
--create-namespace --set controller.enableCertManager=true
NOM : nginx-kic
DERNIÈRE DATE DE DÉPLOIEMENT : Jeu 1 sept 2022 15:58:15
ESPACE DE NOM : nginx-ingress
STATUT : déployé
RÉVISION : 1
SUITE DE TESTS : Aucun
REMARQUES :
Le contrôleur d'entrée NGINX a été installé.
$ kubectl get déploiements --namespace nginx-ingress NOM PRÊT À JOUR DISPONIBLE ÂGE
nginx-kic-nginx-ingress 1/1 1 1 23s
$ kubectl get services --namespace nginx-ingress
NOM TYPE IP-CLUSTER IP-EXTERNE PORT(S) ÂGE
nginx-kic-nginx-ingress Équilibreur de charge 10.128.60.190 www.xxx.yyy.zzz 80:31526/TCP,443:32058/TCP 30 s
Le processus ici dépendra de votre fournisseur DNS. Ce nom DNS devra pouvoir être résolu à partir des serveurs Let's Encrypt, ce qui peut nécessiter que vous attendiez que l'enregistrement se propage avant de fonctionner. Pour plus d’informations à ce sujet, veuillez consulter l’article de SiteGround Qu’est-ce que la propagation DNS et pourquoi cela prend-il autant de temps ?
Une fois que vous pouvez résoudre le FQDN que vous avez choisi, vous êtes prêt à passer à l’étape suivante.
$ host cert.example.com cert.example.com a l'adresse www.xxx.yyy.zzz
L’étape suivante consiste à déployer la version la plus récente de cert-manager. Encore une fois, nous utiliserons Helm pour notre déploiement.
$ helm repo add jetstack https://charts.jetstack.io "jetstack" a été ajouté à vos référentiels
$ helm repo update Attendez un peu pendant que nous récupérons les dernières nouveautés de vos référentiels de graphiques...
...J'ai obtenu avec succès une mise à jour du référentiel de graphiques "nginx-stable"
...J'ai obtenu avec succès une mise à jour du référentiel de graphiques "jetstack"
Mise à jour terminée. ⎈Joyeux Helming !⎈
$ helm install cert-manager jetstack/cert-manager \ --namespace cert-manager --create-namespace \ --version v1.9.1 --set installCRDs=true NOM : cert-manager DERNIÈRE UTILISATION : Jeu 1 sept 16:01:52 2022 ESPACE DE NOM : cert-manager STATUT : déployé RÉVISION : 1 SUITE DE TESTS : Aucune REMARQUE : cert-manager v1.9.1 a été déployé avec succès !
Pour commencer à émettre des certificats, vous devrez configurer une ressource ClusterIssuer ou Issuer (par exemple, en créant un émetteur « letsencrypt-staging »).
Vous trouverez plus d'informations sur les différents types d'émetteurs et sur la manière de les configurer dans notre documentation :
https://cert-manager.io/docs/configuration/
Pour plus d'informations sur la configuration de cert-manager pour provisionner automatiquement des certificats pour les ressources Ingress, consultez la documentation « ingress-shim » :
https://cert-manager.io/docs/usage/ingress/
$ kubectl get deployments --namespace cert-manager NOM PRÊT À JOUR DISPONIBLE ÂGE
cert-manager 1/1 1 1 4m30s
cert-manager-cainjector 1/1 1 1 4m30s
cert-manager-webhook 1/1 1 1 4m30s
Nous allons utiliser l’exemple NGINX Cafe pour fournir notre déploiement et nos services backend. Il s'agit d'un exemple courant utilisé dans la documentation fournie par NGINX. Nous ne déploierons pas Ingress dans ce cadre.
$ git clone https://github.com/nginxinc/kubernetes-ingress.git Clonage dans « kubernetes-ingress »...
remote : Énumération des objets : 44979, terminé.
télécommande : Compter les objets : 100% (172/172), terminé.
à distance : Compression d'objets : 100% (108/108), terminé.
à distance : Total 44979 (delta 87), réutilisés 120 (delta 63), réutilisés en pack 44807
Objets reçus : 100% (44979/44979), 60,27 Mio | 27,33 Mio/s, terminé.
Résolution des deltas : 100% (26508/26508), fait.
$ cd ./kubernetes-ingress/examples/ingress-resources/exemple-complet
$ kubectl apply -f ./cafe.yaml
déploiement.apps/coffee créé
service/coffee-svc créé
déploiement.apps/tea créé
service/tea-svc créé
kubectl
get. Vous souhaitez vous assurer que les pods s'affichent comme PRÊTS
et que les services s'affichent comme en cours d'exécution
. L'exemple ci-dessous montre un échantillon représentatif de ce que vous recherchez. Notez que le service Kubernetes
est un service système exécuté dans le même espace de noms (par défaut) que l'exemple NGINX Cafe.$ kubectl get déploiements, services --namespace default NOM PRÊT À JOUR DISPONIBLE ÂGE
déploiement.apps/coffee 2/2 2 2 69s
déploiement.apps/tea 3/3 3 3 68s
NOM TYPE IP-CLUSTER IP-EXTERNE PORT(S) ÂGE
service/coffee-svc ClusterIP 10.128.154.225 <aucun> 80/TCP 68 s
service/kubernetes ClusterIP 10.128.0.1 <aucun> 443/TCP 29 m
service/tea-svc ClusterIP 10.128.96.145 <aucun> 80/TCP 68 s
Dans cert-manager, le ClusterIssuer peut être utilisé pour émettre des certificats. Il s’agit d’un objet à l’échelle d’un cluster qui peut être référencé par n’importe quel espace de noms et utilisé par toutes les demandes de certificat avec l’autorité d’émission de certificat définie. Dans cet exemple, toutes les demandes de certificats Let's Encrypt peuvent être traitées par ce ClusterIssuer.
Déployez le ClusterIssuer pour le type de défi que vous avez sélectionné. Bien que cela sorte du cadre de cet article, il existe des options de configuration avancées qui vous permettent de spécifier plusieurs résolveurs (choisis en fonction des champs de sélection) dans votre ClusterIssuer.
Le protocole ACME (Automated Certificate Management Environment) est utilisé pour déterminer si vous possédez un nom de domaine et si vous pouvez donc obtenir un certificat Let’s Encrypt. Pour ce défi, voici les paramètres qui doivent être transmis :
Cet exemple montre comment configurer un ClusterIssuer pour utiliser le défi HTTP-01 pour prouver la propriété du domaine et recevoir un certificat.
$ cat << EOF | kubectl apply -f apiVersion: cert-manager.io/v1
type: ClusterIssuer
métadonnées :
nom : prod-issuer
spécification :
acme :
e-mail : example@example.com
serveur : https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef :
nom : prod-issuer-account-key
solveurs :
- http01 :
entrée :
classe : nginx
EOF
clusterissuer.cert-manager.io/prod-issuer créé
$ kubectl get clusterissuer NOM PRÊT ÂGE
prod-issuer Vrai 34 s
Cet exemple montre comment configurer un ClusterIssuer pour utiliser le défi DNS-01 pour authentifier la propriété de votre domaine. Selon votre fournisseur DNS, vous devrez probablement utiliser un secret Kubernetes pour stocker votre jeton. Cet exemple utilise Cloudflare . Notez l’utilisation de l’espace de noms. L'application cert-manager, qui est déployée dans l'espace de noms cert-manager, doit avoir accès au Secret .
Pour cet exemple, vous aurez besoin d'un jeton API Cloudflare , que vous pouvez créer à partir de votre compte. Cela devra être placé dans la ligne ci-dessous. Si vous n'utilisez pas Cloudflare, vous devrez suivre la documentation de votre fournisseur .
$ cat << EOF | kubectl apply -f apiVersion: v1
genre: Secret
métadonnées :
nom : cloudflare-api-token-secret
espace de noms : cert-manager
type : Opaque
stringData :
api-token : <API Token>
EOF
$ cat << EOF | kubectl apply -f apiVersion: cert-manager.io/v1
type: ClusterIssuer
métadonnées :
nom : prod-issuer
spécification :
acme :
e-mail : example@example.com
serveur : https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef :
nom : prod-issuer-account-key
solvers :
- dns01 :
cloudflare :
apiTokenSecretRef :
nom : cloudflare-api-token-secret
clé : api-token
EOF
$ kubectl get clusterissuer NOM PRÊT ÂGE
prod-issuer Vrai 31 m
C’est le point vers lequel nous avons travaillé : le déploiement de la ressource Ingress pour notre application. Cela acheminera le trafic vers l’application NGINX Cafe que nous avons déployée précédemment.
Si vous utilisez la ressource Kubernetes Ingress standard, vous utiliserez le YAML de déploiement suivant pour configurer Ingress et demander un certificat.
apiVersion : networking.k8s.io/v1 type : Entrée
métadonnées :
nom : cafe-ingress
annotations :
cert-manager.io/cluster-issuer : prod-issuer
acme.cert-manager.io/http01-edit-in-place : "true"
spécification :
ingressClassName : nginx
tls :
- hôtes :
- cert.example.com
secretName : cafe-secret
règles :
- hôte : cert.example.com
http :
chemins :
- chemin : /tea
pathType : Préfixe
backend :
service :
nom : tea-svc
port :
numéro : 80
- chemin : /café
pathType : Préfixe
backend :
service :
nom : coffee-svc
port :
numéro : 80
Il vaut la peine de revoir certains éléments clés du manifeste :
metadata.annotations
où nous définissons acme.cert-manager.io/http01-edit-in-place
sur « true ». Cette valeur est obligatoire et ajuste la manière dont le défi est servi. Pour plus d'informations, consultez le document Annotations prises en charge . Cela peut également être géré en utilisant une configuration maître/sbire .spec.ingressClassName
fait référence au contrôleur NGINX Ingress que nous avons installé et que nous utiliserons.spec.tls.secret
stocke la clé de certificat renvoyée lorsque le certificat est émis par Let's Encrypt. cert.example.com
est spécifié pour spec.tls.hosts
et spec.rules.host
. Il s’agit du nom d’hôte pour lequel notre ClusterIssuer a émis le certificat.spec.rules.http
définit les chemins et les services back-end qui traiteront les requêtes sur ces chemins. Par exemple, le trafic vers /tea
sera dirigé vers le port 80 sur tea-svc
.spec.rules.host
et spec.tls.hosts
, mais vous devez vérifier tous les paramètres de la configuration. $ kubectl apply -f ./cafe-virtual-server.yaml virtualserver.k8s.nginx.org/cafe créé
$ kubectl get certificates NOM PRÊT SECRET ÂGE
certificate.cert-manager.io/cafe-secret Vrai cafe-secret 37m
Si vous utilisez les CRD NGINX, vous devrez utiliser le YAML de déploiement suivant pour configurer votre entrée.
apiVersion : k8s.nginx.org/v1
type : VirtualServer
métadonnées :
nom : café
spécifications :
hôte : cert.example.com
tls :
secret : cafe-secret
cert-manager :
cluster-issuer : prod-issuer
upstreams :
- nom : thé
service : tea-svc
port : 80
- nom : café
service : coffee-svc
port : 80
itinéraires :
- chemin : /thé
action :
pass : thé
- chemin : /café
action :
pass : café
Encore une fois, il vaut la peine de revoir certains éléments clés du manifeste :
spec.tls.secret
stocke la clé de certificat renvoyée lorsque le certificat est émis par Let's Encrypt. cert.example.com
est spécifié pour spec.host
. Il s’agit du nom d’hôte pour lequel notre ClusterIssuer a émis le certificat.spec.upstreams
pointent vers nos services backend, y compris les ports.spec.routes
définit à la fois l'itinéraire et l'action à entreprendre lorsque ces itinéraires sont touchés.spec.host
, mais vous devez vérifier tous les paramètres de la configuration. $ kubectl apply -f ./cafe-virtual-server.yaml virtualserver.k8s.nginx.org/cafe créé
$ kubectl get VirtualServers NOM ÉTAT HÔTE IP PORTS ÂGE
cafe Valide cert.example.com www.xxx.yyy.zzz [80,443] 51m
Vous pouvez afficher le certificat via l'API Kubernetes. Vous y trouverez des informations détaillées sur le certificat, notamment sa taille et la clé privée associée.
$ kubectl describe secret cafe-secret Nom : cafe-secret
Espace de noms : par défaut
Étiquettes : <none>
Annotations : cert-manager.io/alt-names: cert.exemple.com
cert-manager.io/certificate-name: café-secret
cert-manager.io/nom-commun: cert.exemple.com
cert-manager.io/ip-sans:
cert-manager.io/groupe-de-l-emetteurs:
cert-manager.io/issuer-kind: ClusterIssuer cert-manager.io/issuer-name : prod-issuer cert-manager.io/uri-sans :Type: kubernetes.io/tls Données ==== tls.crt: 5607 octets tls.key : 1675 octets
Si vous souhaitez voir le certificat et la clé réels, vous pouvez le faire en exécutant la commande suivante. (Note: Cela illustre une faiblesse des secrets Kubernetes. Autrement dit, ils peuvent être lus par toute personne disposant des autorisations d’accès nécessaires.)
$ kubectl obtenir le secret café-secret -o yaml
Tester les certificats . Vous pouvez utiliser ici la méthode que vous souhaitez. L'exemple ci-dessous utilise cURL . La réussite est indiquée par un bloc similaire à celui affiché ci-dessus, qui comprend le nom du serveur, l'adresse interne du serveur, la date, l'URI (itinéraire) choisi (café ou thé) et l'ID de la requête. Les échecs prendront la forme de codes d'erreur HTTP, très probablement 400 ou 301.
$ curl https://cert.example.com/tea
Adresse du serveur : 10.2.0.6:8080
Nom du serveur : tea-5c457db9-l4pvq
Date : 02/Sep/2022:15:21:06 +0000
URI : /tea
ID de la requête : d736db9f696423c6212ffc70cd7ebecf
$ curl https://cert.example.com/coffee
Adresse du serveur : 10.2.2.6:8080
Nom du serveur : coffee-7c86d7d67c-kjddk
Date : 02/09/2022:15:21:10 +0000
URI : /coffee
ID de la requête : 4ea3aa1c87d2f1d80a706dde91f31d54
Au départ, nous avions promis que cette approche éliminerait la nécessité de gérer les renouvellements de certificats. Cependant, nous n’avons pas encore expliqué comment procéder. Pourquoi? Parce qu’il s’agit d’une partie essentielle et intégrée de cert-manager. Dans ce processus automatique, lorsque cert-manager se rend compte qu'un certificat n'est pas présent, est expiré, est dans les 15 jours suivant l'expiration, ou si l'utilisateur demande un nouveau certificat via la CLI, alors un nouveau certificat est automatiquement demandé . Cela ne peut pas être plus simple que cela.
Si vous êtes abonné à NGINX Plus, la seule différence pour vous sera l'installation du contrôleur d'entrée NGINX. Veuillez consulter la section Installation Helm de la documentation NGINX pour obtenir des instructions sur la façon de modifier la commande Helm donnée ci-dessus pour y parvenir.
Cela dépend en grande partie de votre cas d’utilisation.
La méthode de défi HTTP-01 nécessite que le port 80 soit ouvert sur Internet et que l’enregistrement DNS A ait été correctement configuré pour l’adresse IP du contrôleur d’entrée. Cette approche ne nécessite pas d’accès au fournisseur DNS autre que pour créer l’enregistrement A.
La méthode de défi DNS-01 peut être utilisée lorsque vous ne pouvez pas exposer le port 80 à Internet et nécessite uniquement que le gestionnaire de certificats dispose d'un accès de sortie au fournisseur DNS. Cependant, cette méthode nécessite que vous ayez accès à l’API de votre fournisseur DNS, bien que le niveau d’accès requis varie selon le fournisseur spécifique.
Étant donné que Kubernetes est si complexe, il est difficile de fournir des informations de dépannage ciblées. Si vous rencontrez des problèmes, nous vous invitons à nous les poser sur NGINX Community Slack (les abonnés NGINX Plus peuvent utiliser leurs options d'assistance habituelles).
Commencez par demander votre essai gratuit de 30 jours de NGINX Ingress Controller avec NGINX App Protect WAF et DoS, et téléchargez le NGINX Service Mesh toujours gratuit.
« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."