Aller au contenu

Chapitre 13. Identity, et la chaîne complète

Objectifs pédagogiques

Expliquer entités, alias et groupes, et l'articulation de leurs policies avec celles des rôles. Dérouler la chaîne complète d'un login. Mettre en service l'authentification AppRole du fil rouge de bout en bout. Relire l'imputabilité dans l'audit et exécuter une révocation ciblée. Mapper des groupes d'un fournisseur d'identité. Préserver la continuité d'identité à travers plusieurs méthodes.

Prérequis

Les trois chapitres précédents, que celui-ci assemble. Le TP 4 est supposé fait ; le TP 6 rejouera la section 13.4.

Cours

13.1 Pourquoi une couche d'identité

Le chapitre 2 a posé le principe : les droits suivent l'identité, pas le moyen de preuve. Jusqu'ici, les policies sont attachées aux rôles, et un acteur qui s'authentifie par deux méthodes serait deux acteurs.

L'entité est l'acteur canonique, objet propre de Vault avec un nom, des métadonnées et éventuellement ses propres policies. L'alias relie une entité à une méthode d'authentification. Une entité peut avoir plusieurs alias, un par méthode, et c'est toute la valeur : billing authentifié par AppRole et billing authentifié par Kubernetes sont le même acteur, avec la même trace d'audit, les mêmes policies d'identité, la même histoire.

Un comportement à connaître : au premier login d'une identité inconnue, Vault crée automatiquement une entité et son alias, nommés techniquement, sans intention. C'est un filet, pas une architecture. La pratique propre pré-crée les entités qui comptent, avec leurs vrais noms et métadonnées.

Détail documenté qui servira dans dix minutes : pour AppRole, le nom d'alias attendu est le role_id.

13.2 Les groupes

Les groupes rassemblent des entités et portent des policies. Les groupes internes ont des membres gérés dans Vault. Les groupes externes sont le mécanisme le plus important pour les humains : sans membres gérés, ils ont un alias de groupe vers une méthode, et l'appartenance est déclarée par l'amont à chaque login.

[Laboratoire]. Le mapping du fil rouge ; la valeur du claim doit correspondre au nom d'alias :

vault write identity/group name="ops" type="external" \
  policies="ops-backup,ops-audit"

OIDC_ACCESSOR=$(vault auth list -format=json | jq -r '.["oidc/"].accessor')

vault write identity/group-alias name="ops" \
  mount_accessor="$OIDC_ACCESSOR" \
  canonical_id="$(vault read -field=id identity/group/name/ops)"

L'architecture qui en résulte : l'appartenance se gère dans le fournisseur d'identité, arrivées, départs et mutations étant l'affaire de l'annuaire ; les droits se gèrent dans Vault, policies versionnées et revues ; et la jointure est une déclaration d'une ligne. Personne ne recopie de listes de personnes dans Vault, personne ne délègue l'écriture de policies à l'annuaire.

13.3 La chaîne complète d'un login

   preuve (mdp, secret_id, jeton signe, certificat)
        |
        v
   methode d'authentification -- le ROLE borne la population,
        |                        fixe durees et bornes du token
        v
   ALIAS (montage, nom) ------>  ENTITE canonique
                                    |         \
                                    |          appartenances de GROUPES
                                    v
   TOKEN emis, portant l'union :
     policies du role  U  policies de l'entite  U  policies des groupes
     (+ default, sauf exclusion)  --  et l'entity_id, pour l'audit

Les policies d'entité et de groupe s'appliquent au moment de l'usage : ajouter une policy au groupe équipe immédiatement tous ses tokens vivants, sans re-login. Et l'entity_id voyage dans chaque entrée d'audit : l'imputabilité est un champ, pas une intention.

13.4 AppRole de bout en bout

La première authentification applicative du fil rouge, dans l'ordre exact que le TP 6 rejouera.

Étape 1 : la méthode et le rôle, durcis d'emblée. [Laboratoire]

vault auth enable approle

vault write auth/approle/role/billing \
  token_policies="billing-kv" \
  token_ttl=1h token_max_ttl=4h \
  token_bound_cidrs="10.10.30.21/32" \
  secret_id_ttl=10m \
  secret_id_num_uses=1 \
  secret_id_bound_cidrs="10.10.30.21/32"

La spécification du chapitre 12, mot pour mot : le token vivra une heure, quatre au plafond, depuis app-billing-01 seulement ; et le secret zéro résiduel est réduit à dix minutes, un usage, une origine.

Étape 2 : l'identité, avant le premier login. [Laboratoire]

ROLE_ID=$(vault read -field=role_id auth/approle/role/billing/role-id)

