---
{
  "title": "Les extensions FHIR comme pont vers la gestion externe des secrets",
  "description": "Stockez des secrets dans des ressources FHIR sans en stocker les valeurs. Aidbox les résout à partir de fichiers montés par un coffre au moment de l'exécution. Sécurisé, dynamique et sans dépendance envers un fournisseur particulier.",
  "date": "2026-03-09",
  "author": "Andrew Listopadov, Ivan Bagrov",
  "reading-time": "15 minutes",
  "tags": [
    "System Design",
    "FHIR Standard"
  ]
}
---
Nous voulions qu'Aidbox soit entièrement dynamique — configurable au moment de l'exécution, et pas seulement au moment du déploiement. Nous avons donc modélisé les Clients, les IdentityProviders, les TokenIntrospectors et les AidboxTopicDestinations comme des ressources FHIR. Vous pouvez créer une nouvelle destination Kafka ou enregistrer un fournisseur d'identité via l'API FHIR standard, sans redémarrage requis.

Cependant, les ressources FHIR sont persistées dans la base de données. Et certaines de ces ressources contiennent des secrets — des identifiants clients, des clés privées, des configurations SASL pour Kafka. Les secrets statiques comme les mots de passe de base de données ou les clés de licence résident en toute sécurité dans des variables d'environnement et ne touchent jamais la base de données. Mais un Client ou un IdentityProvider créé dynamiquement? Son secret fait partie de la ressource, et la ressource est stockée dans la base de données.

Nous avions besoin d'un moyen d'avoir des secrets à l'intérieur de ressources FHIR sans pour autant y stocker les valeurs réelles des secrets.

