Aller au contenu

Chapitre 40. Intégration applicative

Objectifs pédagogiques

Arbitrer entre consommation directe par bibliothèque et délégation à un agent. Configurer l'agent de bout en bout et situer le proxy. Comparer les modes de consommation. Gérer la rotation sans coupure. Écrire une application qui traverse une indisponibilité de Vault. Solder l'exception de durée ouverte au chapitre 28.

Prérequis

Chapitre 13 (la chaîne d'authentification applicative), chapitre 18 (le cycle de vie des credentials et le comportement en panne), chapitre 26 (la doctrine de réessai), chapitre 28 (l'exception à solder).

Cours

40.1 Deux façons de consommer

Une application peut parler à Vault elle-même, par l'API ou une bibliothèque cliente. Elle peut aussi déléguer à un processus voisin, l'agent, qui s'authentifie, obtient les secrets, les met à disposition sous forme de fichiers et entretient les renouvellements. Le choix n'est pas idéologique et se décide sur quatre critères.

La maîtrise du code : une application qu'on ne modifie pas, progiciel, binaire tiers ou code hérité sans équipe, ne peut pas parler à Vault, et l'agent est alors la seule voie. Le nombre d'équipes : imposer une bibliothèque à quinze équipes, c'est imposer quinze mises à jour à chaque changement de doctrine, quand l'agent centralise la logique dans un composant unique. La finesse d'usage : une application qui fait du chiffrement à chaque requête, ou qui lit des secrets dépendant de son contexte d'exécution, a besoin d'un client dans le code ; un service qui a besoin de trois valeurs au démarrage n'en a pas. La culture d'exploitation, enfin : l'agent ajoute un processus à superviser.

La recommandation générale du cursus penche vers la délégation, et la raison est celle du chapitre 1 : moins l'application contient de logique de sécurité, moins elle contient d'occasions de se tromper. Les cas de client direct restent légitimes, et le chapitre 16 en fournit le plus clair, le chiffrement comme service se consommant dans le code et non par fichier.

40.2 L'agent en profondeur

L'agent assure trois fonctions, qu'une configuration complète montre toutes.

[Laboratoire]

# /etc/vault-agent.d/agent.hcl
vault {
  address = "https://vault.astrea.lab:8200"
}

auto_auth {
  method "approle" {
    config = {
      role_id_file_path   = "/etc/vault-agent.d/role_id"
      secret_id_file_path = "/run/vault-agent/secret_id"
      remove_secret_id_file_after_reading = true
    }
  }
  sink "file" {
    config = { path = "/run/vault-agent/token", mode = 0640 }
  }
}

template {
  source      = "/etc/vault-agent.d/db.env.tpl"
  destination = "/run/billing/db.env"
  perms       = "0640"
  command     = "systemctl reload billing"
}

cache {
  use_auto_auth_token = true
}

listener "tcp" {
  address     = "127.0.0.1:8100"
  tls_disable = true
}

L'authentification automatique reprend la méthode du chapitre 13 et lui ajoute ce que le cursus réclamait : la suppression de l'identifiant secret après lecture, l'entretien du token par renouvellement, et la reprise automatique quand une authentification échoue. Le puits écrit le token à un emplacement que d'autres processus peuvent lire, avec ses permissions : c'est ainsi qu'un outil qui parle déjà à Vault évite d'implémenter sa propre authentification.

Le gabarit est la fonction la plus utile : l'agent rend un fichier à partir d'un modèle, le maintient à jour lorsque la valeur change ou que le bail se renouvelle, et exécute une commande après écriture.

DB_USER={{ with secret "database/creds/billing-app" }}{{ .Data.username }}{{ end }}
DB_PASS={{ with secret "database/creds/billing-app" }}{{ .Data.password }}{{ end }}

L'application ne connaît alors ni Vault, ni les baux, ni les renouvellements : elle lit un fichier et se recharge quand on le lui demande. Le cache, enfin, mémorise les réponses et gère le renouvellement des baux pour les clients qui passent par l'écouteur local, ce qui évite qu'une flotte de processus interroge le serveur en parallèle.

Note de version : depuis la version 1.14, les fonctions de mandataire sont distribuées dans un binaire distinct, tandis que l'agent conserve l'authentification automatique et les gabarits. La distinction est utile pour lire la documentation et choisir le bon outil : le proxy sert d'intermédiaire pour des clients qui parlent l'API, l'agent produit des fichiers pour des applications qui n'en parlent pas.

40.3 Trois modes de consommation

Mode Avantage Limite
Variables au démarrage simplicité lisibles par les moyens du chapitre 1, et rotation impossible sans redémarrage
Fichier rendu par gabarit fraîcheur, rechargement sans coupure exige un service capable de relire sa configuration
Appel direct depuis le code usages non précalculables exige du code correct et une bibliothèque à jour

