Configuration en code et environnements

Comparer export et import de realm, provider Terraform et keycloak-config-cli pour décrire la configuration de Keycloak en code, la promouvoir d'un environnement à l'autre et tenir les secrets hors du dépôt.

Approfondir Cours 15 sur 17 de Keycloak Academy 40 min 4 questions de quiz Cours suivant : Points d'extension et coût de maintenance

Sur cette page
  1. Ce qu’on décrit en code, et ce qu’on n’y met pas
  2. Export et import de realm
  3. Le provider Terraform
  4. keycloak-config-cli
  5. Choisir son outillage
  6. Promouvoir d’un environnement à l’autre
  7. Les secrets
  8. À retenir pour l’architecture
  9. Natif, extension ou hébergeur
  10. Quiz

Configurer Keycloak à la main dans la console fonctionne pour un essai. Dès qu’il y a plusieurs environnements (développement, recette, production) et plusieurs personnes, la configuration doit vivre dans un dépôt Git : relue, versionnée, rejouable. Ce cours compare les trois approches les plus courantes, puis traite la promotion entre environnements et les secrets.

Ce qu’on décrit en code, et ce qu’on n’y met pas

La configuration couvre le realm et ses réglages, les clients, les client scopes et protocol mappers, les rôles, les groupes, les flux d’authentification, les fournisseurs d’identité et la fédération d’annuaire. Elle exclut les comptes des usagers, qui relèvent du provisionnement, ainsi que les sessions et les événements. Seuls quelques comptes techniques, comme des comptes de test en recette, ont leur place dans le dépôt.

Export et import de realm

Keycloak sait exporter et importer un realm complet en JSON :

bin/kc.sh export --realm socle --dir /tmp/export --users skip
bin/kc.sh import --dir /tmp/export --override false

Ces commandes s’exécutent avec le serveur arrêté, sur la même base de données. Au démarrage, l’option --import-realm importe les fichiers JSON du dossier data/import, mais ignore un realm déjà présent. Les fichiers importés peuvent contenir des placeholders résolus depuis l’environnement, par exemple "secret": "${PORTAIL_SECRET}".

L’export partiel de la console (Realm settings, menu Action) n’exporte pas les utilisateurs et masque les secrets par des astérisques. La documentation précise qu’il ne convient ni aux sauvegardes ni aux transferts entre serveurs.

L’export est un bon point de départ et un bon outil de sauvegarde, mais un mauvais format de travail. Il contient tous les identifiants internes et toutes les valeurs par défaut, et il ne sait pas faire évoluer un realm existant par différence.

Le provider Terraform

Le provider Terraform pour Keycloak est maintenu dans l’organisation GitHub keycloak et publié sur le registry sous keycloak/keycloak (il s’appelait auparavant mrparkers/keycloak). Un état existant migre avec terraform state replace-provider mrparkers/keycloak keycloak/keycloak. Le projet annonce supporter officiellement les trois dernières versions mineures de Keycloak.

terraform {
  required_providers {
    keycloak = {
      source  = "keycloak/keycloak"
      version = "~> 5.10"
    }
  }
}

provider "keycloak" {
  url           = var.keycloak_url
  realm         = "master"
  client_id     = "terraform"
  client_secret = var.terraform_client_secret
}

resource "keycloak_realm" "socle" {
  realm        = "socle"
  enabled      = true
  ssl_required = "external"
  login_theme  = var.login_theme
}

resource "keycloak_openid_client" "portail" {
  realm_id                   = keycloak_realm.socle.id
  client_id                  = "portail"
  access_type                = "CONFIDENTIAL"
  standard_flow_enabled      = true
  pkce_code_challenge_method = "S256"
  valid_redirect_uris        = ["${var.portail_url}/callback"]
}

Forces : terraform plan montre l’écart avant d’agir, ce qui détecte les modifications manuelles (la dérive) ; les références entre ressources sont typées ; Terraform est souvent déjà utilisé pour l’infrastructure. Limites : chaque ressource Keycloak doit avoir son équivalent dans le provider, avec parfois un temps de retard sur les nouveautés ; l’état contient des secrets.

keycloak-config-cli