ENTITY_ID=$(vault write -format=json identity/entity \
  name="billing" metadata=app="billing" metadata=owner="equipe-billing" \
  | jq -r '.data.id')

APPROLE_ACCESSOR=$(vault auth list -format=json | jq -r '.["approle/"].accessor')

vault write identity/entity-alias \
  name="$ROLE_ID" \
  canonical_id="$ENTITY_ID" \
  mount_accessor="$APPROLE_ACCESSOR"

Le role_id part dans la configuration de déploiement : c'est un identifiant, pas un coffre ni un chuchotement.

Étape 3 : le secret_id, sous enveloppe. [Laboratoire]

vault write -wrap-ttl=120s -f auth/approle/role/billing/secret-id

La sortie n'est pas un secret_id : c'est un jeton d'enveloppe, deux minutes, un usage. C'est lui seul qui transite par le canal de déploiement. L'opérateur qui l'a généré n'a jamais vu le secret_id, le système de déploiement non plus.

Étape 4 : ouvrir, se connecter, ranger. [Laboratoire]

#!/bin/sh
set -eu
export VAULT_ADDR="https://vault-core-01.astrea.lab:8200"
export VAULT_CACERT="/etc/billing/vault-ca.crt"

ROLE_ID="$(cat /etc/billing/role-id)"            # configuration : l'identifiant
WRAP_TOKEN="$(cat /run/billing/wrap-token)"      # depose par le deploiement

# Ouvrir l'enveloppe : une seule fois possible. Un echec ici est une ALARME
# (enveloppe expiree, ou deja ouverte par quelqu'un d'autre).
SECRET_ID="$(vault unwrap -field=secret_id "$WRAP_TOKEN")"
rm -f /run/billing/wrap-token

# Login AppRole : la preuve est consommee, le token est emis
VAULT_TOKEN="$(vault write -field=token auth/approle/login \
  role_id="$ROLE_ID" secret_id="$SECRET_ID")"
unset SECRET_ID

# Ranger le token : fichier 0600 sur tmpfs, lisible du seul service
umask 077
printf '%s' "$VAULT_TOKEN" > /run/billing/vault-token

Chaque ligne applique un chapitre : la vérification TLS du 7, l'enveloppe et sa détection d'interception du 12, la preuve à usage unique du 10, le token hors environnement et hors historique du 1, posé sur un système de fichiers en mémoire.

Étape 5 : vérifier, puis vérifier les refus. Trois contrôles. Le token : la consultation montre les policies attendues, le TTL en décompte, et un entity_id qui est celui de l'entité créée à l'étape 2, ce qui prouve la jointure d'alias. Les droits : la lecture du secret de production réussit, celle d'un chemin hors périmètre échoue en 403, et ce refus fait partie de la recette. L'audit enfin : les entrées portent l'entity_id, l'accessor du token, l'adresse d'origine, le chemin en clair et la valeur en empreinte.

Étape 6 : rotation et nettoyage des secret_id. L'usage unique fait de chaque déploiement une rotation de fait. Restent les accidents, un secret_id généré et jamais utilisé : chacun a son accessor, listable et destructible.

[Laboratoire]

vault list auth/approle/role/billing/secret-id
vault write auth/approle/role/billing/secret-id-accessor/destroy \
  secret_id_accessor="<accessor>"

13.5 La continuité d'identité

La migration vers Kubernetes donnera à billing une seconde méthode d'authentification. Le réflexe naïf laisserait l'auto-création faire, et billing deviendrait deux acteurs : deux entités, deux historiques, une imputabilité fendue au pire moment.

La couche Identity l'évite : un second alias, le nom du compte de service sur l'accessor du montage Kubernetes, sera attaché à la même entité. Une identité, deux preuves, une histoire. C'est la raison pour laquelle la pré-création de l'étape 2 n'était pas du zèle : les entités qui comptent durent plus longtemps que leurs méthodes.

Exemple : la révocation à froid

La chaîne est déroulée : le déploiement dépose l'enveloppe, billing se connecte seule, l'entity_id apparaît dans l'audit. La relecture en équipe suit requête par requête le login, les lectures légitimes et le 403 de recette ; l'accessor du token est noté au registre.

Puis l'exercice qui fâche, voulu par la RSSI : une révocation à froid. Depuis le poste d'administration, vault token revoke -accessor <accessor>.

Effet immédiat : les lectures de l'application échouent. L'application tente de se reconnecter, et échoue aussi, son secret_id à usage unique ayant été consommé le matin. C'est le comportement prévu, et tout l'intérêt de l'exercice : il chiffre le coût du choix num_uses=1. La remise en service exige un nouveau secret_id wrappé, soit un cycle de déploiement.

