Aller au contenu
Sécurité medium

Vault PKI : générer des certificats TLS automatiquement

20 min de lecture

Vault peut agir comme autorité de certification (CA) interne pour émettre des certificats TLS à la demande. Plus de certificats manuels, plus d’oublis de renouvellement : chaque service demande son certificat quand il en a besoin.

Ce guide couvre la création d’une PKI avec CA intermédiaire dans Vault, les méthodes d’émission (issue vs sign), et le cycle de vie des certificats.

  • Vault installé et démarré
  • Accès admin pour configurer le moteur PKI

Une PKI bien conçue utilise deux niveaux de CA minimum :

Architecture PKI : Root CA hors Vault, Intermediate CA dans Vault, certificats services
NiveauDurée typiqueLocalisationUsage
Root CA10-20 ansHors Vault (offline)Signe uniquement les intermédiaires
Intermediate CA1-5 ansDans Vault (pki_int)Émet les certificats services
Certificats leaf30-90 joursServicesmTLS, HTTPS, API
Fenêtre de terminal
vault secrets enable -path=pki pki
Fenêtre de terminal
vault secrets tune -max-lease-ttl=87600h pki

87600h = 10 ans. La Root CA doit avoir une longue durée de vie.

Fenêtre de terminal
vault write -field=certificate pki/root/generate/internal \
common_name="My Organization Root CA" \
issuer_name="root-2026" \
ttl=87600h > root_ca.crt
Fenêtre de terminal
vault write pki/config/urls \
issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
crl_distribution_points="$VAULT_ADDR/v1/pki/crl"
Fenêtre de terminal
vault secrets enable -path=pki_int pki
Fenêtre de terminal
vault secrets tune -max-lease-ttl=43800h pki_int

43800h = 5 ans maximum pour les certificats émis par cette CA.

Fenêtre de terminal
vault write -format=json pki_int/intermediate/generate/internal \
common_name="My Organization Intermediate CA" \
issuer_name="intermediate-2026" \
| jq -r '.data.csr' > intermediate.csr
Fenêtre de terminal
vault write -format=json pki/root/sign-intermediate \
issuer_ref="root-2026" \
csr=@intermediate.csr \
format=pem_bundle \
ttl=43800h \
| jq -r '.data.certificate' > intermediate.crt
Fenêtre de terminal
vault write pki_int/intermediate/set-signed certificate=@intermediate.crt
Fenêtre de terminal
vault write pki_int/config/urls \
issuing_certificates="$VAULT_ADDR/v1/pki_int/ca" \
crl_distribution_points="$VAULT_ADDR/v1/pki_int/crl"

Depuis Vault 1.11+, un même mount PKI peut gérer plusieurs issuers (plusieurs CA). Cela permet :

  • Rotation d’autorité : créer un nouvel issuer avant d’expirer l’ancien
  • Période de transition : les deux issuers coexistent pendant le sunset
  • Révocation par issuer : révoquer un issuer sans toucher aux autres
Fenêtre de terminal
vault list pki_int/issuers
Fenêtre de terminal
vault write pki_int/config/issuers default="intermediate-2026"
  1. Générer une nouvelle CSR : pki_int/intermediate/generate/internal
  2. La faire signer par la Root
  3. Importer : pki_int/intermediate/set-signed
  4. Mettre à jour le défaut : pki_int/config/issuers
  5. Laisser l’ancien issuer le temps que ses certificats expirent
  6. Supprimer l’ancien issuer si besoin

Un rôle définit les paramètres des certificats émis : domaines autorisés, durée, type de clé.

Fenêtre de terminal
vault write pki_int/roles/webserver \
allowed_domains="example.com" \
allow_subdomains=true \
allow_bare_domains=false \
max_ttl=2160h \
ttl=720h \
key_type="rsa" \
key_bits=2048 \
require_cn=true \
allow_ip_sans=false \
allow_localhost=false \
enforce_hostnames=true
ParamètreDescriptionValeur sécurisée
allowed_domainsDomaines autorisésUn seul domaine par rôle
allow_subdomains*.example.com autoriséSelon besoin
allow_bare_domainsexample.com sans sous-domainefalse en général
allow_ip_sansAutoriser les IPs dans SANfalse sauf besoin explicite
allow_localhostAutoriser localhostfalse en prod
enforce_hostnamesValider le format hostnametrue toujours
Fenêtre de terminal
vault write pki_int/roles/mtls-internal \
allowed_domains="service.internal" \
allow_subdomains=true \
max_ttl=168h \
ttl=72h \
key_type="ec" \
key_bits=256 \
client_flag=true \
server_flag=true \
require_cn=true \
enforce_hostnames=true

