---
{
  "title": "Las extensiones FHIR como puente hacia la gestión externa de secretos",
  "description": "Almacene secretos en recursos FHIR sin guardar los valores. Aidbox los resuelve desde archivos montados en el almacén en tiempo de ejecución. Seguro, dinámico y sin dependencia de proveedor.",
  "date": "2026-03-09",
  "author": "Andrew Listopadov, Ivan Bagrov",
  "reading-time": "15 minutes",
  "tags": [
    "System Design",
    "FHIR Standard"
  ]
}
---

> For the complete documentation index, see [llms.txt](https://www.health-samurai.io/llms.txt).
> Use it to discover all available pages before guessing URLs.

---
Queríamos que Aidbox fuera completamente dinámico — configurable en tiempo de ejecución, no solo en el momento del despliegue. Por eso modelamos Clients, IdentityProviders, TokenIntrospectors y AidboxTopicDestinations como recursos FHIR. Es posible crear un nuevo destino Kafka o registrar un proveedor de identidad a través de la API FHIR estándar, sin necesidad de reiniciar.

Sin embargo, los recursos FHIR se persisten en la base de datos. Y algunos de estos recursos contienen secretos — credenciales de cliente, claves privadas, configuraciones SASL para Kafka. Los secretos estáticos, como las contraseñas de base de datos o las claves de licencia, viven de forma segura en variables de entorno y nunca tocan la base de datos. Pero ¿un Client o un IdentityProvider creados dinámicamente? Su secreto forma parte del recurso, y el recurso se almacena en la base de datos.

Necesitábamos una forma de tener secretos dentro de recursos FHIR sin almacenar realmente los valores de dichos secretos.

A partir de la versión 2602, Aidbox resuelve esto con [extensiones primitivas FHIR](https://www.health-samurai.io/docs/aidbox/configuration/secret-files#extension-pattern). Un recurso no contiene el valor del secreto — lleva una extensión `data-absent-reason` marcada como `masked` y una referencia a un nombre lógico de secreto. Aidbox resuelve ese nombre a un archivo en el sistema de archivos en tiempo de ejecución, lee el valor y lo utiliza. El valor real del secreto nunca llega a la base de datos ni a la API.

Para la capa del sistema de archivos, no queríamos construir un conector dedicado para cada almacén — eso supone una carga de mantenimiento que escala mal y ata a los equipos a proveedores específicos. En su lugar, elegimos la interfaz más simple posible: una ruta de archivo. Muchos almacenes populares — Azure Key Vault, HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager — ya disponen de proveedores para el Secrets Store CSI Driver que montan secretos como archivos en los Pods de Kubernetes. Otros pueden integrarse mediante herramientas externas o scripts que escriben los valores de los secretos en archivos. Los Kubernetes Secrets, Docker Secrets y los bind-mounts simples también funcionan. Mientras el secreto termine en un archivo, Aidbox puede utilizarlo — sin plugins, sin SDKs de proveedor, sin código de integración personalizado.

## Cómo funciona

El mecanismo es sencillo. Consta de tres elementos:
- **Archivos de secretos en el sistema de archivos.** El almacén u orquestador coloca los valores de los secretos como archivos dentro del Pod de Aidbox. Este es el único contrato — un archivo en una ruta conocida.
- **Un archivo de configuración del almacén.** Un archivo JSON asigna nombres lógicos de secretos a rutas del sistema de archivos y declara qué recursos tienen permiso para usar cada secreto. Se apunta a este archivo en Aidbox mediante la variable de entorno `BOX_VAULT_CONFIG`.
- **[Extensiones FHIR](/articles/extending-fhir-resources) en los recursos.** En lugar de almacenar un valor de secreto directamente, un recurso marca el campo como `masked` e incluye una referencia al nombre lógico del secreto. Aidbox lo resuelve en tiempo de ejecución.

Cuando Aidbox necesita un secreto — por ejemplo, para autenticar un cliente — lee el nombre del secreto desde el recurso, busca la ruta del archivo en la configuración del almacén, verifica que el recurso tenga permiso para acceder a él (aplicación del ámbito), lee el archivo y utiliza el valor. El valor del secreto nunca se devuelve a través de la API: las respuestas a `GET` contienen únicamente la referencia.

## La configuración del almacén

La configuración del almacén es un archivo JSON con un objeto `secret`. Cada clave es un nombre lógico, y el valor especifica dónde reside el archivo y quién puede utilizarlo:


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


El campo `scope` controla el acceso. Es posible restringir un secreto a un tipo de recurso específico, o limitarlo aún más a un ID de recurso concreto. Si un recurso que no está en el ámbito intenta resolver un secreto, Aidbox devuelve un error de acceso no autorizado.

Aidbox carga este archivo una vez al iniciar. Si se cambia la configuración del almacén, es necesario reiniciar Aidbox. Sin embargo, los *archivos de secretos en sí* se almacenan en caché con un TTL corto y se validan contra el tiempo de modificación del archivo — por lo que la rotación de secretos funciona sin necesidad de reinicios.

## Referenciando secretos en los recursos

Los recursos utilizan extensiones primitivas FHIR para referenciar secretos. A continuación se muestra un Client con un secreto respaldado por el almacén:


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


Al leerlo de nuevo se devuelve exactamente la misma estructura — la extensión con el nombre del secreto, nunca el valor:


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


Sin embargo, la autenticación funciona como se espera — Aidbox lee el secreto desde el archivo montado y lo utiliza para validar las credenciales:


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


## Qué recursos admiten secretos externos

Los secretos externos no se limitan a las credenciales de cliente. A continuación se muestra la lista completa de recursos y campos compatibles:

| Recurso | Campo | Caso de uso |
| --- | --- | --- |
| Client | secret | Autenticación de cliente |
| IdentityProvider | client.secret | Autenticación simétrica |
| IdentityProvider | client.private-key | Material de clave asimétrica |
| IdentityProvider | client.certificate | Certificado para autenticación asimétrica |
| TokenIntrospector | jwt.secret | Clave de verificación JWT |
| TokenIntrospector | jwt.keys.k | Clave de validación simétrica |
| TokenIntrospector | introspection_endpoint.authorization | Token Bearer / cabecera de autenticación |
| AidboxTopicDestination | parameter.saslJaasConfig | Configuración SASL de Kafka |
| AidboxTopicDestination | parameter.sslKeystoreKey | Clave SSL de Kafka |

Esto cubre los casos más habituales: credenciales de autenticación, claves de proveedor de identidad, verificación de tokens e infraestructura de mensajería.

## Rotación de secretos

Una de las principales ventajas de los secretos externos es la rotación sin tiempo de inactividad. El flujo depende de cómo se entregan los secretos al sistema de archivos:
- **Secrets Store CSI Driver:** El controlador CSI consulta el almacén en busca de cambios. Cuando se actualiza un secreto en Azure Key Vault (u otro almacén), el controlador escribe el nuevo valor en el archivo montado. Aidbox detecta la modificación del archivo y toma el nuevo valor en el siguiente acceso — sin necesidad de reiniciar.
- **Kubernetes Secrets:** Cuando se actualiza el objeto Secret, Kubernetes propaga el cambio a los volúmenes montados. Aidbox detecta el archivo actualizado e invalida su caché.
- **Docker Secrets / bind-mounts:** Actualice el archivo en el host. Aidbox tomará el cambio basándose en el tiempo de modificación del archivo.

En todos los casos, la distinción importante es: el *archivo de configuración del almacén* (al que apunta `BOX_VAULT_CONFIG`) se carga una vez al iniciar y requiere un reinicio para cambiar. Los *archivos de secretos* a los que apunta se almacenan en caché con un TTL corto y se validan contra las marcas de tiempo de modificación, por lo que rotan automáticamente.

## Despliegue con HashiCorp Vault

Disponemos de un [tutorial completo paso a paso](https://www.health-samurai.io/docs/aidbox/tutorials/other-tutorials/hashicorp-vault-external-secrets) que guía a través de un despliegue de HashiCorp Vault en Kubernetes desde cero. Este es el flujo general:

1. Despliegue HashiCorp Vault y almacene sus secretos.

2. Instale el Secrets Store CSI Driver y el proveedor de Vault en su clúster.

3. Configure un rol y una política de Vault que otorgue acceso de lectura a los secretos que necesitan sus recursos de Aidbox.

4. Cree un SecretProviderClass que indique al controlador CSI qué secretos obtener de Vault.

5. Cree una configuración de almacén como ConfigMap, asignando nombres lógicos de secretos a las rutas de archivos montados.

6. Despliegue Aidbox con dos montajes de volumen: el volumen CSI para los secretos y el ConfigMap para la configuración del almacén.
Establezca BOX_VAULT_CONFIG para que apunte al archivo de configuración.

Una vez desplegado, los secretos de HashiCorp Vault aparecen como archivos dentro del Pod. Aidbox los lee en tiempo de ejecución — y cuando se rota un secreto en el almacén, el controlador CSI actualiza el archivo automáticamente sin necesidad de reiniciar.

El mismo patrón se aplica a otros almacenes con proveedores CSI (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager). Para la referencia completa de la configuración del almacén y el formato de extensión, consulte la [documentación de secretos externos](https://www.health-samurai.io/docs/aidbox/configuration/secret-files).

## Próximos pasos

Los secretos externos están disponibles ahora en Aidbox 2602 y versiones posteriores. Si ejecuta Aidbox en Kubernetes y gestiona secretos a través de un almacén, esta integración elimina la necesidad de almacenar valores sensibles en la base de datos. Su almacén sigue haciendo lo que mejor sabe hacer — rotación, auditoría, control de acceso — y Aidbox resuelve los secretos en tiempo de ejecución desde el sistema de archivos.

Nos encantaría conocer cómo gestiona los secretos en sus despliegues FHIR. ¿Qué almacenes utiliza? ¿Qué ha resultado complicado? Únase a [Zulip](https://connect.health-samurai.io/) para explorar los detalles de implementación con nuestro equipo.

Consulte también: [Salvaguardas técnicas HIPAA de Aidbox](/blog/aidbox-hipaa-book-technical-safeguards) y [Hoja de ruta de Aidbox 2025](/blog/aidbox-2025-building-a-future-proof-fhir-platform).