Publié le :
Comme aujourd’hui il est devenu plus risqué de brancher un PC sur un réseau que de rouler à contre sens sur l’autoroute, le chiffrement de l’information et le contrôle de nos échanges numériques est désormais une priorité, surtout en entreprise (avec une petite aide du marketing et du consulting…).
C’est un standard, surtout dans les accès web (mais pas que), d’imposer le chiffrement pour tous type d’accès.
Qu’il s’agisse de consulter l’intranet local de l’entreprise via le réseau interne, ou le site institutionnel exposé publiquement sur le net…en passant par les nombreuses communications inter services: frontend avec backend, backend avec BDD, webservice avec API…toutes les communications doivent être protégées.
Seul les participants légitimes à une connexion sont censés connaitre le contenu et la nature des informations échangées… (même si ce n’est pas parce qu’on voit un petit cadenas à coté de son URL qu’on n’a plus à se poser de questions).
Pour ça, on n’a pas attendu la hype (et la facture) de la cybersécurité pour proposer des solutions.
L’une des méthodes privilégiées pour authentifier et chiffrer des échanges n’a que très peu changé en dehors de l’amélioration des algorithmes utilisés: l’usage de certificats !
Je ne vais pas me lancer dans une explication du fonctionnement des certificats, mais c’est toujours l’une des solutions principales pour:
Les certificats en eux même ne sont que l’implémentation de méthodes cryptographique comme le chiffrement asymétrique, avec les biens connus Alice et Bob.
Cliquez sur l'image pour l'agrandir.
Viennent s’ajouter des protocoles qu’on a souvent l’habitude de mélanger: SSL/TLS/HTTPS…
Il est d’ailleurs bon de rappeler que ce bon vieux SSL même dans sa version 3.0 n’est plus considéré comme sûr, on devrait plutôt parler à chaque fois de TLS.
HTTPS utilise TLS (et anciennement SSL) pour sécuriser les communications entre un client (navigateur) et un serveur.
Aspect | SSL | TLS | HTTPS |
---|---|---|---|
Type | Protocole de chiffrement obsolète | Protocole de chiffrement moderne | Protocole applicatif sécurisé par SSL/TLS |
Fonction principale | Sécuriser les communications (anciennement) | Sécuriser les communications (actuellement) | Transfert sécurisé de données sur le web |
Statut | Dépassé | Actif (standard actuel) | Utilise TLS pour fonctionner |
Exemple d'usage | Ancien HTTPS | HTTPS moderne, e-mails | Sites web sécurisés |
Même si la mode du moment est d’agiter la menace de l’ordinateur quantique, pour l’instant l’implémentation de tout ce petit monde via une logique de certificats reste la pratique la plus courante.
Seulement, avec l’explosions du nombre d’asset, les architectures micro services et les contraintes de plus en plus fortes autour de la cyber, la gestion des certificats est devenue complexe.
Les durées de vie de ces derniers doivent être réduites, il ne faut plus utiliser de certificats génériques pouvant couvrir des suffixes de domaine complet.
Avec tout ça, on n’arrive vite, même pour de petits écosystèmes, à un grand nombre de certificats. Leur gestion devient une vraie préoccupation de production.
L’arrivée du protocole ACME (Automatic Certificate Management Environment) en 2015 a grandement amélioré les choses.
Introduit avec le projet Let's Encrypt a l’initiative de l'Internet Security Research Group (ISRG), il a permis de standardiser et d’automatiser la gestion des certificats.
Le fonctionnement d’ACME est le suivant:
La nature du défi choisi est dépendante de la configuration du client et de l’implémentation qu’il a retenue d'ACME.
Cliquez sur l'image pour l'agrandir.
Jusque-là, je viens de décrire en gros la mécanique classique de l’obtention d’un certificat, sauf qu’avec ACME tout cela est automatisé. La génération du CSR, la négociation du défi, la configuration du client pour répondre au défi et la délivrance du certificat jusqu’à sa mise en œuvre sur le service finale sont totalement automatiques.
Par la suite, le cycle de vie du certificat est géré également automatiquement, avec un renouvellement qui s’effectue de lui-même avant l’expiration du certificat.
Lorsqu’on parle ACME, on parle souvent de Let's Encrypt. Cette CA (autorité de certification) publique et gratuite est aujourd’hui à l’origine de bon nombre de certificats.
Cliquez sur l'image pour l'agrandir.
Elle est extrêmement populaire, mais reste une CA externe. Son usage impose une exposition publique de son domaine et d’une logique de défi rendu accessible à l’extérieur.
Ce n’est pas un problème dans une entreprise lorsqu’il s’agit de couvrir, par exemple, son site institutionnel publié sur le web mais c’est plus problématique pour des usages purement internes. Il n’est pas toujours possible de communiquer avec une CA externe comme Let's Encrypt.
Les entreprises disposent souvent d’une autorité de certification interne. Cette CA s’inscrit dans une PKI pour Public Key Infrastructure (alors qu’elle n’est pas publique, mais l’avantage c’est que le P fonctionne, aussi avec le mot private).
Les certificats qu’elles délivrent ne sont pas reconnus en dehors des assets de l’entreprise, mais c’est parfaitement exploitable pour les échanges privés entres applications spécifiques et devices sous gestion de la société. Ces derniers sont configurés pour reconnaitre les certificats émis par la CA privée.
La PKI en plus d'une (ou plus plusieurs) CA inclut tout un ensemble d’outils et de services pour simplifier et centraliser la gestion des certificats.
Cette PKI peut être déployée sous gestion d’un ou plusieurs Windows Server de Microsoft. Je vois déjà les maximalistes des amoureux du pingouin crier au scandale, mais il faut reconnaitre que la CA de Microsoft est bel et bien utilisée.
Elle est rarement seule, mais fait souvent partie de la combinaison Active Directory/DNS. En effet, Microsoft propose une intégration profonde de son service de PKI dans Active Directory. Ce n’est pas la seule configuration possible, mais c’est la plus courante. Par exemple, une CA enregistrée dans l’annuaire MS rend les certificats qu’elles délivrent automatiquement reconnus sur tout devices du domaine.
Cliquez sur l'image pour l'agrandir.
Par contre, malgré le fait que ACME existe depuis 2015, Microsoft n’a jamais encore eu l’idée, à ma connaissance, de rendre sa Microsoft Enterprise Certificate Authority compatible avec le protocole.
C’est bien dommage, surtout quand on dispose d’un cluster Kubernetes sur lequel on n’a déployé CertManager.
J’ai déjà eu l’occasion d’évoquer ce formidable outil qu’est CertManager dans cet article. J'y présente comment tirer partir de CertManager, Lets’encrypt et ACME pour automatiser tout le provisionning et le cycle de vie de ses certificats présents sur son cluster K8S.
Malheureusement tout cela ne fonctionne que pour mes applications en DMZ. En interne, je ne peux (veux) pas me baser sur Lets’encrypt et donc tirer partie du support de ACME par CertManager.
Mais, grâce au projet acme2certifier, il est possible de lever cette limitation.
acme2certifier est un formidable outil open source, qui permet d’agir comme un proxy ACME. Il donne la capacité d’utiliser ACME, même si sa CA privée ne le supporte pas. C’est acme2certifier qui se charge de dialoguer avec CertManager, lui laissant croire que c’est lui la CA.
Il va s’occuper d’échanger en backend avec la CA finale de la PKI ne supportant pas ACME, en utilisant cette fois-ci une méthode compatible pour récupérer le certificat et le délivrer à CertManager si le défi ACME est réussi.
Dans mon exemple, je vais utiliser acme2certifier pour tirer partir d’une PKI MS interne et pouvoir exploiter cette dernière pour générer des certificats à destination de mes applications hébergées sur mes worker Kubernetes déployés sur le LAN.
Microsoft Enterprise Certificate Authority n’est pas la seule CA à être prises en compte par acme2certifier, d’autres CA sont compatibles dont la liste est directement consultable sur le github du projet.
Cliquez sur l'image pour l'agrandir.
Je ne vais pas forcément rentrer dans le détail pour toutes les étapes, notamment sur la partie PKI Windows, car le but n’est pas de faire un tutoriel dédié. J’essayerais néanmoins de rendre la chose compréhensible et vous devriez, même si vous n’êtes pas utilisateur de la CA MS, pouvoir tirer parti de l’article pour déployer acme2certifier et l’adapter à votre besoin.
Voici d'ailleur un résumé des composants et de la logique à déployer:
Cliquez sur l'image pour l'agrandir.
À noter que pour fonctionner avec acme2certifier, il faut que le serveur Windows hébergeant la CA ait tous ces composants d’installer au niveau du rôle Active Directory Certificat Services.
Cliquez sur l'image pour l'agrandir.
Je vais démarrer par la création d’un compte de service Active Directory (AD). C’est lui qui va être utilisé pour échanger avec la CA MS depuis acme2certifier (je le nomme arbitrairement svc_k8s_cert).
Cliquez sur l'image pour l'agrandir.
Je crée ensuite un template de certificat TPL-SRV-WEB-K8S depuis mon serveur MS qui fait office de CA.
Cliquez sur l'image pour l'agrandir.
Un template fournit un ensemble de paramètres et d’informations de compatibilités supportées/exigées par le certificat qui va être délivré.
C’est au niveau du template que l’on va décider par exemple du type de chiffrement souhaité, des contraintes d’obtention du certificat, et des fonctions qui vont être supportées.
Il est important de noter qu’un certificat peut être utilisé à différentes fins: sécuriser et authentifier un serveur web (le client s’assure qu’il discute avec le bon serveur), identifier un client (le serveur s’assure qu’il discute avec le bon client), signer du code, émettre un ticket Kerberos…bref on peut avoir au sein de sa PKI plusieurs templates correspondant à plusieurs besoins.
C’est aussi au niveau du template qu’on définit les périodes de validité des certificats.
Côté MS c’est dans le template qu’on va également déclarer qui ou quel device peut demander un certificat issu de ce dernier.
Dans mon cas, j’autorise mon compte de service svc_k8s_cert.
Cliquez sur l'image pour l'agrandir.
Très important, j’impose les paramètres de chiffrement. Par exemple, je souhaite une clef de chiffrement d’au moins 4096 bits et utiliser l’algorithme RSA (et une emprunte en SHA256). On n’a d’ailleurs pas encore parlé de ce dernier.
Cliquez sur l'image pour l'agrandir.
Formé de l’initiale de chacun de ses trois créateurs Rivest, Shamir, et Adleman RSA est un algorithme de chiffrement asymétrique, lui-même utilisé par les protocoles SSL et TLS.
Ces derniers peuvent se baser sur RSA pour établir une communication sécurisée entre un client et un serveur.
RSA est encore largement utilisé, même si dans TLS 1.3 il est remplacé par ECDHE (Elliptic-curve Diffie–Hellman).
L’objectif pour moi est d’avoir un template qui impose un minimal syndical pour une bonne sécurité tout en conservant une bonne compatibilité. Il ne faut pas oublier que si votre certificat impose des contraintes algorithmiques trop fortes, il se peut qu’il ne soit pas supporté par les serveurs qui vont le présenter, ou par les clients qui vont devoir le valider.
De même, les algorithmes de chiffrement retenus ont un impact sur les performances. Chiffrer les communications n’est pas sans impliquer une consommation plus élevée des ressources coté serveur, comme coté client même si aujourd’hui, y’a très souvent largement ce qu’il faut sous le capot pour ne pas sentir de différences. Attention tout de même, sur une large échelle ça peut jouer.
J’autorise enfin ce template à être proposé en interne par ma PKI.
Avant de m’attaquer à acme2certifier, je récupère le certificat public associé à ma CA MS, celui si se trouve dans le magasin de certificats de tous mes devices enregistré sur mon domaine AD (coolcorp.priv).
Il suffit d’aller au niveau de Trusted Root Certification (sous Windows) pour exporter en base64 dans un fichier le certificat de ma CA. Je sauvegarde cela dans un fichier CA-COOLCORP.pem.
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
À noter que dans mon exemple, je n’ai qu’une seule CA racine. Dans la réalité, cette configuration n’est pas conseillée.
Généralement on emploie au moins une CA intermédiaire. La logique étant d’avoir une CA root, qui n’est utilisé que pour générer des certificats pour les CA intermédiaires, puis on éteint cette CA root pour éviter tous risques de compromission.
On garde seulement actives les intermédiaires et c’est elles qui vont délivrer les certificats.
Dans ce cas nous aurions besoin de toute la chaine de certification, c’est-à-dire le certificat public racine plus le(s) certificat(s) intermédiaire(s). En travaillant en base64, on peut tout regrouper dans un seul fichier.
Cette hiérarchie permet d’éviter de maintenir en ligne la CA root.
En effet, cela reste la faille des solutions de certificats. On reste dépendant d’un composant tiers et centralisé, en l’occurrence principalement la CA de plus haut niveau. Pour une CA privée, c'est un serveur interne, pour une CA publique c'est l'organisme auprès de qui on n'a demandé un certificat (Lets’encrypt par exemple).
Si une CA est compromise, toute la chaine basée sur cette CA est compromise donc tout les certificats associés.
C’est avant tout à la CA racine qu'on fait confiance. Dans les bonnes pratiques, cette confiance est ensuite déléguée à des CA intermédiaires. On part ensuite du principe que tout certificat qui part de cette chaine est un certificat valide, et donc qu’on peut avoir confiance dans le contenu du serveur qui utilise ce certificat.
Avec des CA intermédiaires si l’une venait à se faire corrompre, on rallume la CA root et on révoque le certificat de la CA compromise. La liste des certificats révoqués (qui elle reste toujours en ligne) est mise à jour et automatiquement tous les certificats générés par cette intermédiaire corrompue se retrouvent non valides.
La CA root, elle, reste fiable et on peut redéployer un nouveau certificat pour une nouvelle CA intermédiaire avant d'à nouveau mettre hors ligne la CA racine.
La bonne pratique est même d'utiliser une architecture 3 tiers
Cliquez sur l'image pour l'agrandir.
Je m’égare sans doute un peu, mais il est important de comprendre qu’à ce niveau du tutoriel avec acme2certifier, il vous faudra la chaine de certification complète associée à la CA que vous interrogerez par la suite avec acme2certifier. Dans mon exemple et par simplicité, ma chaine est réduite à une CA racine.
On peut enfin attaquer le déploiement de acme2certifier
Pour ça on prépare un fichier de configuration acme_srv.cfg.
Pour moi son contenu est adapté à une CA Microsoft, n’hésitez pas à consulter la doc du projet pour récupérer la configuration associée à votre PKI cible.
[DEFAULT]
debug: False
[Nonce]
# disable nonce check. THIS IS A SEVERE SECURTIY ISSUE! Please do only for testing/debugging purposes
nonce_check_disable: False
[CAhandler]
handler_file: examples/ca_handler/mscertsrv_ca_handler.py
host: PRDMUTWIN501.coolcorp.priv
user: svc_k8s_cert
password: mon_password
ca_bundle: /var/www/acme2certifier/config/CA-COOLCORP.pem
auth_method: gssapi
template: TPL-SRV-WEB-K8S
krb5_config: /var/www/acme2certifier/config/krb5.conf
[DBhandler]
#dbfile: /var/lib/acme/db.sqlite3
[Certificate]
revocation_reason_check_disable: False
[Challenge]
# when true disable challenge validation. Challenge will be set to 'valid' without further checking
# THIS IS A SEVERE SECURTIY ISSUE! Please do only for testing/debugging purposes
challenge_validation_disable: False
[Order]
tnauthlist_support: False
Pour MS, il faut reprendre:
On passe justement sur le fichier krb5.conf. Son contenu est le suivant:
[libdefaults]
default_realm = COOLCORP.PRIV
[realms]
COOLCORP.PRIV = {
kdc = PRDMUTWIN501.coolcorp.priv
admin_server = PRDMUTWIN501.coolcorp.priv
default_domain = COOLCORP.PRIV
}
[domain_realm]
.coolcorp.priv = COOLCORP.PRIV
coolcorp.priv = COOLCORP.PRIV
C’est une conf classique quand on exploite kerberos sur un OS linux. On n’y retrouve les noms de domaines à utiliser et les contrôleurs de domaines à solliciter.
Dans mon cas, le domaine est coolcorp.priv et n’ayant qu’un seul DC (c’est un lab ne l’oublions pas), j’indique mon contrôleur de domaine PRDMUTWIN501.coolcorp.priv (qui est aussi ma CA pour ceux qui l’aurait remarqué…encore une fois c’est un lab…dans la vraie vie, c’est strictement interdit de déployer ce type de service sur un DC…).
Je vais placer ce fichier de conf krb5.conf, ainsi que le certificat public de ma CA CA-COOLCORP.pem sur mon NAS (Network-attached storage), dans un dossier qui sera visible via un partage NFS (Network File System) accessible à mes worker Kubernetes.
Cliquez sur l'image pour l'agrandir.
Le déploiement de acme2certifier va se faire sous K8S.
Je vais donc démarrer par justement créer le PersistentVolume (PV) associé à mon partage NFS pour rendre les deux fichiers précédents accessibles à mon pod.
Voici le contenu du fichier 01-pv-acme2certifier-default.yml. Je ne vais pas renter dans le détail, je vous invite à suivre mon cookbook Kubernetes si jamais vous n’êtes pas familier avec K8S et ses objets.
---
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
pv.kubernetes.io/provisioned-by: nfs.csi.k8s.io
name: pv-acme2certifier-default
namespace: inf-cert-lan
labels:
environment: prd
network: lan
app: acme2certifier
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
csi:
driver: nfs.csi.k8s.io
volumeHandle: /Volume1/nfsshare/kub.coolcorp.priv/namespaces/inf-cert-lan/acme2certifier
volumeAttributes:
server: 192.168.10.152
share: /Volume1/nfsshare/kub.coolcorp.priv/namespaces/inf-cert-lan/acme2certifier
On déploie avec la commande kubectl apply -f 01-pv-acme2certifier-default.yml
.
N’hésitez pas à lire mon article sur le CSI (container Storage Interface) NFS, puis que c’est lui que j’utilise dans mon pv.
À noter que j'exploite le namespace inf-cert-lan, déjà existant et que j’avais crée dans le cas de mon installation de CertManager.
En effet, j’ai décidé arbitrairement de déployer acme2certifier, dans le même namespace que les composants de base de CertManager. Je regroupe ainsi tout ce qui touche au certificat pour mon cluster.
Ensuite du pv on enchaine bien évidemment sur le PersistentVolumeClaim (pvc) via le fichier 02-pvc-acme2certifier-default.yml.
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-cme2certifier-default
namespace: inf-cert-lan
labels:
environment: prd
network: lan
application: acme2certifier
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
volumeName: pv-acme2certifier-default
storageClassName: ""
share: /Volume1/nfsshare/kub.coolcorp.priv/namespaces/inf-cert-lan/acme2certifier
On déploie avec la commande kubectl apply -f 02-pvc-acme2certifier-default.yml
.
Pareil, je ne reviens pas dans le détail, cet article vous précisera davantage d’informations sur le fonctionnement du storage sous Kubernetes.
Cliquez sur l'image pour l'agrandir.
Avant de passer au déployement, on va d’abord créer un ConfigMap (cm). C’est un objet natif de Kubernetes en charge de l’hébergement de la configuration d’une application présente dans un pod. Plutôt que de présenter un fichier de conf, on stocke ce fichier dans un cm , puis on mappe ce cm dans le pod.
Un cm n’est pas offusqué et propose son contenu en clair directement. Attention donc aux éléments qu’on n’y fait figurer. S’ils sont trop sensibles, on préféra utiliser un objet secret, même si celui-ci n’est en réalité pas bien mieux protégé puisqu’il ne fait que coder la donnée en base64.
Le cm va permettre de stocker le fichier de config acme_srv.cfg préparé précédemment. Ceci même s’il contient un password. Je sais que ce n’est pas formidable, mais si vous limitez les accès au namespace qui contient CertManager en jouant des rôles custom Kubernetes, vous pouvez réduire le risque.
Placez-vous à l’emplacement où se trouve le fichier acme_srv.cfg et tapez la commande suivante:
kubectl create configmap cm-acme2certifier --from-file=acme_srv.cfg -n inf-cert-lan
Cliquez sur l'image pour l'agrandir.
L’objet cm cm-acme2certifier sera créé dans le namespace inf-cert-lan à partir du contenu de acme_srv.cfg.
On peut enchainer avec le Deployment via le fichier 03-deploy-acme2certifier-default.yml.
Le fichier est très basique et ne donne lieu qu’a un pod, chargé de déployer une image 2certifier:0.36-nginx-wsgi (la version pourrait changer avec le temps).
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: acme2certifier
namespace: inf-cert-lan
labels:
environment: prd
network: lan
app: acme2certifier
spec:
replicas: 1
selector:
matchLabels:
environment: prd
network: lan
app: acme2certifier
template:
metadata:
labels:
environment: prd
network: lan
app: acme2certifier
spec:
containers:
- name: acme2certifier
image: grindsa/acme2certifier:0.36-nginx-wsgi
ports:
- containerPort: 80
volumeMounts:
- name: pv-democsishare-nfs
mountPath: "/var/www/acme2certifier/config"
- name: acme2certifier-conf
mountPath: "/var/www/acme2certifier/acme_srv/acme_srv.cfg"
subPath: acme_srv.cfg
volumes:
- name: acme2certifier-conf
configMap:
name: cm-acme2certifier
- name: pv-democsishare-nfs
persistentVolumeClaim:
claimName: pvc-cme2certifier-default
On présente au pod un volume pv-democsishare-nfs pour l’accès aux fichiers hébergé sur NFS. On fait en sorte que les chemins correspondent avec ce qui a été mis dans le fichier acme_srv.cfg.
On présente le cm issu du fichier acme_srv.cfg pour que le fichier de config soit mappé sous ce nom dans le pod.
On déploie avec la commande kubectl apply -f 03-deploy-acme2certifier-default.yml
.
Cliquez sur l'image pour l'agrandir.
Arrivé à ce stade on peut vérifier si le pod acme2certifier est bien up.
kubectl get pod -n inf-cert-lan
Cliquez sur l'image pour l'agrandir.
C’est bien le cas, on peut continuer.
acme2certifier doit être accessible au sein du cluster, il faut donc déclarer un service (svc) via le fichier 04-svc-acme2certifier-default.yml.
---
kind: Service
apiVersion: v1
metadata:
name: svc-acme2certifier-default
namespace: inf-cert-lan
labels:
environment: prd
network: lan
application: acme2certifier
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
environment: prd
network: lan
app: acme2certifier
Rien de spécial à dire, comme d’habitude on fait attention au label utilisé dans la section selector pour que le service se rattache bien au pod acme2certifier, sur le port 80.
On déploie avec la commande kubectl apply -f 04-svc-acme2certifier-default.yml
.
Cliquez sur l'image pour l'agrandir.
Vient ensuite le fichier 05-clusterissuer-acme2certifier.yml.
Celui-ci est un peu particulier, puisqu’il déploie un ClusterIssuer.
C’est un objet transverse aux namespace rattaché à CertManager.
C’est lui qui va être en charge de discuter avec acme2certifier. Je vous invite à lire mon article sur CertManager, ou j’explique ce qu’est un issuer. J’en avais déjà créé un pour l’associer à letsencrypt.
kubectl get clusterissuer
Cliquez sur l'image pour l'agrandir.
Ici, je veux l’associer à acme2certifier, voici donc le contenu du fichier:
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: clusterissuer-acme2certifier
spec:
acme:
email: bvivi57@coolcorp.priv
server: http://svc-acme2certifier-default.inf-cert-lan/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: clusterissuer-acme2certifier-account-key
solvers:
- http01:
ingress:
ingressClassName: traefik-lan
podTemplate:
metadata:
labels:
network: lan
ingressTemplate:
metadata:
labels:
network: lan
je vais donc y faire figurer l’url vers le service que j’ai déployé juste avant, rendant acme2certifier accessible en interne du cluster. C’est ce que qui figure dans l’option server, dans les specs du ClusterIssuer. J’utilise le nom complet du service, incluant le namespace.
J’y définis aussi le type de défi acme que je souhaite utiliser, à savoir http-01.
Pour pouvoir traiter ce défi, CertManager, via ce ClusterIssuer va devoir provisionner un pod chargé d’héberger le fichier du défi.
L’URL visée sera toujours associée à l’URL du service couvert par l’application qui demandera un certificat.
Il faudra donc créer un Ingress sous la charge d'un IngressControler. Si cela ne vous parle pas, je vous invite à suivre cet article ou j’explique ce qu’est un Ingress et surtout comment on déploie la solution d’IngressControler Traefik. En gros c’est ce qui permet de rendre le service associé au pod joignable depuis l’extérieur du cluster.
Si vous ne spécifiez rien à ce niveau, CertManager exploite l’ IngressControler par défaut.
Dans mon cluster , j’ai deux IngressControler, l’un pour le LAN l’autre pour la DMZ. En l’occurrence, pour ce tutoriel, je dois exploiter celui sur le LAN.
Pour m’assurer que le pod et l’ingress qui seront montés dynamiquement pour répondre au défi http-01 soient corrects, je positionne les bons labels.
Il suffit ensuite de déployer le ClusterIssuer: kubectl apply -f 05-clusterissuer-acme2certifier.yml
.
À ce niveau la chose intéressante à observer est le log de acme2certifier (kubectl logs nom_pod_acme2certifier -n inf-cert-lan
).
Cliquez sur l'image pour l'agrandir.
Au moment où le ClusterIssuer se déploie, on observe qu’il s’enregistre auprès de acme2certifier avec l’email renseigné dans le yaml.
On n’a donc bien un Issuer qui communique en ACME avec acme2certifier qui lui répond comme s’il s’agissait d’une CA supportant le protocole.
Cliquez sur l'image pour l'agrandir.
Désormais, on n’est en mesure de valider le bon fonctionnement de l’ensemble.
Pour ça, je vais reprendre mon application démo que j’avais mis en place pour démontrer le bon fonctionnement de CertManager.
Dans l’article d’origine, j’avais exploité Lets’encrypt et une exposition en DMZ; ici je vais reprendre exactement la même base, un simple serveur nginx, mais que je vais déployer dans un namespace dev-demoacme2certifier-lan (le namespace est créé avec la commande kubectl create ns dev-demoacme2certifier-lan
).
Je redétaille pas le fichier 01-deploy-demoacme2certifier-front.yaml qui permet de décrire l’objet Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-demoacme2certifier-front
namespace: dev-demoacme2certifier-lan
labels:
environment: dev
network: lan
application: demoacme2certifier
spec:
strategy:
type: Recreate
selector:
matchLabels:
environment: dev
network: lan
application: demoacme2certifier
template:
metadata:
labels:
environment: dev
network: lan
application: demoacme2certifier
spec:
containers:
- name: demo-nginx-traefik-lan
image: nginx:1.27
resources:
requests:
memory: "8Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: 1
ports:
- containerPort: 80
Ni le fichier 02-svc-demoacme2certifier-front.yaml pour l’objet service.
---
kind: Service
apiVersion: v1
metadata:
name: svc-demoacme2certifier-front
namespace: dev-demoacme2certifier-lan
labels:
environment: dev
network: lan
application: demoacme2certifier
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
environment: dev
network: lan
application: demoacme2certifier
Je vais m’arrêter un peu sur le fichier 03-ing-demoacme2certifier-front.yaml.
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-demoacme2certifier-default
namespace: dev-demoacme2certifier-lan
labels:
environment: dev
network: lan
application: demoacme2certifier
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
ingressClassName: traefik-lan
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
ingressClassName: traefik-lan
tls:
- hosts:
- demoacme2certifier.coolcorp.priv
secretName: sec-certificate-demoacme2certifier
rules:
- host: demoacme2certifier.coolcorp.priv
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-demoacme2certifier-front
port:
number: 80
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cert-demoacme2certifier-front
namespace: dev-demoacme2certifier-lan
labels:
environment: dev
network: lan
application: demoacme2certifier
spec:
dnsNames:
- demoacme2certifier.coolcorp.priv
commonName: demoacme2certifier.coolcorp.priv
secretName: sec-certificate-demoacme2certifier
privateKey:
algorithm: RSA
size: 4096
issuerRef:
name: clusterissuer-acme2certifier
kind: ClusterIssuer
Comme dans l’article sur traefik ou sur l’article final de mon cookbook, je créer un objet Ingress.
Celui-ci est paramétré pour tirer partir de l’IngressControler traefik-lan. N’hésitez pas à faire tour par le tutoriel traitant de traefik pour bien comprendre ce point.
L’ingress doit répondre à l’URL externe en demoacme2certifier.coolcorp.priv.
Il doit renvoyer vers le service svc-demoacme2certifier-front et proposer un certificat contenu dans le secret sec-certificate-demoacme2certifier.
Ce certificat est déclaré un peu plus bas via l’objet cert-demoacme2certifier-front.
Il reprend dans ses caractéristiques, le dnsname et le commonname correspondant à l’URL du site de démo : demoacme2certifier.coolcorp.priv.
On y retrouve également les caractéristiques de la clef associée qui va être générée, soit 4096 bits, et l’usage de l’algo RSA. Ceci doit être en cohérence avec le template de certificat de la PKI expliqué dans les prérequis.
Si on ne précise rien à ce niveau, le certificat va être demandé avec les options par défaut. Par exemple une clef de 2048 bits…ce qui ne correspondra pas à la taille minimale imposée par le templaté crée précédemment au niveau de la CA Windows.
Le plus intéressant reste la section issuerRef, puisque c’est ici qu’on indique quel Issuer doit être sollicité pour l’obtention du certificat. On va donc renseigner la ClusterIssuer créée juste avant et qui c’est enregistré sur acme2certifier.
Ne pas oublier de créer l’enregistrement DNS pour que l’URL https://demoacme2certifier.coolcorp.priv soit bien renvoyée vers la VIP HAproxy qui expose les instances traefik (plus de détails ici).
Cliquez sur l'image pour l'agrandir.
Il ne reste plus qu’a lancer la création de tous les objets K8S via la commande kubectl apply -f .\dev-demoacme2certifier-lan\
(tous les yaml vont être pris en une fois, dev-demoacme2certifier-lan étant le dossier dans lequel j'ai mis tous les yaml ) et laisser la magie opérer.
Cliquez sur l'image pour l'agrandir.
Si tout va bien, au bout de quelques minutes, on devrait pouvoir voire apparaitre un « true » en face de la sortie de la commande:
kubectl get certificate -n dev-demoacme2certifier-lan
Cliquez sur l'image pour l'agrandir.
Si c’est le cas, cela implique que le certificat est prêt et disponible. On peut le vérifier en allant consulter l’url https://demoacme2certifier.coolcorp.priv..
Cliquez sur l'image pour l'agrandir.
On n’a bien un certificat ! et quand on regarde la CA qui l’a distribué, on tombe sur ma CA MS.
D’ailleurs si on regarde justement du côté de la console de management de la CA en question, dans la section des certificats issues, on retrouve la trace du certificat, avec le nom du compte de service qui l’a demandé et le template rattaché: tout est cohérent 😊.
Cliquez sur l'image pour l'agrandir.
alors qu’est ce qui s’est passé exactement, ben ça on peut le voir avec la commande:
kubectl get event -n dev-demoacme2certifier-lan
En partant du bas de la sortie de la commande, on peut retracer tout ce qui s’est passé.
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
acme2certifier est l’exemple typique des petites pépites proposées bénévolement par des développeurs, qui se reposent eux-mêmes sur d’autres projets open source d’autres développeurs, pour offrir un service venant compenser un manque fonctionnel d’un outil dont on dispose dans notre architecture.
L’usage de certificat, même s’il n’est pas nouveau, reste toujours un challenge dans les entreprises. Chaque année, les contraintes se font plus fortes, obligeant à revoir régulièrement ses politiques de délivrance des certificats.
La pression d’éditeur de navigateur comme Google, qui parfois annonce la fin du support de tel ou tel protocole ou algorithme dans son browser phare Chrome, impose d’être en capacité de redélivrer tout un ensemble de certificats basés sur de nouvelles normes…au risque de bloquer les updates de Chrome.
Ce qui ne tardera pas à faire grincer les dents de votre RSSI, les patchs de sécurités sur les browsers tombant plus vite que la pluie en Normandie (très belle région au demeurant).
Avoir une gestion automatisée de ses certificats est devenue une nécessité. Basé ses stratégies sur ACME est clairement une bonne solution…Encore faut-il pouvoir l’utiliser avec son legacy…et c’est là que l’écosystème Kubernetes avec des outils comme CertManager apporte une vraie plus-value, surtout quand des développeurs de talents proposent des applications comme acme2certifier ! Là il n’y a plus d’excuse pour ne plus générer ses certificats à la main 😊
Pour ceux qui le souhaitent, une version des fichiers de configurations et des yamls utilisés dans cet article sont disponible dans mon repo github