Vault PKI propose deux endpoints pour obtenir un certificat :

EndpointClé privéeCas d’usage
/issue/<role>Générée par VaultScripts, automation, services simples
/sign/<role>Fournie par le client (CSR)HSM, exigences de conformité, contrôle total
Fenêtre de terminal
vault write pki_int/issue/webserver \
common_name="api.example.com" \
ttl=720h

Vault génère la clé privée et le certificat. La clé privée est retournée dans la réponse.

Avantages : simple, tout-en-un. Inconvénients : la clé privée transite par Vault et le réseau.

Fenêtre de terminal
# 1. Générer une clé et une CSR côté client
openssl genrsa -out backend.key 2048
openssl req -new -key backend.key -out backend.csr \
-subj "/CN=backend.example.com"
# 2. Demander à Vault de signer la CSR
vault write -format=json pki_int/sign/webserver \
csr=@backend.csr \
ttl=720h | jq -r '.data.certificate' > backend.crt

Avantages : la clé privée ne quitte jamais le serveur cible. Inconvénients : plus complexe, nécessite un workflow de distribution de CSR.

Fenêtre de terminal
vault write pki_int/issue/webserver \
common_name="api.example.com" \
ttl=720h

Sortie :

Key Value
--- -----
ca_chain [-----BEGIN CERTIFICATE-----...]
certificate -----BEGIN CERTIFICATE-----...
expiration 1747389600
issuing_ca -----BEGIN CERTIFICATE-----...
private_key -----BEGIN RSA PRIVATE KEY-----...
private_key_type rsa
serial_number 5a:c2:1b:4d:7f...
Fenêtre de terminal
vault write pki_int/issue/webserver \
common_name="frontend.example.com" \
alt_names="www.example.com,cdn.example.com" \
ttl=720h
Fenêtre de terminal
vault write -format=json pki_int/issue/webserver \
common_name="backend.example.com" \
ttl=720h | tee \
>(jq -r '.data.certificate' > backend.crt) \
>(jq -r '.data.private_key' > backend.key) \
>(jq -r '.data.ca_chain[]' > ca-chain.crt) \
> /dev/null
chmod 600 backend.key
chmod 644 backend.crt ca-chain.crt

Limitez qui peut émettre des certificats par rôle :

pki-webserver-policy.hcl
# Émettre via issue (Vault génère la clé)
path "pki_int/issue/webserver" {
capabilities = ["create", "update"]
}
# Signer une CSR (client génère la clé)
path "pki_int/sign/webserver" {
capabilities = ["create", "update"]
}
# Lire les infos de la CA
path "pki_int/cert/ca" {
capabilities = ["read"]
}
Fenêtre de terminal
vault policy write pki-webserver pki-webserver-policy.hcl

La qualité de votre PKI dépend de la distribution réelle des URLs, pas seulement de leur configuration dans Vault.

Fenêtre de terminal
vault write pki_int/config/urls \
issuing_certificates="https://vault.example.com/v1/pki_int/ca" \
crl_distribution_points="https://vault.example.com/v1/pki_int/crl"
  1. Accessibilité : les URLs doivent être joignables par tous les clients qui valident les certificats (navigateurs, services, reverse proxies)

  2. Résolution DNS : le nom vault.example.com doit résoudre correctement dans tous les environnements

  3. TLS valide : ironie, le endpoint doit avoir un certificat valide (bootstrap problem à résoudre)

  4. Haute disponibilité : si Vault est down, les validations CRL échouent (selon la politique du client)

Fenêtre de terminal
# Fréquence de mise à jour de la CRL
vault write pki_int/config/crl expiry="72h"
Fenêtre de terminal
curl -s "https://vault.example.com/v1/pki_int/crl" | \
openssl crl -inform DER -text -noout
Fenêtre de terminal
vault list pki_int/certs
Fenêtre de terminal
vault read pki_int/cert/<serial_number>
Fenêtre de terminal
vault write pki_int/revoke serial_number="5a:c2:1b:4d:7f:..."

Vault stocke les métadonnées des certificats émis. Pour nettoyer :

Fenêtre de terminal
vault write pki_int/tidy \
tidy_cert_store=true \
tidy_revoked_certs=true \
tidy_revoked_cert_issuer_associations=true \
safety_buffer="72h"
ParamètreDescription
tidy_cert_storeSupprimer les métadonnées des certificats expirés
tidy_revoked_certsSupprimer les métadonnées des certificats révoqués expirés
safety_bufferNe pas toucher aux certificats expirés depuis moins de X

