Files
RustProxy/docs/INTEGRATIONS_040.md
T
2026-10-03 00:27:09 +01:00

162 lines
9.1 KiB
Markdown

# RustProxy 0.4.0 - forwarding, Tinyauth, listeners and certificate library
This is source implementation, not a verified binary. Read TEST_REPORT.md before deployment.
The admin panel remains local; public frontend TLS does not make the admin listener remote-safe.
## Forwarded identity and the trust boundary
Every origin request now gets canonical `X-Forwarded-For`, `Forwarded`, `X-Real-IP`,
`X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Forwarded-Port` and `X-Forwarded-URI`.
Without configured trusted proxies, incoming proxy headers are discarded. The socket
peer IP is used, so a client cannot supply an arbitrary address in X-Forwarded-For.
Both header formats are emitted; RFC 7239 IPv6 nodes are quoted and bracketed.
There is no ephemeral client port in the representation fingerprint.
When RustProxy is behind a real reverse proxy, Settings -> Forwarding accepts explicit
IPv4/IPv6 CIDRs (max 32). Do not enter application client networks as trusted proxies.
The last hop must sanitize incoming forwarding headers. `0.0.0.0/0` and `::/0` are rejected.
With a trusted socket peer, X-Forwarded-For is preferred; Forwarded's `for=` chain is the
fallback. The chain is walked right-to-left and anything before the nearest untrusted
hop is discarded. Malformed or oversized chains fall back to the actual peer.
`X-Forwarded-Proto` is honored only with the separate `trust_forwarded_proto` opt-in.
Authority/Host always comes from validated Host or HTTP/2/3 `:authority`, not X-Forwarded-Host.
ACLs and IP affinity use this centrally resolved client address. Listener selection
continues to use the REAL local destination socket and actual TLS state.
```json
"forwarding": {
"trusted_proxies": ["10.87.7.10/32"],
"trust_forwarded_proto": true
}
```
That address is illustrative, not a default. Leave the list empty for direct clients.
RFC 7239: https://www.rfc-editor.org/rfc/rfc7239.html
## Tinyauth per vhost
Open Vhosts -> Edit -> Authentication. Enable protection, enter the verification
server and the public login URL, allow a private verifier explicitly if needed,
and save. An origin URL automatically appends `/api/auth/nginx`; an explicit URL
path remains unchanged. No public `/tinyauth` proxy route needs to be created.
The following matches the supplied nginx-style setup:
```json
"tinyauth": {
"enabled": true,
"url": "http://10.87.7.99:3000/api/auth/nginx",
"login_url": "https://auth.linuxiarz.pl/login",
"allow_private": true,
"address_allowlist": ["10.87.7.99/32"],
"connect_timeout_seconds": 5,
"timeout_seconds": 10,
"request_headers": ["cookie", "authorization", "x-api-key", "user-agent", "accept"],
"response_headers": ["remote-user", "remote-email"],
"redirect_forbidden": true
}
```
Verification is an internal body-free GET, carrying canonical forwarding headers,
X-Original-URL and X-Original-Method. Original method, path and query remain available
to Tinyauth, while the upload body is sent only to the application after authorization.
The RustProxy admin session cookie is never passed to the verifier or application.
Only 2xx approves access. Selected Remote-* / safe X-* response headers become trusted
identity headers. Incoming Remote-* and configured identity headers are removed,
including after administrator request-header rules. Missing identity fields are not
filled from client values. Transport/framing/forwarding fields cannot be selected
as identity headers. Each direction supports at most 32 names; approved identity values are bounded
to 8 KiB in total.
401 redirects to a validated X-Tinyauth-Location on the configured login origin,
or constructs `login_url?redirect_uri=<percent-encoded original URL>`.
403 stays 403 unless the provider returns an allowed same-origin redirect and the
403-redirect option is enabled. Cross-origin locations are rejected. Verifier errors
fail closed (502/504), not open. Auth denial/error is not replaced by custom error pages.
Public login URLs require HTTPS; HTTP is allowed only for loopback test servers.
Additional CA PEM can extend trust for Tinyauth HTTPS verification; there is no
verify-off switch for the authentication verifier. The per-backend `tls_verify` option
does not apply to Tinyauth.
Configure Tinyauth itself to trust the ACTUAL RustProxy source IP, not 0.0.0.0/0.
Authorization runs before origin connection, static pages, WebSocket upgrade to the
origin and every cache lookup. Authenticated vhosts always BYPASS the internal shared
cache and emit `Cache-Control: private, no-store`, even when their cache toggle is on.
This intentionally also disables privacy-sensitive compression through the existing
predicate. Login/session validity is NOT cached. Revocation is checked on each new
HTTP request or WebSocket handshake; an already upgraded socket is not periodically
reauthenticated. There is no automatic replay of POST or failed upgrades.
Do not enable this protection on the Tinyauth login vhost itself (login loop).
Provider reference: https://tinyauth.app/docs/guides/nginx-proxy-manager/
Header reference: https://tinyauth.app/docs/reference/headers/
## Named listeners
Settings -> Listeners owns every proxy socket. Each endpoint has a stable ID, display
name, scope label, enabled state and a binding with numeric IP:port, TLS, HTTP/2 and
optional HTTP/3 parameters. Scope labels do not install firewall rules.
Vhosts reference endpoints only through `frontend.listener_ids`. Inline frontend
listener definitions and the old global listener-pair compatibility fields are not
accepted in 0.8.0. A named endpoint can be shared by multiple vhosts; same-socket
transport settings must agree. Disabled endpoints create no socket and grant no vhost
binding. Unknown/duplicate IDs and admin-port conflicts are rejected.
Listener transport changes require restart. The panel shows desired and actually bound
endpoints separately. A wildcard bind never widens a vhost's own destination-IP match.
## Certificate library
Certificates is an independent sidebar section. Import a PEM certificate/full chain
and PEM private key, give the entry an ID, specify domain names to validate the pair,
and save it to the inventory. In Vhost -> SSL certificates, select the saved entry.
Import does not add public SNI names by itself; active vhost assignment supplies names.
The advanced filename editor remains for CLI-managed existing pairs and direct SNI maps.
The library shows assignment and default status. ACME/Let's Encrypt and expiry renewal
are not implemented; the inventory/API boundary is ready for that future work.
Uploads: at most 128 KiB per file, key matching/name validation, immutable randomly
named private files, limited parallel imports and mode 600 on Unix. Config stores
filenames and IDs, never PEM private key bytes. File inputs are cleared after import.
Failure between staging and configuration publication may leave unused private files;
they are not automatically activated or deleted. Removing inventory metadata does not
delete key files. Back up the cert directory together with SQLite.
Existing referenced/default entries cannot be removed in the UI without unassigning them.
Certificate changes affect new handshakes; existing sessions continue normally.
The resolver is shared by listeners: one DNS name cannot use different certificates
on different destination IPs. Conflicts are rejected rather than silently chosen.
HTTP-only startup also prepares the private certificate directory, but creates no TLS
socket unless configured. No existing certificates are overwritten.
## Response policies and cache on extra frontends
Global and per-vhost `server_header` accept `preserve`, `hide`, `custom` plus `value`.
Omitted/null vhost policy inherits the global choice. Final policy applies to origin
responses, HITs, local pages and errors for inline/named TCP/TLS/H3 listeners.
Generic header rules run before this dedicated Server policy.
As of 0.18.8, `diagnostic_headers` exposes only the request-ID switch:
```json
"diagnostic_headers": {
"request_id": false
}
```
There is no revision response-header switch or special `X-Rust-Proxy-Revision` handling. If an upstream or ordinary response-header rule supplies that name, it behaves like any other non-protected response header.
Request IDs remain available internally/upstream and in logs. X-Mock-Origin is preserved and can
be removed with ordinary global or per-vhost response-header rules. An explicit vhost diagnostic
object overrides the request-ID choice; null inherits.
Cache keys now include the actual frontend IP:port and stable canonical forwarding
metadata. Empty HTTP/2/HTTP/3 GET bodies without an exact length are checked by peeking
at most eight frames, skipping empty DATA frames; nonempty data/trailers are
replayed to the origin without buffering the full body.
A stream with data/trailers bypasses cache. Reusing the same socket with a different
client source PORT no longer changes the forwarded representation.
Client IP still affects the conservative all-header fingerprint, so different clients
can have separate cache entries. Auth, cookies, no-store, private, upgrades and partial
bodies still bypass caching. Cookies created by a login or the sticky-session feature
are not a cache bug. Close/consume the entire response before expecting a stored HIT.