# Referencia de configuración

> Todos los campos de la configuración JSON de OpenWAF Egress, con su valor por defecto y lo que hace la pasarela con cada uno.

OpenWAF Egress lee un único fichero JSON al arrancar (`-config`, `config.json` por defecto; la imagen pasa `-config /app/config.json`). Los cambios necesitan reiniciar. Esta página recoge todos los campos de `pkg/egress/config.go` en la v0.1.1 con su valor por defecto; un campo que no escribas toma el valor por defecto.

## Ejemplo completo

El `config.example.json` del repositorio, que es también el fichero que trae la imagen:

```json
{
  "listen_addr": "0.0.0.0:8070",
  "openbao": {
    "addr": "https://vault.example.com:8200",
    "ca_file": "",
    "approle_file": "",
    "kv_mount": "secret"
  },
  "targets": {
    "openrouter": {
      "base_url": "https://openrouter.ai/api/v1",
      "host": "openrouter.ai",
      "auth_header": "Authorization",
      "auth_prefix": "Bearer "
    },
    "openai": {
      "base_url": "https://api.openai.com/v1",
      "host": "api.openai.com",
      "auth_header": "Authorization",
      "auth_prefix": "Bearer "
    },
    "anthropic": {
      "base_url": "https://api.anthropic.com/v1",
      "host": "api.anthropic.com",
      "auth_header": "x-api-key",
      "auth_prefix": ""
    },
    "huggingface": {
      "base_url": "https://router.huggingface.co/v1",
      "host": "router.huggingface.co",
      "auth_header": "Authorization",
      "auth_prefix": "Bearer "
    }
  },
  "agents": {
    "my-support-agent": {
      "token": "OWE_TOKEN_SUPPORT_AGENT",
      "allowed_targets": ["openrouter", "openai"],
      "credential_mapping": {
        "openrouter": { "path": "agents/support", "key": "OPENROUTER_API_KEY" },
        "openai": { "path": "agents/support", "key": "OPENAI_API_KEY" }
      },
      "enforce_injection": true,
      "block_dlp": true
    }
  }
}
```

`OWE_TOKEN_SUPPORT_AGENT` es público: cámbialo por un valor largo y aleatorio para cada agente.

El README añade un destino de Gemini, cuya clave va en `x-goog-api-key`:

```json
"gemini": {
  "base_url": "https://generativelanguage.googleapis.com",
  "host": "generativelanguage.googleapis.com",
  "auth_header": "x-goog-api-key"
}
```

## Nivel superior

| Campo | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `listen_addr` | texto | `127.0.0.1:8070` | Dirección y puerto en los que escucha la pasarela. La opción `-addr` lo sustituye. Dentro de un contenedor usa `0.0.0.0:8070` y publica el puerto solo en loopback o en una red privada. |
| `openbao` | objeto | (vacío) | Conexión con OpenBao o HashiCorp Vault. Sin `openbao.addr` la pasarela escribe `credential injection disabled` en el registro y no inyecta ninguna clave. |
| `targets` | objeto | (ninguno) | APIs de destino por alias. El alias es el `<destino>` de la URL. |
| `agents` | objeto | (ninguno) | Políticas de cada agente por nombre. El nombre es el `<agente>` de la URL. |

## openbao

| Campo | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `addr` | texto | (ninguno) | URL base de OpenBao o Vault, p. ej. `https://openbao.example.com:8200`. Imprescindible para inyectar claves. |
| `ca_file` | texto | raíces del sistema | Fichero PEM con la CA que firmó el certificado del servidor. La conexión exige TLS 1.3. |
| `approle_file` | texto | (ninguno) | Fichero JSON con `{"role_id": "…", "secret_id": "…"}`. Se lee al arrancar si `role_id` o `secret_id` no están escritos en la configuración. |
| `role_id` | texto | (ninguno) | ID del rol de AppRole, escrito en la configuración. |
| `secret_id` | texto | (ninguno) | ID secreto de AppRole, escrito en la configuración. Mejor `approle_file`, para que el secreto no esté en la configuración principal. |
| `kv_mount` | texto | `kv` | Montaje del motor KV v2. Un secreto se lee de `GET /v1/<kv_mount>/data/<path>`. El montaje por defecto de Vault es `secret`. |

