docs/operations/outbound-connection-policy.md
This document describes the outbound connection policy that RustFS applies to
server-initiated HTTP(S) requests, and the RUSTFS_OUTBOUND_ALLOW_ORIGINS
allowlist operators can use to reach endpoints on private or container networks.
It is written for operators whose outbound integrations stopped reaching
endpoints after an upgrade — typically Docker Compose service names,
host.docker.internal, or RFC 1918 addresses. Webhook and audit clients adopted
this policy in 1.0.0-beta.11; OIDC provider requests adopted it in
1.0.0-beta.12.
Several RustFS subsystems open connections to operator-configured URLs. To close a server-side request forgery (SSRF) class of problem, RustFS validates every such destination and re-checks the addresses returned by DNS on each new connection, so a hostname cannot be rebound to a restricted address after it is first accepted.
The policy governs the outbound clients used by:
RUSTFS_NOTIFY_WEBHOOK_*);RUSTFS_AUDIT_WEBHOOK_*);1.0.0-beta.12);The webhook and audit outbound clients also disable proxies and do not follow redirects, so the destination must be reachable directly at the configured URL.
For webhook and audit clients:
| beta.10 | beta.11+ | |
|---|---|---|
Literal localhost / private / loopback IPs | Rejected | Rejected |
Hostnames that resolve to private/loopback addresses (logstash, host.docker.internal, Compose service DNS, …) | Allowed | Blocked at DNS/connect time unless allowlisted |
| Escape hatch for private destinations | None | RUSTFS_OUTBOUND_ALLOW_ORIGINS |
| Proxies / redirects for outbound clients | Followed | Disabled |
Before beta.11 a webhook endpoint whose hostname happened to resolve to a private address was accepted. Beta.11 fails that resolution check unless the exact origin is on the allowlist. This is why a Compose setup that delivered events on beta.10 can go silent after the upgrade even though the configuration is unchanged.
OIDC joined the same policy in beta.12. An internal identity provider that worked in beta.11 can therefore fail discovery after upgrading to beta.12 unless its exact origin is allowlisted. The policy remains active for discovery, JWKS, and token requests.
webhook endpoint is not allowed: ...
with a reason such as private address or loopback host.OIDC provider discovery blocked by outbound policy with the exact origin to
allowlist.RUSTFS_OUTBOUND_ALLOW_ORIGINSRUSTFS_OUTBOUND_ALLOW_ORIGINS is a comma-separated list of exact HTTP(S)
origins that are permitted to resolve to otherwise-restricted addresses. It is an
operator-owned process setting read once at startup; individual target
configuration cannot extend it.
# exact scheme://host:port — comma-separate multiple origins
RUSTFS_OUTBOUND_ALLOW_ORIGINS=http://logstash:8080,http://host.docker.internal:3020
Each entry is matched as an exact origin (scheme://host:port):
http or https.http://logstash:8080 does not authorize http://logstash:9090 or
https://logstash:8080.80 for http, 443
for https); the destination must then use that same default port./ is accepted, but a path, query,
or fragment (for example http://logstash:8080/events) is rejected as an
invalid origin — the process fails closed rather than silently ignoring the
path.http://user:pass@host) is not allowed.An invalid list fails closed: the affected subsystem reports an
invalid outbound policy / invalid origin at position N error instead of
starting with a partially applied allowlist.
Allowlisting an origin only relaxes the loopback, private, shared, and reserved address classes for that exact origin. The following remain forbidden for every origin, allowlisted or not:
169.254.169.254 and the other
well-known IMDS addresses);169.254.0.0/16, fe80::/10);0.0.0.0, ::);::ffff:127.0.0.1
and similar cannot be used to bypass the policy).The allowlist authorizes only the exact host you name. A DNS answer for a different hostname that points at a private address is still rejected, and each new connection re-validates the resolved addresses so a rebinding answer fails closed.
services:
rustfs:
image: rustfs/rustfs:latest
environment:
RUSTFS_NOTIFY_ENABLE: "true"
RUSTFS_NOTIFY_WEBHOOK_ENABLE_PRIMARY: "on"
RUSTFS_NOTIFY_WEBHOOK_ENDPOINT_PRIMARY: "http://logstash:8080/events"
RUSTFS_NOTIFY_WEBHOOK_QUEUE_DIR_PRIMARY: "/tmp/rustfs-events"
# Allow the webhook host to resolve to the Compose private network.
# Note: the allowlist takes the origin only, without the /events path.
RUSTFS_OUTBOUND_ALLOW_ORIGINS: "http://logstash:8080"
logstash:
image: docker.elastic.co/logstash/logstash:8.15.0
# ...
The endpoint keeps its full path (/events); the allowlist entry is the origin
(http://logstash:8080) only.
RUSTFS_OUTBOUND_ALLOW_ORIGINS as an exact
scheme://host:port origin (no path).... is not allowed messages if a
target still fails to activate.