---
{
  "title": "FHIR Extensions als Brücke zum externen Secret-Management",
  "description": "Speichern Sie Secrets in FHIR-Ressourcen, ohne die eigentlichen Werte zu speichern. Aidbox löst sie zur Laufzeit aus vault-gemounteten Dateien auf. Sicher, dynamisch und ohne Vendor-Lock-in.",
  "date": "2026-03-09",
  "author": "Andrew Listopadov, Ivan Bagrov",
  "reading-time": "15 minutes",
  "tags": [
    "System Design",
    "FHIR Standard"
  ]
}
---
Unser Ziel war es, Aidbox vollständig dynamisch zu gestalten — konfigurierbar zur Laufzeit, nicht nur zum Zeitpunkt des Deployments. Daher haben wir Clients, IdentityProviders, TokenIntrospectors und AidboxTopicDestinations als FHIR-Ressourcen modelliert. Sie können ein neues Kafka-Ziel anlegen oder einen Identity-Provider über die Standard-FHIR-API registrieren, ohne einen Neustart durchführen zu müssen.

FHIR-Ressourcen werden jedoch in der Datenbank persistiert. Und einige dieser Ressourcen enthalten Secrets — Client-Credentials, private Schlüssel, SASL-Konfigurationen für Kafka. Statische Secrets wie Datenbankpasswörter oder Lizenzschlüssel leben sicher in Umgebungsvariablen und gelangen niemals in die Datenbank. Aber ein dynamisch erstellter Client oder IdentityProvider? Sein Secret ist Teil der Ressource, und die Ressource wird in der Datenbank gespeichert.

Wir benötigten eine Möglichkeit, Secrets in FHIR-Ressourcen zu verwenden, ohne die eigentlichen Secret-Werte zu speichern.