La pasarela entra en `POST /v1/auth/approle/login` y renueva el token dos minutos antes de que caduque su concesión (una hora si el servidor no indica ninguna). Cada secreto se guarda en caché cinco minutos, así que una clave rotada llega a la pasarela en cinco minutos como mucho. Las peticiones a OpenBao caducan a los diez segundos.

## targets.<alias>

| Campo | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `base_url` | texto | (ninguno) | Adónde van las peticiones. Se le añaden el resto de la ruta del agente y su cadena de consulta: `/v1/agent/a/proxy/openrouter/chat/completions` → `<base_url>/chat/completions`. |
| `host` | texto | (ninguno) | Cabecera `Host` que se envía al proveedor y nombre que resuelve la comprobación de SSRF. La conexión va al host de `base_url`: pon el mismo nombre en los dos. |
| `auth_header` | texto | `Authorization` | Cabecera que recibe la clave. Anthropic usa `x-api-key`; Gemini, `x-goog-api-key`. Las claves en la cadena de consulta (`?key=`) no se inyectan: usa la cabecera. |
| `auth_prefix` | texto | `Bearer ` si `auth_header` es `Authorization`; si no, vacío | Texto que va delante de la clave. Un valor vacío con `Authorization` pasa a ser `Bearer `. |

## agents.<nombre>

| Campo | Tipo | Por defecto | Qué hace |
|---|---|---|---|
| `token` | texto | (ninguno) | El marcador del agente. Si está, cada petición tiene que llevar `Authorization: Bearer <token>`, y esa cabecera se quita antes de reenviar. Si está vacío, cualquiera que sepa el nombre del agente puede usarlo: pon siempre uno. |
| `allowed_targets` | lista de textos | `[]` | Alias de los destinos a los que puede llamar el agente. `"*"` permite todos. Con la lista vacía, todas las peticiones reciben `403 egress_blocked`. |
| `credential_mapping` | objeto | `{}` | Alias del destino → `{"path": "…", "key": "…"}`: la ruta del secreto bajo `kv_mount` y el campo dentro de él. A un destino sin entrada no se le inyecta clave. |
| `enforce_injection` | booleano | `false` | Pasa los detectores de inyección de prompt por el cuerpo; una detección recibe `403 injection_detected`. Las de `cost.amplification` se ignoran. |
| `block_dlp` | booleano | `false` | Busca en el cuerpo números de tarjeta, claves privadas y claves de API; una coincidencia recibe `403 data_leak_blocked`. |

Con `enforce_injection` o `block_dlp` activados, el texto del cuerpo tiene que caber en la ventana de inspección de 1 MiB. Los medios en línea no cuentan: las URI `data:image/…;base64,…` (también de audio y vídeo) y los miembros JSON `"data"` con al menos 1 KiB de base64 (`input_audio` de OpenAI, `inlineData` de Gemini, fuentes base64 de Anthropic) se reenvían, pero no se inspeccionan.

## Opciones de la línea de órdenes

| Opción | Por defecto | Qué hace |
|---|---|---|
| `-config` | `config.json` | Ruta del fichero de configuración. |
| `-addr` | (ninguna) | Sustituye a `listen_addr`. |
| `-version` | | Muestra la versión y sale. |

## Límites fijos

En la v0.1.1 son constantes, no configuración:

| Límite | Valor |
|---|---|
| Cuerpo de la petición | 8 MiB (`413 body_too_large`) |
| Ventana de inspección, con `enforce_injection` o `block_dlp` | 1 MiB de texto, sin contar las URI `data:` de medios ni los miembros JSON `"data"` con ≥ 1 KiB de base64 (`413 body_too_large`) |
| Detecciones devueltas por petición | 16, cada fragmento de 160 bytes como mucho |
| Caché de secretos | 5 minutos |
| Peticiones a OpenBao | 10 s de plazo; 3 s para la comprobación de `/health` |
| Proveedor | 10 s para el saludo TLS, 5 min hasta las cabeceras de respuesta del proveedor, 15 min por intercambio (con el cuerpo en streaming) |
| Servidor de la pasarela | 10 s para leer las cabeceras de la petición, 120 s para leer la petición, 15 min para escribir la respuesta, 120 s de inactividad |
| Redirecciones | nunca se siguen: el `3xx` vuelve al agente |

Escrito a partir de [github.com/openwaf-dev/egress@v0.1.1](https://github.com/openwaf-dev/egress/tree/v0.1.1).
