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 who upgraded to 1.0.0-beta.11 (or later) and found
that event-notification webhooks, audit webhooks, or other outbound integrations
stopped reaching endpoints that worked before — typically Docker Compose service
names, host.docker.internal, or RFC 1918 addresses.
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_*);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.
| 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.
webhook endpoint is not allowed: ...
with a reason such as private address or loopback host.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.