Pour les workloads Kubernetes, cert-manager avec le provider Vault est la solution recommandée :

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: vault-issuer
spec:
vault:
# Pour issue (Vault génère la clé) : path "pki_int/issue/webserver"
# Pour sign (CSR) : path "pki_int/sign/webserver"
path: pki_int/sign/webserver
server: https://vault.example.com
auth:
kubernetes:
role: cert-manager
mountPath: auth/kubernetes

Vault Agent peut gérer le renouvellement automatique :

agent-config.hcl
template {
source = "/etc/vault-agent/cert.tpl"
destination = "/etc/ssl/certs/myapp/cert.pem"
perms = "0644"
command = "systemctl reload nginx"
}
template {
source = "/etc/vault-agent/key.tpl"
destination = "/etc/ssl/certs/myapp/key.pem"
perms = "0600"
}

Pour les environnements simples sans Vault Agent :

#!/bin/bash
set -e
SERVICE_NAME="myapp"
CERT_DIR="/etc/ssl/certs/$SERVICE_NAME"
ROLE="webserver"
CN="$SERVICE_NAME.example.com"
TTL="720h"
mkdir -p "$CERT_DIR"
vault write -format=json "pki_int/issue/$ROLE" \
common_name="$CN" \
ttl="$TTL" | tee \
>(jq -r '.data.certificate' > "$CERT_DIR/cert.pem") \
>(jq -r '.data.private_key' > "$CERT_DIR/key.pem") \
>(jq -r '.data.ca_chain[]' > "$CERT_DIR/ca.pem") \
> /dev/null
chmod 600 "$CERT_DIR/key.pem"
systemctl reload nginx
echo "$(date): Certificate renewed for $CN" >> /var/log/cert-renewal.log
# Renouveler tous les 25 jours (TTL 30 jours)
0 3 */25 * * /opt/scripts/renew-cert.sh >> /var/log/cert-renewal.log 2>&1
ResponsabilitéVault PKIVous
Générer des certificats
Stocker la clé privée après émission
Distribuer les certificats aux services
Recharger les services (reload nginx, etc.)
Installer la Root CA dans les trust stores
Monitorer les expirations❌*
Garantir la qualité du design PKI

*Vault expose des métriques, mais le monitoring est à votre charge.

SymptômeCause probableSolution
domain not allowedCN non autorisé par le rôleVérifier allowed_domains du rôle
TTL exceeds maxTTL demandé > max_ttl du rôleRéduire le TTL ou augmenter max_ttl
certificate has expiredCertificat non renouveléVérifier le cron/automation
unknown authorityCA chain incomplèteInclure la chaîne complète côté client
permission deniedPolicy manquanteVérifier les capabilities issue/sign
unable to fetch CRLURL CRL inaccessibleVérifier réseau et DNS
Fenêtre de terminal
# Voir les dates d'expiration
openssl x509 -in cert.pem -noout -dates
# Voir le CN et SAN
openssl x509 -in cert.pem -noout -subject -ext subjectAltName
# Vérifier la chaîne de confiance
openssl verify -CAfile ca-chain.pem cert.pem
# Voir les URLs AIA et CRL
openssl x509 -in cert.pem -noout -text | grep -A2 "Authority Information Access"
openssl x509 -in cert.pem -noout -text | grep -A1 "CRL Distribution Points"
  1. Root CA hors de Vault : machine air-gapped ou HSM dédié
  2. Un mount = un niveau : pki pour la root (si dans Vault), pki_int pour l’intermédiaire
  3. Rotation d’issuer : préparer le nouvel issuer avant expiration de l’ancien
  1. Un rôle par usage : pas de rôle générique multi-domaines
  2. TTL courts : 30-90 jours pour les services, 24-72h pour le mTLS
  3. enforce_hostnames=true : toujours
  4. allow_ip_sans=false : sauf besoin explicite documenté
  1. Tidy régulier : nettoyer les certificats expirés/révoqués
  2. Monitoring : alerter sur les certificats proches de l’expiration
  3. Audit : tracer toutes les émissions
  4. Backup : la Root CA est critique, sauvegardez-la séparément
  1. Root CA hors de Vault en production — seule l’intermédiaire est dans Vault
  2. issue : Vault génère clé + cert — simple mais clé en transit
  3. sign : client envoie CSR — clé reste locale
  4. Rôles stricts : un rôle par domaine/usage, pas de wildcard global
  5. URLs accessibles : les CRL et AIA doivent être joignables par les clients
  6. Multi-issuer : depuis 1.11+, rotation sans interruption possible
  7. Tidy : nettoyez les métadonnées des certificats expirés
  8. Vault ≠ distribution : vous restez responsable de l’installation des certificats sur les services

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn