Configuration reference

Every field of the OpenWAF Egress JSON configuration, with its default and what the gateway does with it.

On this page

OpenWAF Egress reads one JSON file at startup (-config, config.json by default; the image passes -config /app/config.json). Changes need a restart. This page lists every field of pkg/egress/config.go in v0.1.1 and its default; a field you leave out takes the default.

Full example

The config.example.json of the repository, which is also the file built into the image:

{
  "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 is public: replace it with a long random value per agent.

The README adds a Gemini target, whose key goes in x-goog-api-key:

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

Top level

FieldTypeDefaultWhat it does
listen_addrstring127.0.0.1:8070Address and port the gateway listens on. The -addr flag overrides it. Inside a container use 0.0.0.0:8070 and publish the port on loopback or a private network only.
openbaoobject(empty)Connection to OpenBao or HashiCorp Vault. Without openbao.addr the gateway logs credential injection disabled and injects no keys.
targetsobject(none)Upstream APIs by alias. The alias is the <target> of the URL.
agentsobject(none)Agent policies by name. The name is the <agent> of the URL.

openbao

FieldTypeDefaultWhat it does
addrstring(none)Base URL of OpenBao or Vault, e.g. https://openbao.example.com:8200. Required for key injection.
ca_filestringsystem rootsPEM file with the CA that signed the server certificate. The connection requires TLS 1.3.
approle_filestring(none)JSON file with {"role_id": "…", "secret_id": "…"}. Read at startup when role_id or secret_id is not set inline.
role_idstring(none)AppRole role ID, inline.
secret_idstring(none)AppRole secret ID, inline. Prefer approle_file so the secret stays out of the main configuration.
kv_mountstringkvMount of the KV v2 engine. A secret is read from GET /v1/<kv_mount>/data/<path>. Vault's default mount is secret.

The gateway logs in at POST /v1/auth/approle/login and renews the token two minutes before its lease ends (one hour when the server returns no lease). Each secret is cached for five minutes, so a rotated key reaches the gateway within five minutes. Requests to OpenBao time out after ten seconds.

targets.<alias>

FieldTypeDefaultWhat it does
base_urlstring(none)Where requests go. The rest of the agent's path and its query string are appended: /v1/agent/a/proxy/openrouter/chat/completions → <base_url>/chat/completions.
hoststring(none)Host header sent upstream, and the name the SSRF check resolves. The connection itself goes to the host of base_url: set both to the same name.
auth_headerstringAuthorizationHeader that receives the key. Anthropic uses x-api-key, Gemini x-goog-api-key. Keys in the query string (?key=) are not injected: use the header.
auth_prefixstringBearer when auth_header is Authorization, otherwise emptyText put before the key. An empty value with Authorization becomes Bearer.

agents.<name>

FieldTypeDefaultWhat it does
tokenstring(none)The agent's placeholder. When set, every request must carry Authorization: Bearer <token>, and that header is removed before forwarding. When empty, anyone who knows the agent's name can use it: always set one.
allowed_targetslist of strings[]Target aliases this agent may call. "*" allows every target. With an empty list every request gets 403 egress_blocked.
credential_mappingobject{}Target alias → {"path": "…", "key": "…"}: the secret path under kv_mount and the field inside it. A target without a mapping gets no injected key.
enforce_injectionbooleanfalseRun the prompt-injection detectors over the body; a hit gets 403 injection_detected. cost.amplification hits are ignored.
block_dlpbooleanfalseScan the body for card numbers, private keys and API keys; a hit gets 403 data_leak_blocked.

With enforce_injection or block_dlp on, the text of the body must fit the 1 MiB inspection window. Inline media does not count: data:image/…;base64,… (also audio and video) URIs and JSON "data" members of at least 1 KiB of bare base64 (OpenAI input_audio, Gemini inlineData, Anthropic base64 sources) are forwarded but not inspected.

Command-line flags

FlagDefaultWhat it does
-configconfig.jsonPath to the configuration file.
-addr(none)Overrides listen_addr.
-versionPrints the version and exits.

Fixed limits

These are constants in v0.1.1, not configuration:

LimitValue
Request body8 MiB (413 body_too_large)
Inspection window, with enforce_injection or block_dlp1 MiB of text; data: media URIs and JSON "data" members of ≥ 1 KiB base64 excluded (413 body_too_large)
Detections returned per request16, each snippet at most 160 bytes
Secret cache5 minutes
OpenBao requests10 s timeout; 3 s for the /health check
Upstream10 s TLS handshake, 5 min until the provider's response headers, 15 min per exchange (streamed body included)
Gateway server10 s to read request headers, 120 s to read the request, 15 min to write the response, 120 s idle
Redirectsnever followed: the 3xx goes back to the agent

Written from github.com/openwaf-dev/[email protected] (external link).

Last updated:

↑↓ to navigate↵ to openesc to close