Ab Version 2602 löst Aidbox dieses Problem mit [FHIR-Primitive-Extensions](https://www.health-samurai.io/docs/aidbox/configuration/secret-files#extension-pattern). Eine Ressource enthält nicht den Secret-Wert — sie trägt eine `data-absent-reason`-Extension, die als `masked` markiert ist, sowie einen Verweis auf einen logischen Secret-Namen. Aidbox löst diesen Namen zur Laufzeit zu einer Datei im Dateisystem auf, liest den Wert und verwendet ihn. Der tatsächliche Secret-Wert gelangt weder in die Datenbank noch in die API.

Für die Dateisystem-Ebene wollten wir keinen dedizierten Connector für jeden Vault entwickeln — das ist ein Wartungsaufwand, der schlecht skaliert und Teams an bestimmte Anbieter bindet. Stattdessen haben wir die denkbar einfachste Schnittstelle gewählt: einen Dateipfad. Viele gängige Vaults — Azure Key Vault, HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager — verfügen bereits über Secrets Store CSI Driver-Provider, die Secrets als Dateien in Kubernetes-Pods mounten. Andere können über externe Tools oder Skripte integriert werden, die Secret-Werte in Dateien schreiben. Kubernetes Secrets, Docker Secrets und einfache Bind-Mounts funktionieren ebenfalls. Solange das Secret in einer Datei landet, kann Aidbox es verwenden — ohne Plugins, ohne Vendor-SDKs, ohne benutzerdefinierten Integrations-Code.

## Funktionsweise

Der Mechanismus ist unkompliziert. Es gibt drei Bestandteile:
- **Secret-Dateien im Dateisystem.** Ihr Vault oder Orchestrator legt Secret-Werte als Dateien im Aidbox-Pod ab. Dies ist der einzige Vertrag — eine Datei an einem bekannten Pfad.
- **Eine Vault-Konfigurationsdatei.** Eine JSON-Datei bildet logische Secret-Namen auf Dateisystempfade ab und deklariert, welche Ressourcen auf welches Secret zugreifen dürfen. Sie verweisen Aidbox über die Umgebungsvariable `BOX_VAULT_CONFIG` auf diese Datei.
- **[FHIR-Extensions](/articles/extending-fhir-resources) auf Ressourcen.** Anstatt einen Secret-Wert direkt zu speichern, markiert eine Ressource das Feld als `masked` und enthält einen Verweis auf den logischen Secret-Namen. Aidbox löst diesen zur Laufzeit auf.

Wenn Aidbox ein Secret benötigt — beispielsweise zur Authentifizierung eines Clients — liest es den Secret-Namen aus der Ressource, schlägt den Dateipfad in der Vault-Konfiguration nach, prüft, ob die Ressource berechtigt ist, darauf zuzugreifen (Scope-Durchsetzung), liest die Datei und verwendet den Wert. Der Secret-Wert wird niemals über die API zurückgegeben: `GET`-Antworten enthalten ausschließlich den Verweis.

## Die Vault-Konfiguration

Die Vault-Konfiguration ist eine JSON-Datei mit einem `secret`-Objekt. Jeder Schlüssel ist ein logischer Name, und der Wert gibt an, wo die Datei liegt und wer sie verwenden darf:


```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" }
    }
  }
}
```


Das Feld `scope` steuert den Zugriff. Sie können ein Secret auf einen bestimmten Ressourcentyp einschränken oder es weiter auf eine bestimmte Ressourcen-ID eingrenzen. Wenn eine Ressource, die nicht im Scope enthalten ist, versucht, ein Secret aufzulösen, gibt Aidbox einen Unauthorized-Fehler zurück.

Aidbox lädt diese Datei einmalig beim Start. Wenn Sie die Vault-Konfiguration ändern, müssen Sie Aidbox neu starten. Die Secret-*Dateien selbst* werden jedoch mit einem kurzen TTL gecacht und gegen den Zeitpunkt der letzten Dateiänderung validiert — sodass Secret-Rotation ohne Neustart funktioniert.

## Secrets in Ressourcen referenzieren

Ressourcen verwenden FHIR-Primitive-Extensions, um Secrets zu referenzieren. Hier ist ein Client mit einem vault-gesicherten Secret:


```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"]
}
```


Das erneute Lesen gibt exakt dieselbe Struktur zurück — die Extension mit dem Secret-Namen, niemals den Wert:


```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"]
}
```


Die Authentifizierung funktioniert jedoch wie erwartet — Aidbox liest das Secret aus der gemounteten Datei und verwendet es zur Validierung der Credentials:


```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
```


## Welche Ressourcen externe Secrets unterstützen

Externe Secrets sind nicht auf Client-Credentials beschränkt. Hier ist die vollständige Liste der unterstützten Ressourcen und Felder:

| Ressource | Feld | Anwendungsfall |
| --- | --- | --- |
| Client | secret | Client-Authentifizierung |
| IdentityProvider | client.secret | Symmetrische Authentifizierung |
| IdentityProvider | client.private-key | Asymmetrisches Schlüsselmaterial |
| IdentityProvider | client.certificate | Zertifikat für asymmetrische Authentifizierung |
| TokenIntrospector | jwt.secret | JWT-Verifikationsschlüssel |
| TokenIntrospector | jwt.keys.k | Symmetrischer Validierungsschlüssel |
| TokenIntrospector | introspection_endpoint.authorization | Bearer-Token / Auth-Header |
| AidboxTopicDestination | parameter.saslJaasConfig | Kafka-SASL-Konfiguration |
| AidboxTopicDestination | parameter.sslKeystoreKey | Kafka-SSL-Schlüssel |

Dies deckt die häufigsten Fälle ab: Authentifizierungs-Credentials, Identity-Provider-Schlüssel, Token-Verifikation und Secrets für Messaging-Infrastrukturen.

## Secret-Rotation

Einer der wesentlichen Vorteile externer Secrets ist die Rotation ohne Ausfallzeit. Der Ablauf hängt davon ab, wie Secrets im Dateisystem bereitgestellt werden:
- **Secrets Store CSI Driver:** Der CSI Driver fragt den Vault regelmäßig auf Änderungen ab. Wenn ein Secret in Azure Key Vault (oder einem anderen Vault) aktualisiert wird, schreibt der Driver den neuen Wert in die gemountete Datei. Aidbox erkennt die Dateiänderung und übernimmt den neuen Wert beim nächsten Zugriff — kein Neustart erforderlich.
- **Kubernetes Secrets:** Wenn das Secret-Objekt aktualisiert wird, propagiert Kubernetes die Änderung in die gemounteten Volumes. Aidbox erkennt die aktualisierte Datei und invalidiert seinen Cache.
- **Docker Secrets / Bind-Mounts:** Aktualisieren Sie die Datei auf dem Host. Aidbox übernimmt die Änderung anhand des Zeitpunkts der letzten Dateiänderung.

In allen Fällen gilt der wichtige Unterschied: Die *Vault-Konfigurationsdatei* (auf die `BOX_VAULT_CONFIG` verweist) wird einmalig beim Start geladen und erfordert einen Neustart bei Änderungen. Die *Secret-Dateien*, auf die sie verweist, werden mit einem kurzen TTL gecacht und gegen Änderungs-Zeitstempel validiert, sodass sie automatisch rotieren.

## Deployment mit HashiCorp Vault

Wir haben ein vollständiges [Schritt-für-Schritt-Tutorial](https://www.health-samurai.io/docs/aidbox/tutorials/other-tutorials/hashicorp-vault-external-secrets), das ein HashiCorp Vault-Deployment auf Kubernetes von Grund auf beschreibt. Hier ist der übergeordnete Ablauf:

1. Deployen Sie HashiCorp Vault und speichern Sie Ihre Secrets.

2. Installieren Sie den Secrets Store CSI Driver und den Vault-Provider auf Ihrem Cluster.

3. Konfigurieren Sie eine Vault-Rolle und -Policy, die Lesezugriff auf die Secrets gewährt, die Ihre Aidbox-Ressourcen benötigen.

4. Erstellen Sie eine SecretProviderClass, die dem CSI Driver mitteilt, welche Secrets er aus dem Vault abrufen soll.

5. Erstellen Sie eine Vault-Konfiguration als ConfigMap, die logische Secret-Namen den gemounteten Dateipfaden zuordnet.

6. Deployen Sie Aidbox mit zwei Volume-Mounts: dem CSI-Volume für Secrets und der ConfigMap für die Vault-Konfiguration.
Setzen Sie `BOX_VAULT_CONFIG` so, dass es auf die Konfigurationsdatei verweist.

Nach dem Deployment erscheinen Secrets aus HashiCorp Vault als Dateien im Pod. Aidbox liest sie zur Laufzeit — und wenn Sie ein Secret im Vault rotieren, aktualisiert der CSI Driver die Datei automatisch, ohne dass ein Neustart erforderlich ist.

Das gleiche Muster gilt für andere Vaults mit CSI-Providern (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager). Die vollständige Vault-Konfigurationsreferenz und das Extension-Format finden Sie in der [Dokumentation zu External Secrets](https://www.health-samurai.io/docs/aidbox/configuration/secret-files).

## Ausblick

External Secrets ist ab Aidbox 2602 verfügbar. Wenn Sie Aidbox auf Kubernetes betreiben und Secrets über einen Vault verwalten, entfällt mit dieser Integration die Notwendigkeit, sensible Werte in der Datenbank zu speichern. Ihr Vault übernimmt weiterhin, was er am besten kann — Rotation, Auditing, Zugriffssteuerung — und Aidbox löst Secrets zur Laufzeit aus dem Dateisystem auf.

Wir würden gerne erfahren, wie Sie Secrets in Ihren FHIR-Deployments verwalten. Welche Vaults setzen Sie ein? Was hat sich als problematisch erwiesen? Treten Sie [Zulip](https://connect.health-samurai.io/) bei, um Implementierungsdetails mit unserem Team zu besprechen.

Siehe auch: [Aidbox HIPAA Technical Safeguards](/blog/aidbox-hipaa-book-technical-safeguards) und [Aidbox 2025-Roadmap](/blog/aidbox-2025-building-a-future-proof-fhir-platform).