keycloak-config-cli, projet communautaire d’adorsys, applique un état décrit en JSON ou YAML au format d’export de realm. Il est idempotent : relancé sur un realm déjà conforme, il ne change rien. Il mémorise dans le realm ce qu’il a créé (remote state), ce qui lui permet de supprimer une ressource retirée du fichier sans toucher à ce qui a été créé autrement (comportement par défaut, réglable par les options import.managed.* et import.remote-state.*). Le projet vise les quatre dernières versions de Keycloak et publie des images Docker étiquetées par version de Keycloak.

realm: "socle"
enabled: true
loginTheme: "keycloak"
roles:
  realm:
    - name: "agent"
groups:
  - name: "agents"
    realmRoles:
      - "agent"
clients:
  - clientId: "portail"
    protocol: "openid-connect"
    publicClient: false
    standardFlowEnabled: true
    redirectUris:
      - "$(env:PORTAIL_URL)/callback"
    secret: "$(env:PORTAIL_SECRET)"
    attributes:
      pkce.code.challenge.method: "S256"

La substitution $(env:…) n’est active qu’avec IMPORT_VARSUBSTITUTION_ENABLED=true, et elle s’exécute là où tourne l’outil. Forces : le format est celui que la console exporte, donc familier ; pas d’état externe à stocker ; un fichier par realm ou par domaine fonctionnel. Limites : pas de plan préalable aussi lisible que celui de Terraform ; l’outil dépend d’un tiers et doit suivre les versions de Keycloak.

Choisir son outillage

CritèreExport / import natifTerraformkeycloak-config-cli
Faire évoluer un realm existantNon (écrasement ou rien)Oui, par différenceOui, par convergence
Voir l’écart avant d’appliquerNonOui (plan)Partiel (journaux)
FormatJSON complet et bruitéHCLJSON ou YAML au format d’export
Stockage d’un étatAucunÉtat Terraform, contient des secretsDans le realm, chiffrable
DépendanceAucuneProvider externeOutil communautaire
Cas d’usage typeSauvegarde, initialisation d’un posteÉquipe déjà outillée Terraform, infrastructure et IAM ensembleÉquipe proche de Keycloak, migration d’une configuration existante

Les deux outils couvrent le besoin. Le critère décisif est souvent l’existant de l’équipe d’exploitation. Évitez de mélanger deux outils sur le même realm : chacun croirait que l’autre crée de la dérive.

Promouvoir d’un environnement à l’autre

Une chaîne saine suit trois règles :

  1. Une source unique. Les mêmes fichiers servent à tous les environnements. Ce qui varie (URL, redirect URIs, thème, secrets, durées) passe par des variables.
  2. Un ordre fixe. Développement, puis recette, puis production, avec relecture des changements avant chaque passage.
  3. Pas de modification manuelle en production. Les droits de la console de production sont limités à la consultation pour l’équipe projet. Toute correction passe par le dépôt, sinon la prochaine application l’écrase.

Les identifiants internes (UUID) diffèrent d’un environnement à l’autre : les fichiers doivent référencer les objets par leur nom (clientId, nom de rôle), jamais par UUID.

Les secrets

Trois familles de secrets circulent dans cette chaîne :

  • Les secrets des clients confidentiels. Ils n’entrent pas dans le dépôt. Soit ils sont injectés depuis un coffre au moment de l’application, soit Keycloak les génère et l’outil les lit pour les transmettre à l’application. Depuis 26.8, la rotation des secrets clients est supportée : deux secrets peuvent être actifs pendant la transition. Quand l’application le permet, l’authentification par clé privée signée évite tout secret partagé.
  • Le secret de l’outil lui-même. L’outil s’authentifie avec un compte de service. S’il crée des realms, il lui faut le rôle admin du realm master, un droit très large à protéger comme tel. S’il ne gère qu’un realm, le rôle realm-admin de ce realm suffit.
  • L’état. L’état Terraform contient les secrets en clair : backend distant chiffré, accès restreint. keycloak-config-cli peut chiffrer son état distant avec une clé dédiée.

Appliquer un realm décrit en YAML

30 min

