Autorité de certification souveraine pour l'émission et la gestion de certificats à l'échelle de l'entreprise
Gestion du cycle de vie des certificats : découverte, gouvernance et automatisation
Domain Control Validation agnostique des DNS, prêt pour les certificats TLS de 47 jours
SPIFFE est une spécification graduée de la CNCF qui définit une identité workload portable et vérifiable cryptographiquement. SPIRE en est l'implémentation de référence. Ensemble, ils remplacent les secrets partagés, les jetons porteurs et les clés de bootstrap par des SVIDs à durée de vie courte, distribués via une Workload API locale, et donnent à chaque service, VM et pod une identité qu'il peut prouver sur le réseau.
SPIFFE — Secure Production Identity Framework For Everyone — est une spécification graduée de la CNCF qui définit une identité portable et vérifiable cryptographiquement pour les workloads logiciels. Un SPIFFE ID ressemble à spiffe://prod.example/ns/payments/sa/api et est encodé soit comme URI dans le Subject Alternative Name d'un certificat X.509 (X.509-SVID), soit comme claim dans un JWT signé (JWT-SVID). Le format est volontairement minimaliste : il porte un trust domain, un chemin, et rien sur la manière dont le workload a été authentifié.
SPIRE est l'implémentation de référence. Elle s'exécute sous forme d'un Serveur central qui émet les certificats et les JWTs, et d'un Agent par nœud qui expose une Workload API locale (socket Unix) à chaque processus de la machine. L'Agent procède à l'attestation de chaque workload appelant — par ServiceAccount Kubernetes, document d'identité d'instance AWS, unité systemd, image de conteneur, tout élément pouvant être rattaché cryptographiquement au nœud — et le Serveur signe un SVID à TTL court, typiquement une heure par défaut.
La logique est opérationnelle, pas philosophique. SPIFFE remplace les secrets partagés et les jetons porteurs à longue durée de vie par une identité que les workloads peuvent prouver sur le réseau, et unifie la manière dont cette identité est amorcée à travers Kubernetes, les VMs classiques et le bare metal. C'est le socle d'un mTLS de qualité production et de la moitié « workload » de toute posture Zero Trust sérieuse.
Pendant l'essentiel des vingt dernières années, la réponse concrète à « comment le service A s'authentifie-t-il auprès du service B ? » a pris la forme d'un secret partagé. Une clé d'API commitée dans un fichier de configuration, un jeton porteur à longue durée de vie monté comme Kubernetes Secret, un mot de passe de base de données figé dans une variable d'environnement, une clé privée générée une fois et copiée sur l'ensemble d'une flotte. Le mécanisme variait ; le mode de défaillance, non. Chaque secret finit par fuiter — vers un fichier de log, une sauvegarde, un artefact de CI, une stack trace — et une fois sorti, le workload qui le détenait n'a aucun moyen de prouver que ce n'est pas lui qui l'a laissé filer.
SPIFFE a été conçu pour rendre cette conversation différente. Au lieu de donner aux workloads un secret à retenir, on leur donne un nom qu'ils peuvent prouver, une identité liée à l'endroit où le workload tourne et à ce qu'il est, pas à une chaîne de caractères qu'il se trouve détenir. La spécification, hébergée par la CNCF et graduée en 2022, définit à quoi ressemble une identité workload (le SPIFFE ID), comment elle est encodée sur le réseau (X.509-SVID et JWT-SVID) et comment un workload en obtient une (la Workload API). SPIRE, également gradué CNCF, est l'implémentation de référence sur laquelle la spec se lit. Il en existe d'autres — Istio émet des identités au format SPIFFE nativement, Linkerd aussi, et une poignée de plateformes cloud parlent la Workload API — mais c'est avec SPIRE que les patterns de production sont les plus lisibles.
Ce guide parcourt ce que la spec définit vraiment, comment SPIRE la met en œuvre et où elle se place à côté de votre PKI existante.
La spec est volontairement courte. Elle définit un format d'identité, deux formats de SVID, et une API locale. Tout le reste — comment fonctionne l'attestation, comment la CA émettrice est opérée, comment les identités sont révoquées — est laissé à l'implémentation. Le flux de bout en bout que SPIRE réalise ressemble à ceci.
C'est la Workload API elle-même que la plupart des nouveaux venus sous-estiment. Le workload ne parle jamais au Serveur SPIRE. Il ne détient jamais d'identifiant à longue durée de vie. Il n'a pas de « join token » ni de « fichier de clé de service account » qui traîne sur disque. Son identité est réémise chaque heure et lui est poussée à travers un flux sur un socket local — et si le workload migre, meurt ou redémarre ailleurs, le prochain processus à ouvrir ce socket sera identifié sur ses propres mérites, pas parce qu'il a hérité d'un secret.
Un opérateur choisit un nom de trust domain (par exemple `prod.example`) et provisionne un Serveur SPIRE pour celui-ci. Le Serveur détient la CA émettrice — soit une racine auto-signée, soit, plus couramment, une intermédiaire signée par une CA en amont — et publie un trust bundle que tout vérificateur du domaine peut récupérer.
Un processus sur un nœud ouvre le socket Unix `/run/spire/agent/api.sock` et appelle la Workload API. Il ne présente aucun identifiant. Le noyau expose à l'Agent son PID, UID, GID et autres métadonnées de processus via `SO_PEERCRED` et `/proc`.
L'Agent exécute un ou plusieurs plugins d'attestation de charge contre ce processus — Kubernetes (dans quel pod est ce PID, quel ServiceAccount, quel digest d'image de conteneur), Docker, unité systemd, UID Unix, empreinte du binaire parent. Les plugins renvoient un ensemble de sélecteurs. L'Agent compare ces sélecteurs aux entrées d'enregistrement reçues du Serveur et décide à quel SPIFFE ID, le cas échéant, cette charge a droit.
L'Agent transmet la requête au Serveur, qui signe un X.509-SVID (un certificat feuille dont l'URI dans le SAN est le SPIFFE ID) ou un JWT-SVID (un JWT signé dont le claim `sub` est le SPIFFE ID). Le TTL par défaut est d'une heure pour les X.509-SVIDs, de cinq minutes pour les JWT-SVIDs. L'Agent met en cache le résultat et diffuse les mises à jour vers le workload avant expiration.
La charge présente son X.509-SVID lors des handshakes mTLS (des deux côtés) et utilise les JWT-SVIDs là où le mTLS n'est pas praticable — messagerie asynchrone, délégation au périmètre d'une requête, appels à travers une passerelle L7 qui termine TLS. Le trust bundle publié par le Serveur indique à chaque vérificateur du trust domain quelle CA suivre dans la chaîne.
Quand deux trust domains doivent communiquer — par exemple un cluster de staging et un cluster de production, ou deux entités métier — leurs Serveurs échangent des trust bundles signés. Une charge dans `staging.example` présentant un SVID à une charge dans `prod.example` n'est acceptée que si le Serveur local a été configuré pour fédérer avec `staging.example` et si un bundle correspondant a été importé.
Une URI de la forme `spiffe://
La forme « sur le fil » d'une identité. Deux variantes : X.509-SVID (un certificat à courte durée de vie portant le SPIFFE ID dans l'URI du SAN, utilisé pour mTLS) et JWT-SVID (un JWT signé portant le SPIFFE ID dans `sub`, utilisé là où mTLS ne convient pas). Les deux sont signés par la CA émettrice du trust domain.
L'ensemble des certificats de CA (X.509) et des clés publiques (JWT) que les vérificateurs d'un trust domain utilisent pour valider les SVIDs. Publié par le Serveur, diffusé aux Agents et aux charges via la Workload API, et renouvelé automatiquement.
Le socket Unix local (`/run/spire/agent/api.sock` par convention) que les charges appellent. Défini comme un service gRPC dans la spec SPIFFE, avec deux RPCs qui comptent en production : `FetchX509SVID` (renvoie SVID + trust bundle, diffuse les mises à jour) et `FetchJWTSVID` (renvoie un JWT pour une audience donnée).
L'Agent exécute des node attestors (preuve du nœud sur lequel il tourne — AWS instance identity, GCP instance identity, Kubernetes PSAT, Azure MSI, x509pop) et des workload attestors (preuve de ce qu'est un processus appelant — pod Kubernetes, conteneur Docker, unité systemd, UID Unix). La combinaison attestation de nœud + attestation de charge est ce qui lie un SPIFFE ID à un morceau de logiciel en cours d'exécution.
La comparaison qui compte dans la plupart des revues d'ingénierie oppose SPIFFE/SPIRE aux patterns à secret partagé qu'il remplace — un jeton de ServiceAccount Kubernetes monté en fichier, un identifiant IAM cloud amorcé au démarrage, une clé d'API statique dans un coffre. Les deux colonnes ressemblent à ceci.
Les colonnes ne sont pas symétriques. Les jetons porteurs gagnent sur la simplicité — rien à attester, pas d'Agent à déployer, pas de socket à monter, pas de spec à lire. SPIFFE gagne partout où la durée de vie, le rayon d'impact ou la portabilité comptent. La plupart des parcs en production finissent par utiliser les deux : SPIFFE à l'intérieur du périmètre, et des jetons porteurs pour le trafic nord-sud qui doit traverser des tiers.
| Secret partagé / jeton SA | SPIFFE / SPIRE | |
|---|---|---|
| Preuve d'identité | Possession d'une chaîne porteuse ; quiconque détient le fichier est la charge | Possession cryptographique d'une clé liée à l'identité attestée du processus et du nœud |
| Durée de vie | Jours à années ; les jetons de ServiceAccount durent un an par défaut sauf s'ils sont projetés | Une heure par défaut pour les X.509-SVIDs, quelques minutes pour les JWT-SVIDs |
| Rotation | Manuelle ou via une automatisation externe ; en pratique souvent oubliée | Continue, poussée par l'Agent avant expiration, transparente pour la charge |
| Rayon d'impact | Chaque requête que le secret peut authentifier, jusqu'à rotation et révocation | Au plus le TTL restant d'un seul SVID, sur un seul nœud |
| Portabilité | Liée à la plateforme qui émet le jeton (K8s, IAM cloud, éditeur) | Un format d'identité unique sur Kubernetes, VMs, bare metal, on-prem, multi-cloud |
| Compatibilité mTLS | Nulle — les jetons porteurs vivent au niveau applicatif | Native — les X.509-SVIDs sont des certificats client et serveur valides dès la sortie de boîte |
La manière la plus propre de se convaincre qu'un SVID est un vrai certificat X.509 est de l'inspecter avec `openssl`. Le SPIFFE ID vit dans le SAN sous forme d'URI, et nulle part ailleurs — le Subject est vide par conception.
Deux détails méritent attention. Le `notAfter` est à une heure de distance, pas à un an, et le seul Subject Alternative Name est une URI — pas de nom DNS, pas d'email, pas de CN à mettre en correspondance. Un vérificateur TLS classique qui attend un nom d'hôte rejettera ce certificat ; les vérificateurs d'un déploiement SPIFFE sont configurés pour comparer sur l'URI du SAN, via des bibliothèques comme go-spiffe v2.
# Fetch and inspect a workload's current X.509-SVID
spire-agent api fetch x509 -socketPath /run/spire/agent/api.sock \
-write /tmp/svid
openssl x509 -in /tmp/svid/svid.0.pem -noout -text | grep -A1 'Subject Alternative Name'
# X509v3 Subject Alternative Name:
# URI:spiffe://prod.example/ns/payments/sa/api
openssl x509 -in /tmp/svid/svid.0.pem -noout -dates
# notBefore=Jun 17 09:14:22 2026 GMT
# notAfter =Jun 17 10:14:22 2026 GMT Dans SPIRE, l'opérateur déclare quels sélecteurs autorisent un workload à quel SPIFFE ID au travers d'une entrée d'enregistrement. Dans un déploiement Kubernetes, le moyen le plus propre est la CRD `ClusterSPIFFEID` du SPIRE Controller Manager, qui génère des entrées à partir de sélecteurs de labels, au gré du cycle de vie des pods.
La CRD n'émet rien par elle-même ; elle indique au Serveur SPIRE de produire des entrées d'enregistrement que l'Agent, après attestation de nœud, mettra en correspondance avec les pods appelants. L'attestation de nœud, elle, a déjà eu lieu — typiquement via `k8s_psat` (Projected ServiceAccount Token), qui lie l'identité de l'Agent à la vue du nœud par le kubelet, et non à un join token à longue durée de vie.
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: payments-api
spec:
# SPIFFE ID template — interpolated per matching pod
spiffeIDTemplate: "spiffe://prod.example/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
# Which pods this entry covers
podSelector:
matchLabels:
app.kubernetes.io/name: payments-api
app.kubernetes.io/component: api
# Restrict to a single namespace
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: payments
# SVID lifetime — one hour is the SPIRE default
ttl: 1h
# Optional: federate with another trust domain
federatesWith:
- "staging.example" La bibliothèque go-spiffe v2 cache presque tout. Le workload ouvre un `X509Source` contre la Workload API, le passe à la configuration TLS, et ne pense plus jamais aux certificats — rotation, rafraîchissement du trust bundle et fédération se passent en arrière-plan.
Le même pattern à l'envers — `tlsconfig.MTLSClientConfig` plus `AuthorizeID(...)` — vous donne un client qui ne parle qu'à un SPIFFE ID précis. L'autorisation pilotée par l'identité devient, en d'autres termes, une seule ligne de configuration : pas de parsing de certificat, pas de comparaison de SAN, pas de validation de chaîne à la main.
package main
import (
"context"
"log"
"net/http"
"github.com/spiffe/go-spiffe/v2/spiffeid"
"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
"github.com/spiffe/go-spiffe/v2/workloadapi"
)
func main() {
ctx := context.Background()
// Open a streaming source against the local Workload API.
// The library connects to /run/spire/agent/api.sock by default
// and keeps the SVID + trust bundle up to date in memory.
source, err := workloadapi.NewX509Source(ctx)
if err != nil {
log.Fatalf("workload API: %v", err)
}
defer source.Close()
// Only accept peers whose SPIFFE ID lives in this trust domain.
td := spiffeid.RequireTrustDomainFromString("prod.example")
tlsCfg := tlsconfig.MTLSServerConfig(source, source, tlsconfig.AuthorizeMemberOf(td))
server := &http.Server{
Addr: ":8443",
TLSConfig: tlsCfg,
Handler: http.HandlerFunc(handle),
}
log.Fatal(server.ListenAndServeTLS("", ""))
}
func handle(w http.ResponseWriter, r *http.Request) {
// r.TLS.PeerCertificates[0] carries the caller's SPIFFE ID in the SAN URI.
w.Write([]byte("ok\n"))
} La force d'un déploiement SPIFFE ne tient pas aux certificats émis — ce sont des X.509 banals — mais à l'attestation qui décide qui en obtient lequel. Un Serveur SPIRE configuré avec l'ancien node attestor `k8s_sat` accepte tout appelant détenant un jeton de ServiceAccount, c'est-à-dire le même secret partagé que SPIFFE était censé éliminer. L'attestor PSAT (`k8s_psat`) lie l'attestation à un jeton projeté, à audience restreinte et courte durée de vie, que le kubelet rafraîchit ; sur des nœuds cloud, utilisez l'attestor d'identité d'instance natif (`aws_iid`, `gcp_iit`, `azure_msi`). L'attestation de charge devrait épingler le digest de l'image de conteneur, pas son nom, et le ServiceAccount, pas seulement le namespace. Le rayon d'impact d'un attestor mal configuré, c'est l'intégralité du trust domain.
Un SVID d'une heure est une fonctionnalité, pas un problème — mais seulement si le workload le relit avant expiration. Des bibliothèques comme go-spiffe le gèrent de manière transparente parce qu'elles diffusent depuis la Workload API. Des clients faits maison qui récupèrent une fois au démarrage et réutilisent le certificat sont un mode de défaillance classique : ça marche très bien en staging, puis ça casse simultanément sur toute la flotte exactement une heure après le déploiement. Considérez tout chemin de code qui touche un SVID sur fichier comme un bug ; les SVIDs doivent vivre en mémoire, rafraîchis par la bibliothèque.
Le Serveur SPIRE est la CA émettrice du trust domain. S'il est en panne, aucun nouveau SVID n'est émis ; les SVIDs existants continuent de fonctionner jusqu'à expiration de leur TTL. Exécutez le Serveur en mode HA (plusieurs réplicas partageant un datastore SQL ou PostgreSQL) et traitez la clé émettrice comme n'importe quelle clé de CA — adossez-la à un HSM, faites-la tourner selon un calendrier, et planifiez une séquence de rollover du trust bundle qui chevauche ancien et nouveau bundles afin qu'aucun vérificateur ne voie momentanément un signataire inconnu.
La fédération est la manière dont SPIFFE règle le cas multi-domaines — staging qui parle à prod, on-prem qui parle à une landing zone cloud, une entité métier qui parle à une autre. Elle fonctionne en échangeant des trust bundles signés entre Serveurs et en configurant les vérificateurs de chaque côté pour accepter les SPIFFE IDs de l'autre. Le mécanisme est simple ; la politique ne l'est pas. La fédération transforme la compromission d'un trust domain distant en votre problème. Traitez chaque entrée `federatesWith` comme une décision délibérée et documentée, avec une réponse claire à « que se passe-t-il quand leur Serveur est compromis ? ».
Par défaut, un Serveur SPIRE peut auto-signer sa CA émettrice, ce qui est pratique pour des démos et inutile en production. Dans toute organisation qui exploite déjà une PKI d'entreprise, SPIRE devrait être configuré avec une CA signée en amont : SPIRE génère un CSR d'intermédiaire, la racine d'entreprise ou une CA émettrice hors ligne signe ce CSR, et SPIRE émet les SVIDs depuis cette intermédiaire. Les vérificateurs hors monde SPIFFE (load balancers, services historiques, partenaires) remontent alors la chaîne vers la même racine à laquelle ils font déjà confiance, et votre inventaire de certificats couvre les identités workload au même titre que le reste.
CA en amont pour SPIRE — Evertrust PKI signe l'intermédiaire que SPIRE utilise pour émettre les SVIDs, de sorte que les identités workload remontent jusqu'à la même racine gouvernée et auditée que vos autres certificats TLS et client. La génération des clés peut être adossée à un HSM, la politique et la durée de vie de l'intermédiaire sont appliquées de façon centralisée, et faire tourner la clé émettrice de SPIRE devient une opération routinière d'intermédiaire, plutôt qu'une procédure sur mesure.
Visibilité à l'échelle du workload — Evertrust CLM ingère les certificats émis par SPIRE en même temps que les certificats à longue durée de vie qui protègent serveurs, load balancers et équipements, pour qu'un seul inventaire couvre les millions de SVIDs d'une heure qu'un cluster actif émet par jour et les certificats classiques renouvelés à l'agenda. Prévention des coupures, supervision des expirations et découverte fonctionnent de la même façon des deux côtés.
Une politique unique pour l'humain et la machine — le même modèle de gouvernance qui valide un nouveau certificat de signature de code ou un profil mTLS partenaire valide aussi un nouveau trust domain SPIFFE, un lien de fédération ou une configuration d'attestor. Deux surfaces opérationnelles — PKI d'entreprise à longue durée de vie et identité workload à courte durée de vie — convergent vers une seule politique, une seule piste d'audit et une seule source de vérité.