Skip to main content

Rolter sends requests to URLs an operator writes. An admin surface that accepts an arbitrary one would turn the gateway into a way to reach whatever its network position can reach, and the prize on a cloud host is instance metadata at 169.254.169.254. The egress policy refuses those destinations.

Configuration#

Self-hosted and air-gapped upstreams live on loopback and private networks, so only the link-local range is denied by default.

What it covers#

Every URL below is checked when it is saved, and again before each request. A stored row is not a standing permission to egress: a policy tightened later applies to rows saved earlier.

URLSaved throughA denied value is
Provider api_base, egress proxyprovider API, config filea 400; in a snapshot, row dropped
Provider status_page_url, kv_events.endpoint, lmcache.endpointconfig filerefused at load; row dropped
MCP server URL and MCP OAuth URLsMCP API, config filea 400
Alert channel and connector endpointsalerting and connector APIsa 400
SSO issuer, and the endpoints its discovery document namesSSO provider APIa 400; at login, the login fails
Guardrail webhook url ([guardrail_webhook] and Guardrails, Providers)guardrail provider API, config filea 400; in a snapshot, kept and reported
PII sanitizer url, restore_url and restore_stream_urlconfig filerefused at load; kept and reported in a snapshot
Plugin endpointplugin APIa 400; in a snapshot, kept and reported

A denied provider URL in a snapshot drops that provider rather than refusing the snapshot, so one bad row cannot stop every gateway from receiving its configuration. A denied guardrail webhook, sanitizer or plugin URL is never dropped or switched off, because that would turn a fail-closed control into a fail-open one. It stays in the configuration and every call to it is refused, so its failure mode decides: fail closed rejects the request, fail open lets it through. Every such problem is listed by GET /api/v1/config/problems; check that list after tightening the policy.

Hostnames and redirects#

A saved URL is classified by its IP literal in every spelling a client would dial it by (2852039166, 0xa9fea9fe, 169.254.169.254.). A hostname cannot be classified without DNS, so the connection itself is checked: the addresses the name resolves to are filtered immediately before connecting, which also catches a name that later rebinds to a denied address. A name that resolves to several addresses keeps the permitted ones.

None of the clients above follows a redirect, because a 3xx is how an endpoint that passed the check hands the request to one that would not have.

Note

The kv_events subscription speaks ZeroMQ rather than HTTP. Its endpoint is checked, and a hostname is resolved and filtered, before each connect, but the transport resolves the name again itself, so a rebind in between is not caught.