IP allowlist
이 콘텐츠는 아직 번역되지 않았습니다.
IpAllowlist restricts a route subtree to clients whose IP falls
inside one of the configured CIDRs — defence-in-depth on top of
BearerTokenAuth: even a leaked
token is useless off an allowlisted network.
import { IpAllowlist, IpAllowlistOptions, withMiddleware } from 'actor-ts/http';
const ipAllowlistOptions = IpAllowlistOptions.create().withAllow('10.0.0.0/8', '127.0.0.1/32');const allowlist = IpAllowlist(ipAllowlistOptions);
const managementRoutes = withMiddleware(allowlist, clusterRoutes);IPv4 and IPv6 CIDRs are both supported ('::1/128', 'fd00::/8'), and
IPv4-mapped IPv6 peers (::ffff:a.b.c.d) on a dual-stack socket are
normalised so a plain IPv4 CIDR still matches. A non-matching — or
missing — client IP fails closed with 403.
Configuration
Section titled “Configuration”IpAllowlistOptions — builder or plain object:
| Field | Purpose |
|---|---|
allow | Non-empty list of CIDR strings; at least one must contain the client IP, else 403. Invalid CIDR syntax throws at construction. |
trustedProxies | CIDRs of the reverse proxies in front of this app. Unset (the default) means no forwarding header is read at all. See below. |
forwardedHeader | Header carrying the forwarded chain. Default 'x-forwarded-for'; only read when trustedProxies is set. |
getClientIp | Replace IP extraction wholesale — the escape hatch. Default reads request.remoteAddress (the socket peer). Returning null/undefined denies the request (fail-closed). Mutually exclusive with trustedProxies. |
Behind a reverse proxy
Section titled “Behind a reverse proxy”The default reads the socket peer, which behind a proxy is the proxy. To get the client’s own address, name the proxies — that is the whole configuration:
const ipAllowlistOptions = IpAllowlistOptions.create() .withAllow('10.0.0.0/8') .withTrustedProxies('10.9.9.0/24');
const allowlist = IpAllowlist(ipAllowlistOptions);The middleware then reads the chain in wire order —
[...x-forwarded-for entries, socket peer], client first — and walks it
from the right, taking the first address that is not one of your
proxies.
That direction is the entire point, because every common proxy
appends to an inbound X-Forwarded-For rather than replacing it:
| Proxy | What it does to X-Forwarded-For |
|---|---|
| NGINX | $proxy_add_x_forwarded_for is the inbound header, comma-appended with $remote_addr |
| AWS ALB | appends the connecting peer (xff_header_processing defaults to append) |
| Cloudflare | appends, and additionally sets CF-Connecting-IP |
So the leftmost entry is whatever the client typed, and only the entries added from the right were added by infrastructure. Three things follow, and each closes a hole a hand-written extractor leaves open:
- A client that reaches the app directly is the socket peer, and the
peer is not one of your proxies — so the walk stops there and the
header is never read. A forged
x-forwarded-fordecides nothing. - Junk a client prepends sits to the left of its real address and is never reached.
- An entry that is not a valid address matches no CIDR, counts as
untrusted, ends the walk — and then fails
allowtoo.
Where your proxy sets a single-value header instead of appending,
point the same walk at it. On Cloudflare that is CF-Connecting-IP:
const ipAllowlistOptions = IpAllowlistOptions.create() .withAllow('10.0.0.0/8') .withTrustedProxies('173.245.48.0/20', '103.21.244.0/22') // …the published Cloudflare ranges .withForwardedHeader('cf-connecting-ip');Where to next
Section titled “Where to next”- Bearer token auth — the token guard to layer on top.
- Security — where the allowlist sits in the stack.
- Management endpoints — the routes you most often restrict by network.
