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" has been added to your repositories
$ helm repo update Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "nginx-stable" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm install nginx-kic nginx-stable/nginx-ingress \ --namespace nginx-ingress --set controller.enableCustomResources=true \
--create-namespace --set controller.enableCertManager=true
NAME: nginx-kic
LAST DEPLOYED: Thu Sep 1 15:58:15 2022
NAMESPACE: nginx-ingress
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The NGINX Ingress Controller has been installed.
$ kubectl get deployments --namespace nginx-ingress NAME READY UP-TO-DATE AVAILABLE AGE
nginx-kic-nginx-ingress 1/1 1 1 23s
$ kubectl get services --namespace nginx-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-kic-nginx-ingress LoadBalancer 10.128.60.190 www.xxx.yyy.zzz 80:31526/TCP,443:32058/TCP 30s
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 has address 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" has been added to your repositories
$ helm repo update Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "nginx-stable" chart repository
...Successfully got an update from the "jetstack" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm install cert-manager jetstack/cert-manager \ --namespace cert-manager --create-namespace \
--version v1.9.1 --set installCRDs=true
NAME: cert-manager
LAST DEPLOYED: Thu Sep 1 16:01:52 2022
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.9.1 has been deployed successfully!
In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
More information on the different types of issuers and how to configure them
can be found in our documentation:
https://cert-manager.io/docs/configuration/
For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:
https://cert-manager.io/docs/usage/ingress/
$ kubectl get deployments --namespace cert-manager NAME READY UP-TO-DATE AVAILABLE AGE
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 Cloning into 'kubernetes-ingress'...
remote: Enumerating objects: 44979, done.
remote: Counting objects: 100% (172/172), done.
remote: Compressing objects: 100% (108/108), done.
remote: Total 44979 (delta 87), reused 120 (delta 63), pack-reused 44807
Receiving objects: 100% (44979/44979), 60.27 MiB | 27.33 MiB/s, done.
Resolving deltas: 100% (26508/26508), done.
$ cd ./kubernetes-ingress/examples/ingress-resources/complete-example
$ kubectl apply -f ./cafe.yaml
deployment.apps/coffee created
service/coffee-svc created
deployment.apps/tea created
service/tea-svc created
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 deployments,services --namespace default NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/coffee 2/2 2 2 69s
deployment.apps/tea 3/3 3 3 68s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/coffee-svc ClusterIP 10.128.154.225 <none> 80/TCP 68s
service/kubernetes ClusterIP 10.128.0.1 <none> 443/TCP 29m
service/tea-svc ClusterIP 10.128.96.145 <none> 80/TCP 68s
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
kind: ClusterIssuer
metadata:
name: prod-issuer
spec:
acme:
email: example@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: prod-issuer-account-key
solvers:
- http01:
ingress:
class: nginx
EOF
clusterissuer.cert-manager.io/prod-issuer created
$ kubectl get clusterissuer NAME READY AGE
prod-issuer True 34s
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
kind: Secret
metadata:
name: cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
stringData:
api-token: <API Token>
EOF
$ cat << EOF | kubectl apply -f apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: prod-issuer
spec:
acme:
email: example@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: prod-issuer-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
EOF
$ kubectl get clusterissuer NAME READY AGE
prod-issuer True 31m
Nous en arrivons enfin au moment clé : déployer la ressource Ingress pour votre application. Cela dirigera le trafic vers l’application NGINX Cafe que vous avez déployée précédemment.
Si vous utilisez la ressource standard Kubernetes Ingress, utilisez le fichier YAML de déploiement ci-dessous pour configurer l’Ingress et demander un certificat.
apiVersion: networking.k8s.io/v1 kind: Ingress
metadata:
name: cafe-ingress
annotations:
cert-manager.io/cluster-issuer: prod-issuer
acme.cert-manager.io/http01-edit-in-place: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- cert.example.com
secretName: cafe-secret
rules:
- host: cert.example.com
http:
paths:
- path: /tea
pathType: Prefix
backend:
service:
name: tea-svc
port:
number: 80
- path: /coffee
pathType: Prefix
backend:
service:
name: coffee-svc
port:
number: 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é du certificat délivrée 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 created
$ kubectl get certificates NAME READY SECRET AGE
certificate.cert-manager.io/cafe-secret True 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
kind: VirtualServer
metadata:
name: cafe
spec:
host: cert.example.com
tls:
secret: cafe-secret
cert-manager:
cluster-issuer: prod-issuer
upstreams:
- name: tea
service: tea-svc
port: 80
- name: coffee
service: coffee-svc
port: 80
routes:
- path: /tea
action:
pass: tea
- path: /coffee
action:
pass: coffee
Encore une fois, il vaut la peine de revoir certains éléments clés du manifeste :
spec.tls.secret
stocke la clé du certificat délivrée 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 created
$ kubectl get VirtualServers NAME STATE HOST IP PORTS AGE
cafe Valid 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 Name: cafe-secret
Namespace: default
Labels: <none>
Annotations: cert-manager.io/alt-names: cert.example.com
cert-manager.io/certificate-name: cafe-secret
cert-manager.io/common-name: cert.example.com
cert-manager.io/ip-sans:
cert-manager.io/issuer-group:
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: prod-issuer
cert-manager.io/uri-sans:Type: kubernetes.io/tlsData
====
tls.crt: 5607 bytes
tls.key: 1675 bytes
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 get secret cafe-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
Server address: 10.2.0.6:8080
Server name: tea-5c457db9-l4pvq
Date: 02/Sep/2022:15:21:06 +0000
URI: /tea
Request ID: d736db9f696423c6212ffc70cd7ebecf
$ curl https://cert.example.com/coffee
Server address: 10.2.2.6:8080
Server name: coffee-7c86d7d67c-kjddk
Date: 02/Sep/2022:15:21:10 +0000
URI: /coffee
Request ID: 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."