Le fichier rendu est le mode recommandé. Il vit dans un volume en mémoire, ses permissions sont strictes, et le rechargement se fait par signal ou par commande : un service bien écrit sait relire sa configuration sans couper les connexions en cours, exactement comme Vault le fait pour ses propres certificats.

L'appel direct garde sa place pour les usages qui ne peuvent pas être précalculés : le chiffrement comme service, la génération de certificats à la demande, la lecture de secrets dépendant d'un contexte.

40.4 Rotation sans coupure

Un secret qui change pendant que l'application tourne est le cas normal du modèle dynamique, et c'est là que les intégrations naïves échouent. Trois mécanismes suffisent.

Le rechargement plutôt que le redémarrage : sur signal, l'application relit sa configuration, ouvre les nouvelles connexions avec les nouveaux identifiants et laisse les anciennes s'éteindre naturellement.

Le pool de connexions doit être conçu pour cela : les connexions existantes restent valides jusqu'à leur fermeture, le compte de base existant encore jusqu'à son échéance, et seules les nouvelles utilisent le credential frais. Une purge brutale du pool à chaque rotation produit des erreurs visibles pour les utilisateurs, alors que la transition peut être invisible.

La marge, enfin : l'agent renouvelle bien avant l'échéance et rend le nouveau secret disponible avant que l'ancien ne meure. Une application qui découvre l'expiration par une erreur d'authentification a été mal outillée.

40.5 Les modes de défaillance

La partie VI l'avait annoncé : le modèle dynamique fait de Vault une dépendance de démarrage et de renouvellement. Quatre situations méritent un traitement explicite.

Vault indisponible au démarrage. L'application ne peut pas obtenir ses secrets. Le comportement correct est de réessayer avec un espacement croissant, en journalisant clairement la cause, plutôt que de s'arrêter immédiatement ou de boucler à toute vitesse. Sous orchestrateur, cela se traduit par une sonde de démarrage tolérante ; sur une machine, par une unité qui retente.

Vault indisponible en régime établi. Les credentials en cours restent valables : l'application continue de fonctionner et doit simplement retenter ses renouvellements sans paniquer. C'est le cas où une intégration mal écrite transforme une panne de quelques minutes en incident applicatif, en invalidant ses connexions parce qu'un appel a échoué.

Bascule du cluster. Quelques secondes d'erreurs, retentées avec succès. La doctrine est celle des réessais : lectures toujours, écritures avec discernement.

Credential révoqué ou expiré. L'application doit distinguer une erreur d'authentification d'une erreur de service et réagir en conséquence : réobtenir un credential plutôt que de réessayer indéfiniment avec le même. C'est le seul cas où l'erreur signale une action à mener, pas une attente.

Une exigence transversale traverse ces quatre cas : ne jamais journaliser un secret, y compris dans les traces d'erreur, où une chaîne de connexion complète se retrouve trop souvent.

40.6 Ce que l'agent solde

Le chapitre 28 avait accordé aux certificats des nœuds une exception documentée en la bornant explicitement, la renvoyant au chapitre 40 pour le jour où l'agent aurait industrialisé le renouvellement. La dette arrive à échéance.

Un agent installé sur chaque nœud, authentifié par son identité, rend le certificat par gabarit et exécute le rechargement après écriture.

{{ with pkiCert "pki-int/issue/astrea-services" "common_name=vault.astrea.lab" "alt_names=vault-core-01.astrea.lab" "ttl=72h" }}
{{ .Data.Cert }}{{ .Data.CA }}{{ .Data.Key }}
{{ end }}

Le renouvellement devient un mécanisme plutôt qu'un minuteur, la durée revient à celle des autres services, et l'exception se ferme au registre. Le même dispositif équipe les services applicatifs, ce qui rend enfin praticable la doctrine du chapitre 17 : des certificats courts partout, parce que la révocation ne se croit pas.

L'alerte de dernier filet du chapitre 28 est conservée : un renouvellement qui échoue en silence reste possible, et le contrôle du contrôle ne se supprime pas parce que l'outil s'est amélioré.

Exemple : billing, version finale

Le service de facturation tel qu'il tourne à la fin du cursus, décrit du point de vue de son équipe, qui n'a écrit aucune ligne de code Vault.

Le démarrage. Le pod démarre avec son conteneur adjacent. L'agent s'authentifie par l'identité de plateforme, obtient un token d'une heure, et rend deux fichiers dans un volume en mémoire : les identifiants de base de données issus du moteur dynamique, et le certificat client du service. Il exécute une commande de rechargement à chaque changement.

Le fonctionnement. L'application lit ces fichiers au démarrage et sur signal ; son pool ouvre les nouvelles sessions avec les identifiants courants et laisse les anciennes s'éteindre. Pour le chiffrement des coordonnées bancaires, elle appelle Transit directement, avec le token du puits, parce que ce cas ne se précalcule pas.

