DNS-01 challenge: Certificats wildcard TLS sur Kubernetes
DNS-01 challenge: Générez des certificats wildcard TLS sur kubernetes avec cert-manager et let's encrypt

Lorsqu'on déploie des applications sur un cluster kubernetes, celles-ci sont souvent exposées à l'extérieur en HTTPS via un ingress controller, généralement en utilisant cert-manager pour gérer les certificats TLS avec Let's Encrypt.
La demande de certificat TLS est généralement faite avec le challenge HTTP-01, qui vérifie que l'on peut accéder à du contenu sur une URL spécifique.
Cependant, d'autres types de challenges existent, notamment le challenge DNS-01 : Let's Encrypt vérifier une entrée DNS spécifiques, pour s'assurer que le domaine sur lequel nous demandons un certificat nous appartien bien. Cela peut être utile dans plusieurs cas :
- Les applications ne sont pas exposées sur Internet (Let's Encrypt ne peut alors pas se connecter sur l'URL)
- Le certificats wildcard, car il n'y a pas d'URL par défaut ou héberger la preuve de certificat
On peut retrouver plus d'informations sur les différents types de challenge ici : https://letsencrypt.org/docs/challenge-types/
Pour demander un certificat de cette manière dans un cluster kubernetes, on aura besoin de mettre à jour automatiquement les entrées DNS associées à l'application chez le cloud provider. Seulement les providers "majeurs" sont nativement supportés, mais on peut étendre ce fonctionnement avec des webhooks.
Dans cet article, nous verrons comment paramétrer un cluster kubernetes, configurer cert-manager pour gérer des challenges DNS-01 avec des certificats Wildcards, et déployer une application utilisatn ces certificats.
Paramétrage et Pré-requis
Pour la démo, on utilise les outils et plateformes suivants :
- Cluster Kubernetes Kapsule de chez Scaleway
- Serveur DNS de chez Scaleway toujours, car on peut le piloter avec les cert-manager webhooks
- Terraform pour facilement tout mettre en palce
- k8s Lens pour facilement voir les ressourcs déployées
L'article ne couvre pas l'installation de Terraform & autres outils kubectl, helm and co.
Provisionnement du cluster
Avec Terraform, on provisionne un cluster Kapsule simple. Il suffit juste d'utilser les ressources scaleway_k8s_cluster et scaleway_k8s_pool:
terraform {
required_providers {
scaleway = {
source = "scaleway/scaleway"
version = "2.1.0"
}
}
required_version = ">= 0.13"
}
provider "scaleway" {
zone = "fr-par-1"
region = "fr-par"
}
resource "scaleway_k8s_cluster" "k8s_cluster" {
name = var.k8s_cluster_name
version = "1.22.2"
cni = "cilium"
}
resource "scaleway_k8s_pool" "k8s_pool" {
cluster_id = scaleway_k8s_cluster.k8s_cluster.id
name = var.k8s_pool_name
node_type = "DEV1-M"
size = 2
autohealing = true
}
resource "local_file" "kubeconfig" {
content = scaleway_k8s_cluster.k8s_cluster.kubeconfig[0].config_file
filename = "${path.module}/${scaleway_k8s_cluster.k8s_cluster.name}-kubeconfig"
file_permission = "0600"
}Maintenant on peut provisionner le cluster :
$ terraform init
$ terraform plan -out k8s_scaleway.out
$ terraform apply k8s_scaleway.outAprès quelques minutes d'attente, le cluster est prêt et dispo, avec Nginx comme ingress controller, un load-balancer, et cert-manager de configuré. On a également un fichier kubeconfig à disposition pour contacter le cluster !
Paramétrage DNS
On peut maintenant configurer l'entrée DNS pour faire le lien avec l'IP du load-balancer. On pourrait faire cela automatiquement, mais les ressources Terraform n'existent pas encore, c'est prévu pour une prochaine release, voir ici.
Pour ce setup, le domaine utilisé est scw.vrchr.fr, et donc chaque URL se terminant ainsi sera automatiquement dirigée vers l'IP du load-balancer du cluster kubernetes préalablement installé.

Note : le cluster de démo n'existe plus à l'heure actuelle, pas la peine d'essayer de le joindre, cela n'a été fait que le temps de l'article ;)
Certificat wildcard avec DNS-01
Webhook Scaleway
Pour rapppel, pour certains cloud providers, on doit utiliser les webhooks cert-manager afin de piloter les entrées DNS. C'est le cas pour Scaleway, alors installons ce qu'il faut :
$ git clone https://github.com/scaleway/cert-manager-webhook-scaleway.git
$ cd cert-manager-webhook-scaleway
$ helm install scaleway-webhook deploy/scaleway-webhook --set secret.accessKey=changeme --set secret.secretKey=changeme --set certManager.serviceAccountName=jetstack-cert-manager --namespace=cert-managerAttention au serviceAccountName qui doit être le même que celui créé avec le chart helm cert-manager.
On peut maintenant voir les ressources déployées :