À partir de la version 2602, Aidbox résout ce problème grâce aux [extensions primitives FHIR](https://www.health-samurai.io/docs/aidbox/configuration/secret-files#extension-pattern). Une ressource ne contient pas la valeur du secret — elle porte une extension `data-absent-reason` marquée `masked` ainsi qu'une référence à un nom de secret logique. Aidbox résout ce nom vers un fichier sur le système de fichiers au moment de l'exécution, lit la valeur et l'utilise. La valeur réelle du secret n'atteint jamais la base de données ni l'API.

Pour la couche du système de fichiers, nous ne voulions pas construire un connecteur dédié pour chaque coffre — cela représente un fardeau de maintenance qui évolue mal et lie les équipes à des fournisseurs spécifiques. Nous avons plutôt choisi l'interface la plus simple possible : un chemin de fichier. De nombreux coffres populaires — Azure Key Vault, HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager — disposent déjà de fournisseurs du pilote CSI Secrets Store qui montent les secrets sous forme de fichiers dans les Pods Kubernetes. D'autres peuvent être intégrés par l'entremise d'outils externes ou de scripts qui écrivent les valeurs des secrets dans des fichiers. Les Kubernetes Secrets, les Docker Secrets et les montages liés simples fonctionnent également. Du moment que le secret se retrouve dans un fichier, Aidbox peut l'utiliser — sans modules d'extension, sans SDK de fournisseur, sans code d'intégration personnalisé.

## Comment ça fonctionne

Le mécanisme est simple. Il comporte trois éléments :
- **Des fichiers secrets sur le système de fichiers.** Votre coffre ou orchestrateur place les valeurs des secrets sous forme de fichiers à l'intérieur du Pod Aidbox. C'est le seul contrat — un fichier à un chemin connu.
- **Un fichier de configuration du coffre.** Un fichier JSON associe des noms de secrets logiques à des chemins du système de fichiers et déclare quelles ressources sont autorisées à utiliser chaque secret. Vous indiquez ce fichier à Aidbox via la variable d'environnement `BOX_VAULT_CONFIG`.
- **[Des extensions FHIR](/articles/extending-fhir-resources) sur les ressources.** Plutôt que de stocker directement une valeur de secret, une ressource marque le champ comme `masked` et inclut une référence au nom de secret logique. Aidbox le résout au moment de l'exécution.

Lorsqu'Aidbox a besoin d'un secret — par exemple pour authentifier un client — il lit le nom du secret dans la ressource, recherche le chemin du fichier dans la configuration du coffre, vérifie que la ressource est autorisée à y accéder (application de la portée), lit le fichier et utilise la valeur. La valeur du secret n'est jamais retournée via l'API : les réponses aux requêtes `GET` ne contiennent que la référence.

## La configuration du coffre

La configuration du coffre est un fichier JSON avec un objet `secret`. Chaque clé est un nom logique, et la valeur précise où se trouve le fichier et qui peut l'utiliser :


```javascript
{
  "secret": {
    "my-client-secret": {
      "path": "/run/secrets/my-client-secret",
      "scope": { "resource_type": "Client", "id": "my-client" }
    },
    "idp-private-key": {
      "path": "/run/secrets/idp-key",
      "scope": { "resource_type": "IdentityProvider" }
    }
  }
}
```


Le champ `scope` contrôle l'accès. Vous pouvez restreindre un secret à un type de ressource spécifique, ou le limiter davantage à un identifiant de ressource précis. Si une ressource qui ne figure pas dans la portée tente de résoudre un secret, Aidbox retourne une erreur non autorisée.

Aidbox charge ce fichier une seule fois au démarrage. Si vous modifiez la configuration du coffre, vous devez redémarrer Aidbox. Cependant, les *fichiers secrets eux-mêmes* sont mis en cache avec un court délai d'expiration et validés selon l'heure de modification du fichier — ainsi, la rotation des secrets fonctionne sans redémarrage.

## Référencer des secrets dans les ressources

Les ressources utilisent des extensions primitives FHIR pour référencer les secrets. Voici un Client avec un secret géré par un coffre :


```javascript
PUT /fhir/Client/my-client
```



```javascript
{
  "resourceType": "Client",
  "id": "my-client",
  "_secret": {
    "extension": [
      {
        "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
        "valueCode": "masked"
      },
      {
        "url": "http://health-samurai.io/fhir/secret-reference",
        "valueString": "my-client-secret"
      }
    ]
  },
  "grant_types": ["client_credentials", "basic"]
}
```


Sa relecture retourne exactement la même structure — l'extension avec le nom du secret, jamais la valeur :


```javascript
GET /fhir/Client/my-client
```



```javascript
{
  "resourceType": "Client",
  "id": "my-client",
  "_secret": {
    "extension": [
      {
        "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
        "valueCode": "masked"
      },
      {
        "url": "http://health-samurai.io/fhir/secret-reference",
        "valueString": "my-client-secret"
      }
    ]
  },
  "grant_types": ["client_credentials", "basic"]
}
```


Mais l'authentification fonctionne comme prévu — Aidbox lit le secret depuis le fichier monté et l'utilise pour valider les identifiants :


```javascript
# Works — Aidbox resolves the secret from the filesystem
curl -u my-client:the-actual-secret-value http://aidbox/fhir/Patient

# Fails — wrong password
curl -u my-client:wrong-password http://aidbox/fhir/Patient
```


## Quelles ressources prennent en charge les secrets externes

Les secrets externes ne se limitent pas aux identifiants clients. Voici la liste complète des ressources et des champs pris en charge :

| Ressource | Champ | Cas d'utilisation |
| --- | --- | --- |
| Client | secret | Authentification du client |
| IdentityProvider | client.secret | Authentification symétrique |
| IdentityProvider | client.private-key | Matériel de clé asymétrique |
| IdentityProvider | client.certificate | Certificat pour l'authentification asymétrique |
| TokenIntrospector | jwt.secret | Clé de vérification JWT |
| TokenIntrospector | jwt.keys.k | Clé de validation symétrique |
| TokenIntrospector | introspection_endpoint.authorization | Jeton Bearer / en-tête d'autorisation |
| AidboxTopicDestination | parameter.saslJaasConfig | Configuration SASL Kafka |
| AidboxTopicDestination | parameter.sslKeystoreKey | Clé SSL Kafka |

Cela couvre les cas les plus courants : les identifiants d'authentification, les clés de fournisseurs d'identité, la vérification des jetons et les secrets d'infrastructure de messagerie.

## Rotation des secrets

L'un des principaux avantages des secrets externes est la rotation sans interruption de service. Le déroulement dépend de la façon dont les secrets sont acheminés vers le système de fichiers :
- **Pilote CSI Secrets Store :** Le pilote CSI interroge le coffre pour détecter les modifications. Lorsqu'un secret est mis à jour dans Azure Key Vault (ou un autre coffre), le pilote écrit la nouvelle valeur dans le fichier monté. Aidbox détecte la modification du fichier et récupère la nouvelle valeur au prochain accès — aucun redémarrage requis.
- **Kubernetes Secrets :** Lorsque l'objet Secret est mis à jour, Kubernetes propage la modification aux volumes montés. Aidbox détecte le fichier mis à jour et invalide son cache.
- **Docker Secrets / montages liés :** Mettez à jour le fichier sur l'hôte. Aidbox récupérera la modification en fonction de l'heure de modification du fichier.

Dans tous les cas, la distinction importante est la suivante : le *fichier de configuration du coffre* (indiqué par `BOX_VAULT_CONFIG`) est chargé une seule fois au démarrage et nécessite un redémarrage pour être modifié. Les *fichiers secrets* vers lesquels il pointe sont mis en cache avec un court délai d'expiration et validés selon les horodatages de modification, de sorte qu'ils se renouvellent automatiquement.

## Déploiement avec HashiCorp Vault

Nous disposons d'un [tutoriel complet étape par étape](https://www.health-samurai.io/docs/aidbox/tutorials/other-tutorials/hashicorp-vault-external-secrets) qui guide à travers un déploiement de HashiCorp Vault sur Kubernetes à partir de zéro. Voici le déroulement général :

1. Déployez HashiCorp Vault et stockez vos secrets.

2. Installez le pilote CSI Secrets Store et le fournisseur Vault sur votre grappe.

3. Configurez un rôle et une politique Vault accordant un accès en lecture aux secrets dont vos ressources Aidbox ont besoin.

4. Créez un SecretProviderClass qui indique au pilote CSI quels secrets récupérer depuis Vault.

5. Créez une configuration de coffre sous forme de ConfigMap, en associant les noms de secrets logiques aux chemins de fichiers montés.

6. Déployez Aidbox avec deux montages de volumes : le volume CSI pour les secrets et le ConfigMap pour la configuration du coffre.
Configurez BOX_VAULT_CONFIG pour pointer vers le fichier de configuration.

Une fois déployé, les secrets de HashiCorp Vault apparaissent sous forme de fichiers à l'intérieur du Pod. Aidbox les lit au moment de l'exécution — et lorsque vous effectuez la rotation d'un secret dans le coffre, le pilote CSI met à jour le fichier automatiquement sans redémarrage nécessaire.

Le même schéma s'applique aux autres coffres dotés de fournisseurs CSI (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager). Pour la référence complète de la configuration du coffre et du format des extensions, consultez la [documentation sur les secrets externes](https://www.health-samurai.io/docs/aidbox/configuration/secret-files).

## Et ensuite

External Secrets est disponible dès maintenant dans Aidbox 2602 et les versions ultérieures. Si vous exécutez Aidbox sur Kubernetes et gérez vos secrets via un coffre, cette intégration élimine le besoin de stocker des valeurs sensibles dans la base de données. Votre coffre continue de faire ce qu'il fait le mieux — rotation, audit, contrôle d'accès — et Aidbox résout les secrets au moment de l'exécution à partir du système de fichiers.

Nous aimerions savoir comment vous gérez les secrets dans vos déploiements FHIR. Quels coffres utilisez-vous? Qu'est-ce qui a été difficile? Rejoignez [Zulip](https://connect.health-samurai.io/) pour explorer les détails d'implémentation avec notre équipe.

Voir aussi : [Les garanties techniques HIPAA d'Aidbox](/blog/aidbox-hipaa-book-technical-safeguards) et la [feuille de route Aidbox 2025](/blog/aidbox-2025-building-a-future-proof-fhir-platform).