Configuration¶
SecRouter reads a single JSON config file, resolved in this order:
FREEROUTER_CONFIGenvironment variable./freerouter.config.json(working directory)~/.config/freerouter/config.json
The security block is validated at startup and fails closed — the server refuses to boot in an unsafe configuration. Start production from the hardened reference config that ships with the release.
Shape¶
{
"providers": {
"bedrock": { "api": "openai", "baseUrl": "https://bedrock-runtime.us-gov-west-1.amazonaws.com/openai/v1", "auth": { "type": "env", "key": "AWS_BEARER_TOKEN_BEDROCK" } },
"azure": { "api": "azure", "baseUrl": "https://<resource>.openai.azure.us", "apiVersion": "2024-10-21", "azureAuth": "api-key", "auth": { "type": "env", "key": "AZURE_OPENAI_API_KEY" } },
"local": { "api": "openai", "baseUrl": "https://llm.internal.example.url/v1" }
},
"tiers": {
"SIMPLE": { "primary": "bedrock/openai.gpt-oss-20b-1:0", "fallback": ["local/llama-3.3-70b-instruct"] },
"MEDIUM": { "primary": "bedrock/openai.gpt-oss-120b-1:0", "fallback": ["azure/gpt-4o"] },
"COMPLEX": { "primary": "bedrock/openai.gpt-oss-120b-1:0", "fallback": ["azure/gpt-4o"] }
},
"security": { "...": "see below" }
}
Frontier OpenAI models are served two compliant ways, both speaking the OpenAI chat format so switching a tier between them is a one-line change:
Amazon Bedrock (GovCloud) — Bedrock’s OpenAI-compatible endpoint (
{bedrock-runtime}/openai/v1) authenticated with a Bedrock API key. Useapi: "openai"and set the base URL to.../openai/v1.Azure AI Foundry (Azure OpenAI) —
api: "azure"with your resourcebaseUrl(…openai.azure.usfor Azure Government), anapiVersion, andazureAuthof"api-key"(key in an env var) or"entra"(a{ tenantId, clientId, clientSecretEnv, authority, scope }service principal). The model id is your deployment name.
Block |
Purpose |
|---|---|
|
Backends and how to reach them. |
|
Which model serves each tier ( |
|
Optional per-model catalog ( |
|
|
|
Auth, per-user policy, egress control, audit, and TLS/FIPS. Off unless |
The security block¶
"security": {
"enabled": true,
"requireFips": true,
"oidc": {
"issuer": "https://idp.example.url/realms/cui",
"audience": "secrouter",
"requireMfa": true,
"groupsClaim": "groups",
"clientId": "secrouter-admin-console"
},
"classification": { "default": "CUI", "levels": ["UNCLASSIFIED", "CUI"] },
"egress": {
"allowlist": [
{ "provider": "bedrock",
"allowedHost": "bedrock-runtime.us-gov-west-1.amazonaws.com",
"authorizedClassifications": ["CUI"] }
]
},
"policy": {
"default": { "allowedTiers": ["SIMPLE", "MEDIUM"], "budgets": [{ "window": "day", "maxCostUsd": 25 }] },
"groups": {
"secrouter-admins": { "admin": true },
"power-users": { "allowedTiers": ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"] }
}
},
"audit": { "sink": "both", "syslog": { "host": "siem.example.url", "port": 6514, "protocol": "tcp" } },
"tls": { "mode": "frontend" }
}
Key |
What it controls |
|---|---|
|
Token validation: issuer, audience, JWKS, MFA assertion, the groups claim, and the admin-console client id. |
|
The ordered data-classification ladder used by the egress gate. |
|
Deny-by-default list of authorized destinations and the classifications each may receive. |
|
Per-group and per-user grants: |
|
|
|
Prometheus |
|
Per-provider circuit breaker: |
|
Governed MCP tool gateway. |
|
|
Keep trackJti off
oidc.trackJti enforces single-use tokens. Standard OIDC access tokens are multi-use bearer tokens, so leaving it on rejects the second request that reuses a token. Only enable it if your IdP issues one-time tokens.
Reload without restart¶
Edit the config, then have an admin POST to reload — the new config is re-validated (fail-closed) before it’s applied:
curl -X POST -H "Authorization: Bearer $ADMIN_TOKEN" https://secrouter.example.url/reload-config
Policy and tier→model edits made in the admin console apply live without a reload.