Issuer and Certificates
Maintenant, on va créer un "Certificate Issuer", qui sera responsable des demandes de certificats TLS. Il s'agit d'une Custom Resource avec la propriété "dns01". Dans l'exemple on créé un ClusterIssuer plutôt qu'un Issuer, afin de gérer les demandes de certificats sur l'ensemble du cluster :
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: scaleway-issuer-prod
spec:
acme:
email: name@company.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: scaleway-private-key-secret
solvers:
- dns01:
webhook:
groupName: acme.scaleway.com
solverName: scaleway$ kubectl apply -f cert_issuer.yamlOn peut rajouter un issuer pour les certificats de type staging si besoin.
Maintenant, créons une demande de certificat ! La demande sera faite pour "*.scw.vrchr.fr", qui sera enregistrée dans un secret nommé "wildcard-scw-vrchr-fr-tls” :
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-scw-vrchr-fr-tls
namespace: default
spec:
dnsNames:
- "*.scw.vrchr.fr"
issuerRef:
name: scaleway-issuer-prod
kind: ClusterIssuer
secretName: wildcard-scw-vrchr-fr-tlsQue se passe-t'il maintenant ?
- Cert-manager détecte une demande de certificat, et génère une demande vers les serveurs Let’s Encrypt
- Cert-manager utilise le webhook pour créer une entrée DNS TXT DNS : _acme-challenge.scw.vrchr.fr
- Les serveurs Let's Encrypt vont vérifier cette entrée DNS, et valident la requpete. Il faut être patient, le temps de la propagation DNS qui peut être longue
- Une fois la demande validée, le certificat est créé dans un secret disponible dans le cluster !

Deploiement d'application
OK ! Maintenant qu'on a un certificat wildcard généré automatiquement, utilisons-le sur des applications.
On créé un déploiement simple, on l'expose via un service, et on créé une règle d'ingress. La partie importante de la configuration est dans l'ingress, qui spécifie quel certificat TLS utilisé. Pas besoin d'annotations particulières pour géré le certificat automatique, car il est déjà créé et géré ailleurs.
[...]
spec:
tls:
- hosts:
- "*.scw.vrchr.fr"
secretName: wildcard-scw-vrchr-fr-tls
[...]Comme on a créé un certificat wildcard, chaque FQDN qui matchera le wildcard sera valide.
Voici l'exemple d'un déploiement complet de l'application jpetazzo/webcolor qui expose différentes couleurs.
Exemple de déploiement & service:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: green
spec:
selector:
matchLabels:
app: green
replicas: 1
template:
metadata:
labels:
app: green
spec:
containers:
- image: jpetazzo/webcolor
name: webcolor
---
apiVersion: v1
kind: Service
metadata:
name: green
spec:
ports:
- port: 8000
targetPort: 8000
selector:
app: greenIngress:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: color-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
tls:
- hosts:
- "*.scw.vrchr.fr"
secretName: wildcard-scw-vrchr-fr-tls
rules:
- host: green.scw.vrchr.fr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: green
port:
number: 8000
- host: purple.scw.vrchr.fr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: purple
port:
number: 8000
- host: yellow.scw.vrchr.fr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: yellow
port:
number: 8000$ kubectl apply -f dep_green.yaml
$ kubectl apply -f wildcard_tls_ingress.yamlMaintenant, accédons à https://green.scw.vrchr.fr, qui devrait présenter le certificat wildcard !



Conclusion et remarques
Dans cet article on a pu :
- Déployer un cluster kubernetes sur Scaleway avec Terraform
- Déployer Cert Manager & Nginx via Helm & Terraform
- Déployer les DNS Webhook Scaleway
- Générer des certificats wildcard avec le protocole DNS-01 via les webhooks
- Déployer une application dans un sous-domaine, présentant le certificats wildcard
Maintenant on peut déployer autant d'application dans le sous-domaine que l'on veut, en utilisant toujours le même certificat. Pour faciliter l'exercice, ici tout a été fait dans un même namespace, ne pas hésiter à lire la doc de cert-manager pour partager les certificats entre plusieurs namespaces.
Enfin on retrouvera le code d'exemple de l'articile ici : https://gitlab.com/rverchere/vrchr-k8s-dns-demo
Et n'oublions pas : "It's always DNS" !

Références
Quelques ressources très utiles pour comprendre les concepts utilisés dans l'articule :