L'arbitrage est alors tranché et consigné : l'usage unique est conservé, parce qu'il rend tout secret_id volé sans valeur après le premier login légitime, et la procédure de relivraison est documentée pour être exécutable en quelques minutes plutôt que découverte en incident.

Sécurité : la chaîne dans son ensemble

Les deux moitiés ne voyagent jamais ensemble. Le role_id vit dans la configuration, le secret_id dans une enveloppe périssable. Un canal qui verrait les deux durablement reconstituerait le credential complet et annulerait le découpage.

L'échec d'unwrap est une alarme, pas une erreur. Deux cas se distinguent : enveloppe expirée, incident bénin, ou enveloppe déjà ouverte, incident majeur. La consultation sans consommation et les journaux du déploiement les départagent ; le second déclenche la procédure du chapitre 31.

Les bornes se cumulent. Origine du secret_id, origine du token, durée du secret_id, durée du token, usage unique : cinq bornes indépendantes sur un même credential, dont aucune ne suffit seule.

L'identité est ce qui reste. Les méthodes changent, les plateformes migrent, les tokens expirent. L'entité, elle, porte l'histoire d'audit et les droits : c'est l'objet dont la gouvernance compte le plus dans la durée.

Erreurs fréquentes

Laisser l'auto-création nommer les identités. Des entités techniques sans propriétaire ni métadonnées, multipliées au premier alias venu : l'audit devient une devinette (sections 13.1, 13.4).

Livrer le secret_id en clair juste cette fois. Dans une variable de CI, un ticket, un gestionnaire partagé : le chapitre 1 réinstallé au cœur du système qui devait le résoudre (section 13.4).

Une enveloppe au délai généreux. Un secret qui traîne, et une détection d'interception diluée (section 13.4).

Oublier que le nom d'alias AppRole est le role_id. L'alias créé avec le nom du rôle ne joint jamais, et l'auto-création fabrique une seconde entité en silence (section 13.1).

Gérer les appartenances dans Vault plutôt que dans l'annuaire. Des listes de personnes recopiées, qui divergent dès la première mutation (section 13.2).

Croire qu'une policy de groupe exige un re-login. Elle s'applique aux tokens vivants, ce qui est précisément le levier d'administration courant (section 13.3).

Ne jamais exercer la révocation. Le coût du choix num_uses=1 se découvre alors en incident, pas en exercice (Exemple).

Mise en pratique : la chaîne de la CI

Sans machine ; le chapitre 39 et le TP 6 exécuteront. Réponses commentées en fin de partie.

  1. Rédigez la séquence de configuration côté Vault : montage jwt-github, rôle ci-billing avec ses bornes, policies et durées.
  2. Décrivez la pré-création d'identité qui donne à la CI une entité propre, et dites sur quelle valeur l'alias doit être construit.
  3. Énumérez les champs qu'une entrée d'audit de déploiement montrera, puis précisez ce que cette chaîne n'a pas eu à livrer, et pourquoi.

Questions de compréhension

  1. Définissez entité, alias et groupe, et le principe du chapitre 2 que la couche Identity implémente.
  2. Que fait l'auto-création au premier login, pourquoi existe-t-elle, et pourquoi pré-créer malgré tout ?
  3. Distinguez groupes internes et externes, et décrivez la répartition des responsabilités qu'ils permettent.
  4. Restituez le schéma de la chaîne complète et la composition exacte des policies du token émis.
  5. Pourquoi une policy ajoutée à un groupe agit-elle sur les tokens déjà émis ?
  6. Déroulez les six étapes de la mise en service AppRole, en citant l'acquis mobilisé à chaque fois.
  7. Quel est le nom d'alias attendu pour AppRole, et que se passe-t-il en cas d'erreur ?
  8. Expliquez pourquoi l'application ne peut pas se reconnecter après la révocation de l'exemple, et l'arbitrage que cela révèle.
  9. Comment la continuité d'identité se préserve-t-elle lors d'une migration de plateforme ?

Synthèse

La couche Identity donne à la chaîne son pivot : des entités canoniques que l'on nomme et possède, des alias qui y rattachent chaque méthode de preuve, des groupes dont les externes délèguent l'appartenance à l'amont en gardant les droits dans Vault. Le token final porte l'union des policies du rôle, de l'entité et des groupes, avec l'entity_id dans chaque ligne d'audit. Sur ce socle, la mise en service de billing a tout assemblé : un rôle durci, un secret zéro réduit à dix minutes et un usage, livré sous enveloppe à détection d'interception. S'y ajoutent un script qui n'expose rien, des recettes qui testent les refus, un audit nominatif, et un exercice de révocation qui a transformé un arbitrage théorique en décision datée. Déclenche le TP 6 (énoncé en partie XV).