Ce que l'équipe connaît de tout cela : deux chemins de fichiers, un signal de rechargement, une consigne de réessai. Le reste, méthode d'authentification, durées, renouvellements, rotation trimestrielle de la clé, bascules du cluster, appartient à l'infrastructure et change sans qu'aucune ligne de code applicatif ne bouge.

La dernière ligne du registre du chantier le formule ainsi : « L'objectif n'était pas que billing sache utiliser Vault. Il était que billing n'ait plus besoin de le savoir. »

Sécurité : l'application et son voisinage

Le fichier rendu est un secret sur disque. Volume en mémoire, permissions strictes, propriétaire dédié : les mêmes exigences que pour une clé privée. Un gabarit qui écrit dans un répertoire persistant annule le bénéfice du modèle dynamique.

Le puits de token est un accès complet. Qui lit le fichier de token dispose des droits de l'application. Ses permissions valent celles du secret le plus élevé qu'il permet d'atteindre.

Le cache local est une surface. Un écouteur ouvert au-delà de la boucle locale offre à tout voisin les droits du token qu'il porte.

Les traces d'erreur fuient plus que les journaux applicatifs. Chaînes de connexion complètes, en-têtes, corps de requêtes : les bibliothèques verbeuses affichent volontiers ce qu'il ne faut pas. Le contrôle se fait à l'écriture du code et se vérifie par lecture des traces réelles.

Erreurs fréquentes

Écrire un client Vault par application. Quinze implémentations de la même logique, quinze occasions de se tromper (section 40.1).

Passer les secrets par variables d'environnement. Lisibles par les moyens du chapitre 1, et incompatibles avec toute rotation sans redémarrage (section 40.3).

Vider brutalement le pool de connexions à chaque rotation. Des erreurs visibles alors que la transition pouvait être invisible (section 40.4).

S'arrêter au premier échec de Vault au démarrage. Une panne de deux minutes devient une indisponibilité longue et une intervention humaine (section 40.5).

Invalider ses connexions parce qu'un renouvellement a échoué. Les credentials en cours restent valables : l'application doit continuer et retenter (section 40.5).

Confondre erreur d'authentification et erreur de service. Retenter indéfiniment avec un credential révoqué n'aboutit jamais (section 40.5).

Laisser le fichier de token lisible trop largement. Il porte les droits complets de l'application (Sécurité).

Mise en pratique : outiller l'application

Sur papier ; réponses commentées en fin de partie.

  1. Rédigez la configuration d'agent complète pour un service qui a besoin de credentials de base de données, d'un certificat client et d'un accès au chiffrement comme service, en justifiant chaque bloc et chaque permission.
  2. Écrivez, en pseudo-code commenté d'une vingtaine de lignes, la logique de démarrage et de rechargement d'une application conforme à la doctrine, avec le traitement des quatre modes de défaillance.
  3. Une équipe refuse l'agent au motif qu'il ajoute un processus à exploiter et préfère lire Vault au démarrage par un appel direct, sans renouvellement. Rédigez l'analyse : ce qui fonctionnera, ce qui cassera, et à quelle échéance.

Questions de compréhension

  1. Donnez les quatre critères d'arbitrage entre bibliothèque et agent, et le cas où le client direct reste le bon choix.
  2. Décrivez les trois fonctions de l'agent et ce que chacune évite à l'application.
  3. Que distingue l'agent du proxy, et depuis quelle version ?
  4. Comparez les trois modes de consommation et dites pourquoi les variables d'environnement sont écartées en production.
  5. Quels trois mécanismes permettent une rotation sans coupure, et quelle erreur de pool produit des incidents visibles ?
  6. Détaillez les quatre modes de défaillance et le comportement correct pour chacun.
  7. Pourquoi l'erreur d'authentification appelle-t-elle une réaction différente des autres erreurs ?
  8. Que solde ce chapitre concernant les certificats d'infrastructure, et quel contrôle est conservé malgré l'automatisation ?
  9. Que connaît, au final, l'équipe applicative, et pourquoi est-ce l'objectif ?

Synthèse

Une application consomme Vault soit par son propre code, soit par délégation à un agent, et le cursus penche pour la seconde voie : moins l'application contient de logique de sécurité, moins elle a d'occasions de se tromper. L'agent apporte trois fonctions, authentification automatique avec puits de token, gabarits qui rendent des fichiers et déclenchent un rechargement, cache qui mutualise les renouvellements. Le mode recommandé est le fichier rendu, en mémoire, avec rechargement sans coupure. La rotation devient invisible dès lors que le pool laisse s'éteindre les anciennes connexions et que la marge de renouvellement précède l'échéance. Restent les modes de défaillance, à traiter explicitement plutôt qu'à découvrir en incident. L'agent solde enfin l'exception ouverte au chapitre 28. Et billing, au terme du cursus, ne sait plus rien de Vault, ce qui était l'objectif.