Installer le lab
  1. Créez un dossier kcc et un fichier kcc/socle-lab.yaml reprenant l’exemple YAML du cours, en remplaçant socle par socle-lab.

  2. Appliquez-le avec keycloak-config-cli (sous macOS ou Windows, remplacez --network host et localhost par host.docker.internal) :

    docker run --rm --network host \
      -e KEYCLOAK_URL=http://localhost:8080 \
      -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin \
      -e IMPORT_FILES_LOCATIONS='/config/*' \
      -e IMPORT_VARSUBSTITUTION_ENABLED=true \
      -e PORTAIL_URL=http://localhost:3000 \
      -e PORTAIL_SECRET=secret-de-dev-uniquement \
      -v "$PWD/kcc":/config \
      adorsys/keycloak-config-cli:latest-26
  3. Dans la console, vérifiez le realm socle-lab, le client portail (PKCE en S256, redirect URI résolue), le rôle agent et le groupe agents.

  4. Relancez exactement la même commande : les journaux indiquent qu’il n’y a rien à modifier.

  5. Ajoutez un rôle superviseur au fichier, relancez, puis retirez-le et relancez encore. Observez la création puis la suppression du rôle.

  6. Créez à la main un rôle manuel dans la console, puis relancez l’outil : avec le remote state actif (réglage par défaut), il n’est pas supprimé, car l’outil ne l’a pas créé.

  7. Faites un export partiel par l’API et regardez le secret du client :

    KC=http://localhost:8080
    TOKEN=$(curl -s -d client_id=admin-cli -d username=admin -d password=admin \
      -d grant_type=password "$KC/realms/master/protocol/openid-connect/token" | jq -r .access_token)
    curl -s -X POST -H "Authorization: Bearer $TOKEN" \
      "$KC/admin/realms/socle-lab/partial-export?exportClients=true&exportGroupsAndRoles=true" \
      | jq '.clients[] | select(.clientId=="portail") | {clientId, secret}'
  8. Le secret est masqué. Notez pourquoi cet export ne peut pas servir à promouvoir la configuration vers un autre environnement.

À retenir pour l’architecture

Le document d’architecture doit trancher un outil (Terraform ou keycloak-config-cli), décrire la chaîne de promotion et ses validations, interdire la modification manuelle en production, et dire où vivent les secrets. Vérifiez avec l’hébergeur que la chaîne de déploiement peut joindre l’Admin REST API de chaque environnement, et avec quel compte technique.

Natif, extension ou hébergeur

Natif : fourni par Keycloak, à configurer. Extension : demande du code à maintenir (un SPI, le mécanisme de plugin de Keycloak). Hébergeur : dépend de la plateforme qui héberge Keycloak, à vérifier avec elle.

CapacitéVerdictPrécision
Export et import de realm (commandes kc.sh, import au démarrage)NatifFiable pour sauvegarder ou initialiser un environnement. L'import au démarrage ignore un realm déjà présent.
Variables d'environnement dans les fichiers de realm importésNatifSyntaxe de placeholder documentée dans le guide Importing and exporting realms.
Provider Terraform keycloak/keycloakExtensionOutil externe au serveur, maintenu dans l'organisation GitHub keycloak. Supporte officiellement les trois dernières versions mineures.
keycloak-config-cliExtensionOutil communautaire (adorsys) qui applique un état décrit en JSON ou YAML au format d'export de realm.
Rotation des secrets clientsNatifSupportée et activée par défaut depuis 26.8, pilotée par les client policies.
Accès à l'Admin REST API depuis la chaîne de déploiementHébergeurOuverture réseau, comptes techniques et environnements disponibles sont à vérifier avec l'hébergeur.

Vérifier ce que vous avez retenu

4 questions

  1. Vous voulez que la recette et la production aient la même configuration de clients, avec des URL et des secrets différents. Quelle approche retenez-vous ?

  2. L'équipe veut utiliser --import-realm au démarrage pour appliquer chaque modification de configuration en production. Quel est le problème ?

  3. Avec Terraform, où se retrouvent les secrets des clients confidentiels ?

  4. Quelle population ne devrait pas être gérée par l'outil de configuration en code ?