This commit is contained in:
Mateusz Gruszczyński committed 2026-10-27 13:22:43 +01:00
1 parent e364392659
commit f27fbf6a30
28 files changed
+2000 -60

No files matched your search

+37 -9
View File
@@ -19,7 +19,7 @@ Global restrictions add to per-vhost and path rules. Rate-limit requests are cou
Default deny plus explicit allow exceptions is usually safer for private admin applications. Apply rules to a staging client before enforcing them on a live business-critical service.
In the **Vhost → Security** editor, Traffic policy groups reusable ACL profiles and the separate **inline Vhost IP/CIDR access list** together, followed by HTTP methods, request Content-Type filtering, per-IP rates, country policy, country-rate and User-Agent-rate controls. The inline list is not a second version of an assigned profile: both layers remain independently enforced; an allow in one does not cancel a deny in the other. The **Vhost → Authentication** tab selects exactly one of Basic Auth, Tinyauth, Authelia and authentik. HSTS, security headers and User-Agent blocking are separate Security groups. **Custom locations → Access** separates its ACL profile, HTTP method, country and inline IP/CIDR fields. These are only layout changes; restriction scopes still combine as described above.
In the **Vhost → Security** editor, Traffic policy groups reusable ACL profiles and the separate **inline Vhost IP/CIDR access list** together, followed by HTTP methods, request Content-Type filtering, per-IP rates, country policy, country-rate and User-Agent-rate controls. The inline list is not a second version of an assigned profile: both layers remain independently enforced; an allow in one does not cancel a deny in the other. The **Vhost → Authentication** tab first selects an identity provider, then a compatible integration method (Forward Auth, OIDC or Basic). A Vhost still uses only one active method; existing JSON settings are retained for compatibility. HSTS, security headers and User-Agent blocking are separate Security groups. **Custom locations → Access** separates its ACL profile, HTTP method, country and inline IP/CIDR fields. These are only layout changes; restriction scopes still combine as described above.
## Content-Type request denylist
@@ -29,22 +29,32 @@ Ordinary Vhosts can reject selected MIME types under **Vhosts → Security → R
Method policies allow, block or leave methods unrestricted. A denied method returns `405`, while typical ACL/country denials return `403`. Per-client rate limits can configure request count, window and burst with optional country overrides; exceeding the limit returns `429` with `Retry-After`. Limits are application controls, not a replacement for upstream DDoS protection.
## Basic Auth, Tinyauth, Authelia and authentik
## Identity providers and authentication integration methods
Choose **Identity provider → Integration method** in **Vhost → Authentication**. Tinyauth, Authelia and authentik support both **Forward Auth** and **OIDC** when the installed identity service has the relevant endpoint enabled. Pocket ID and other generic OpenID Connect issuers use **OIDC** only. Built-in HTTP Basic remains available. Forward Auth uses the vendor-specific settings object and transport, while OIDC uses the shared `oidc` settings and an exact application callback. The protected app does not need to implement OIDC.
New Vhosts store an explicit `authentication` choice; old Vhosts with only `tinyauth.enabled`, `authelia.enabled`, `authentik.enabled`, `basic_auth.enabled` or `oidc.enabled` still load. An older OIDC configuration without a named provider appears as **Other OIDC provider**, retaining its issuer and client settings. The selected pair must agree with the enabled settings (e.g. `authentication: {provider: authelia, method: oidc}` requires `oidc.enabled: true` and `authelia.enabled: false`). Conflicting choices are rejected, not silently downgraded to an unprotected Vhost.
### Existing integrations
- **Basic Auth:** protect selected Vhosts with configured credentials. Use HTTPS so credentials are not sent over plaintext.
- **Tinyauth:** add a verification URL and an HTTPS login URL. RustProxy makes a bounded, body-free authorization request and can pass specifically allowed identity headers upstream. An origin URL automatically uses `/api/auth/nginx` (or set that path explicitly). This Nginx auth-request integration sends `X-Original-URL` and `X-Original-Method`, with a validated `X-Forwarded-For` and `X-Real-IP` for Tinyauth IP ACLs. It does **not** send `X-Forwarded-Host` or `X-Forwarded-URI` to the verifier, avoiding the `conflicting auth module headers` rejection introduced in Tinyauth 5.2.0 while keeping compatibility with earlier versions that implement the Nginx endpoint. Tinyauth has its own timeout and private-backend policy.
- **Provider-neutral gateway error pages (0.34.15):** One embedded `src/admin/web/error_auth_provider.html` template renders a self-contained HTML page for **Tinyauth, Authelia, authentik, and future providers**, using only the safe provider display name and the failure category. It replaces the three vendor-specific `error_tinyauth_*.html` source files while preserving the familiar Tinyauth response titles and statuses. For example: `502 Tinyauth connection error` if its HTTP client cannot reach Tinyauth (DNS/TCP/TLS/transport), `504 Tinyauth timeout` if the auth deadline expires, or `502 Tinyauth verification error` for unexpected verifier status or invalid/oversized data. The page always retains the HTTP error status, `Content-Type: text/html; charset=utf-8`, `Cache-Control: private, no-store` and `X-Content-Type-Options: nosniff`. Backend URLs, protocol errors and identity data are not shown to visitors. All of these cases **deny access** to the protected origin. HTTP `401`/`403` and configured login redirects remain unchanged. These auth-specific pages take precedence over custom Vhost/general HTTP error pages so the failure remains distinguishable. The generic failure marker also protects Basic Auth denials and provider login redirects from being replaced by Vhost pages. HTTPS-verifier transport errors are classified as connection failures, truncated/oversized/invalid verifier responses as verification failures, and verification deadlines as timeouts.
- Point the verifier URL **directly** at the private Tinyauth service (for example `http://tinyauth:3000/api/auth/nginx`), rather than routing it through a second public proxy that might inject conflicting headers. Do not disable Tinyauth's header-spoofing protections. Confirm that Tinyauth trusts only the actual RustProxy address/network when enabling Tinyauth IP-based access controls (`TINYAUTH_AUTH_TRUSTEDPROXIES`).
- **Authelia (0.34.15):** select **Authelia** under **Vhost → Authentication**. Enter the internal service origin (for example `http://authelia:9091`) and the public HTTPS login portal (for example `https://auth.example.com`); RustProxy calls `/api/authz/forward-auth`. It forwards trusted `X-Forwarded-*`, `X-Original-URL` and `X-Original-Method` metadata, verifies the provider result, returns provider-approved `302/303` login redirects only to the configured portal origin, and forwards configured `Remote-*` identity headers after stripping client-forged values. A `200` verifier response alone grants access. `401`/`403` deny; transport failures return 502 and timeouts 504. The Authelia `session.cookies` domains and `authelia_url` are defined in Authelia itself: protecting **unrelated registered domains** generally requires a login URL/cookie configuration within each domain, not one cookie from a single unrelated site.
- **authentik (0.34.15):** select **authentik** and enter the private outpost origin (for example `http://authentik:9000`), not an `/if/flow` login URL. RustProxy calls `/outpost.goauthentik.io/auth/nginx`, forwards verified `X-Authentik-*` identity headers, and responds to a `401` with a same-origin login start at `/outpost.goauthentik.io/start?rd=...`. RustProxy reserves `/outpost.goauthentik.io` (and descendants) on the protected application hostname and forwards them to the configured outpost **without checking authentication again**, after ordinary global/Vhost IP/country/rate rules. No manual Custom Location is needed for that path. In authentik create a separate **Proxy Provider → Forward auth (single application)** for each protected external application URL, assign it to the serving outpost, then enable that Vhost's integration. Multiple unrelated domains can share the same authentik installation; they do **not** share a browser cookie across domains.
- **Adding another provider:** Keep the new vendor's `Settings` and `Compiled` implementation under `src/<provider>/mod.rs` and its tests under `src/<provider>/tests.rs`. Implement the `auth_provider::Provider` trait for runtime authorization, optional `reserved_path`/`serve_reserved` hooks for same-host callbacks, and (for Nginx-compatible providers) the shared `forward_auth::Adapter`. Add an enabled-by-default-false Vhost settings field, validate mutual exclusivity in `auth_provider::Selection`, compile it into the **single** `CompiledFrontend.auth_provider` slot, and register the method in the panel. Reuse `auth_provider::deny` / `auth_provider::gateway_failure` instead of adding separate HTML templates. Existing `tinyauth`, `authelia`, and `authentik` configuration keys remain backward compatible.
- **Per-provider security:** The verifier/outpost connection uses TLS certificate verification for HTTPS with optional additional CA, explicit private-backend opt-in and the existing safe-address/local-listener restrictions. Only allowlisted response identity fields and bounded session cookies reach applications/browsers. Inaccessible, malformed or timed-out authorization services **deny** origin access. Both Authelia and authentik are disabled by default; old Tinyauth settings are retained when inactive. Only one of the four authentication methods can be enabled for one Vhost. Protected responses bypass shared caching. Confirm both allowed/denied requests, logins, sessions, redirects and WebSockets with the actual provider before rollout.
- **Authelia (0.34.15):** select **Authelia → Forward Auth** under **Vhost → Authentication**. Enter the internal service origin (for example `http://authelia:9091`) and the public HTTPS login portal (for example `https://auth.example.com`); RustProxy calls `/api/authz/forward-auth`. It forwards trusted `X-Forwarded-*`, `X-Original-URL` and `X-Original-Method` metadata, verifies the provider result, returns provider-approved `302/303` login redirects only to the configured portal origin, and forwards configured `Remote-*` identity headers after stripping client-forged values. A `200` verifier response alone grants access. `401`/`403` deny; transport failures return 502 and timeouts 504. The Authelia `session.cookies` domains and `authelia_url` are defined in Authelia itself: protecting **unrelated registered domains** generally requires a login URL/cookie configuration within each domain, not one cookie from a single unrelated site.
- **authentik (0.34.15):** select **authentik → Forward Auth** and enter the private outpost origin (for example `http://authentik:9000`), not an `/if/flow` login URL. RustProxy calls `/outpost.goauthentik.io/auth/nginx`, forwards verified `X-Authentik-*` identity headers, and responds to a `401` with a same-origin login start at `/outpost.goauthentik.io/start?rd=...`. RustProxy reserves `/outpost.goauthentik.io` (and descendants) on the protected application hostname and forwards them to the configured outpost **without checking authentication again**, after ordinary global/Vhost IP/country/rate rules. No manual Custom Location is needed for that path. In authentik create a separate **Proxy Provider → Forward auth (single application)** for each protected external application URL, assign it to the serving outpost, then enable that Vhost's integration. Multiple unrelated domains can share the same authentik installation; they do **not** share a browser cookie across domains.
- **OIDC (0.34.16, opt-in):** choose **Authelia → OIDC**, **authentik → OIDC**, **Pocket ID → OIDC** or **Other OIDC provider → OIDC** for the protected Vhost. This switches to the shared OIDC implementation instead of the vendor's Forward Auth adapter. Provide the exact HTTPS **Issuer**, Client ID and confidential Client Secret, a strong unique Session Secret (`openssl rand -hex 32`), and `https://YOUR-EXACT-APP-HOST/_rustproxy/oidc/callback` as the **Redirect URL**. Register that exact callback as an allowed redirect URI in the identity provider. The issuer can be `https://auth.gruszczynski.cc` while the protected hostname is `app.linuxiarz.pl`; browser cookies do not cross between them. The issuer's discovery `/.well-known/openid-configuration`, authorization, token and JWKS endpoints must resolve from RustProxy and use the issuer's HTTPS origin with trusted TLS. Use split DNS or the private-address opt-in if the issuer resolves to internal addresses; do not disable HTTPS certificate validation. OIDC currently requires a confidential client using `client_secret_basic`, authorization-code flow, and an RS256 or ES256 signing key. Public PKCE-only clients are not supported.
- **OIDC session and identity:** RustProxy generates short-lived transaction state with S256 PKCE and nonce; requires a signed ID token with exact issuer, audience, validity and nonce; and encrypts a separate `__Host-` session cookie for the application host (default 3600 seconds, max 86400). The session is **not continuously revalidated with the issuer**; removing a user at the issuer does not invalidate an already-issued RustProxy session before its expiry or local logout (`/_rustproxy/oidc/logout`). Successful login injects `Remote-Sub`, `Remote-Issuer`, `Remote-User` and optional `Remote-Email`, `Remote-Name`, `Remote-Groups`; use `(Remote-Issuer, Remote-Sub)` for stable account identity and do not auto-link accounts solely by email or username. The backend must not be directly accessible from untrusted clients. Non-GET/HEAD requests without a valid session receive 401, and authentication endpoint failures return 502/504. The provider URL must not itself be protected by this Vhost's OIDC integration. For Authelia, enabling its Forward Auth portal alone is insufficient: also configure Authelia as an OIDC issuer under `identity_providers.oidc`, with at least one signing key, and register a confidential client for every callback URL (or separate clients per application). OIDC does not require any special support from the application being proxied, only from the remote identity provider.
- **Adding another provider:** Register the vendor and supported methods in `auth_provider::choice::IdentityProvider` and in the Vhost editor. OIDC-compatible vendors reuse the shared `oidc` integration and may need no new Rust transport adapter. New Forward Auth adapters belong in `src/<provider>/mod.rs` with tests and may reuse `forward_auth::Adapter`; their compiled implementation implements the object-safe `auth_provider::Provider` trait. Runtime request handling continues through one `CompiledFrontend.auth_provider` slot and provider-neutral `error_auth_provider.html`. Preserve legacy Vhost configuration keys; add new providers without copying OIDC protocol code or HTML error templates.
- **Per-provider security:** The verifier/outpost connection uses TLS certificate verification for HTTPS with optional additional CA, explicit private-backend opt-in and the existing safe-address/local-listener restrictions. Only allowlisted response identity fields and bounded session cookies reach applications/browsers. Inaccessible, malformed or timed-out authorization services **deny** origin access. Both Authelia and authentik are disabled by default; old Tinyauth settings are retained when inactive. Only one integration method can be enabled for one Vhost. Protected responses bypass shared caching. Confirm both allowed/denied requests, logins, sessions, redirects and WebSockets with the actual provider before rollout.
### Minimal Vhost configuration examples (inside a Vhost object)
Authelia:
Authelia with Forward Auth:
```json
"authentication": {"provider": "authelia", "method": "forward_auth"},
"authelia": {
"enabled": true,
"url": "http://authelia.internal:9091",
@@ -53,9 +63,10 @@ Authelia:
}
```
authentik (same URL for the outpost check and its reserved public path):
authentik with Forward Auth (same URL for the outpost check and reserved public path):
```json
"authentication": {"provider": "authentik", "method": "forward_auth"},
"authentik": {
"enabled": true,
"url": "http://authentik.internal:9000",
@@ -63,7 +74,24 @@ authentik (same URL for the outpost check and its reserved public path):
}
```
Set `basic_auth.enabled`, `tinyauth.enabled`, and the other provider's `enabled` to `false` for these examples. These are fragments, not whole Vhost documents. Protect the public provider portal with a separate Vhost **without** forward auth to avoid recursive redirects.
For central login from an unrelated application domain, select **Authelia → OIDC** and use the following Vhost fragment (also register this callback with the issuer):
```json
"authentication": {"provider": "authelia", "method": "oidc"},
"oidc": {
"enabled": true,
"issuer_url": "https://auth.gruszczynski.cc",
"backend_url": "http://10.0.0.20:9091",
"redirect_url": "https://app.linuxiarz.pl/_rustproxy/oidc/callback",
"client_id": "app-client-id",
"client_secret": "CHANGE_ME_CLIENT_SECRET",
"session_secret": "CHANGE_ME_RANDOM_SECRET_AT_LEAST_32_BYTES",
"scopes": "openid profile email",
"allow_private": true
}
```
The `client_secret` and `session_secret` are illustrative placeholders and must be replaced with generated values. Disable other authentication settings for this Vhost. Set `basic_auth.enabled`, `tinyauth.enabled`, and the other provider's `enabled` to `false` for these examples. These are fragments, not whole Vhost documents. Protect the public provider portal with a separate Vhost **without** forward auth to avoid recursive redirects.
Do not use a User-Agent blocklist as the primary access control: HTTP clients can forge their User-Agent freely.
+1 -1
View File
@@ -78,7 +78,7 @@ The section name in the URL and its corresponding JSON member in a full configur
| `logging` | `logging`, `error_log` |
| `global-security` | `global_security`, including `user_agent_blocking` |
Every GET returns a `value` object or array whose shape can be sent unchanged to the matching PUT. For the three grouped sections the `value` contains exactly the named members; for the other sections it is the serialized value of the matching configuration member. Saving does not alter unrelated sections. In 0.34.15 each ordinary Vhost may also configure mutually exclusive `authelia` and `authentik` objects alongside the existing `tinyauth`/`basic_auth` settings; both new providers default to disabled. See [Access](ACCESS.md).
Every GET returns a `value` object or array whose shape can be sent unchanged to the matching PUT. For the three grouped sections the `value` contains exactly the named members; for the other sections it is the serialized value of the matching configuration member. Saving does not alter unrelated sections. In 0.34.16 an ordinary Vhost may configure mutually exclusive `oidc`, `authelia` and `authentik` objects alongside existing `tinyauth`/`basic_auth` settings; every optional provider defaults to disabled. OIDC uses `/_rustproxy/oidc/callback` on an exact Vhost HTTPS hostname and requires issuer/client/session secrets. See [Access](ACCESS.md).
### Complete section-update example
+1
View File
@@ -7,6 +7,7 @@ RustProxy offers built-in integrations and optional helper components. Each has
| **Docker agent** | Discover running Docker services and publish generated Vhosts | Install separate agent on Docker host; use Bearer token and TLS certificate pin. [Guide](DOCKER_DISCOVERY.md). |
| **Tinyauth** | Delegate authentication for selected Vhosts | Existing Nginx auth-request support remains unchanged, with fail-closed 502/504 errors. [Access](ACCESS.md). |
| **Authelia** | Forward auth for selected Vhosts | Select it in Vhost Authentication, set internal service origin and trusted public HTTPS login URL, and configure the portal's per-domain cookie rules. [Access](ACCESS.md). |
| **OIDC integration method (Authelia, Pocket ID, authentik and compatible issuers)** | Central OAuth/OIDC login for protected apps across different parent domains | Select the identity provider, then OIDC. Set HTTPS issuer discovery, Client ID/Secret, explicit app callback and encrypted local session. Requires an OIDC client on the chosen provider. [Access](ACCESS.md). |
| **authentik** | Forward auth for selected Vhosts, including unrelated application domains | Configure one authentik single-application proxy provider per public application and its serving outpost; enter the outpost's internal origin. RustProxy handles the reserved outpost path automatically. [Access](ACCESS.md). |
| **ACME / Certbot** | Issue/renew HTTPS certificates | HTTP-01 or DNS-01 via Cloudflare, OVH or RFC2136; protect credentials. [Certificates](ACME_PROVIDERS.md). |
| **Prometheus** | Scrape operational metrics | Separate endpoint/token/CIDR rules. [Monitoring](MONITORING.md). |
+2 -2
View File
@@ -1,6 +1,6 @@
# RustProxy documentation
Practical guides for **RustProxy 0.34.15**. This index and the listed pages are also available in the authenticated panel at **`/docs → Reader`**. The adjacent **API** tab provides the embedded OpenAPI reference. Paths below are links to actual files in the source archive.
Practical guides for **RustProxy 0.34.16**. This index and the listed pages are also available in the authenticated panel at **`/docs → Reader`**. The adjacent **API** tab provides the embedded OpenAPI reference. Paths below are links to actual files in the source archive.
## Getting started
@@ -22,7 +22,7 @@ Practical guides for **RustProxy 0.34.15**. This index and the listed pages are
- [Experimental TLS post-quantum key exchange](TLS_POST_QUANTUM.md) — opt-in X25519MLKEM768, compatibility, rollback and validation.
- [TCP/UDP Streams](STREAMS.md) — non-HTTP forwarding and its security boundaries.
The Vhosts and Docker discovery guides include the shared adaptive request-rate chart scale introduced in 0.34.11. Version 0.34.12 preserves that adaptive range and adds a disabled-by-default X/Y scale display option under **Settings → Appearance → Charts**. Release 0.34.13 adds global HTTP security policies and UI layout improvements, groups the global User-Agent policy under `global_security`, provides consistent section-based GET/PUT APIs, and moves manual GeoIP refresh to `POST /api/config/geoip/update`. See [Dashboard](DASHBOARD.md). Release 0.34.14 keeps the Tinyauth Nginx-header compatibility patch and dedicated fail-closed 502/504 pages. Release 0.34.15 adds optional Authelia and authentik forward-auth integrations, a shared provider runtime and a single provider-neutral HTML error template. See [Access](ACCESS.md) and [Troubleshooting](TROUBLESHOOTING.md).
The Vhosts and Docker discovery guides include the shared adaptive request-rate chart scale introduced in 0.34.11. Version 0.34.12 preserves that adaptive range and adds a disabled-by-default X/Y scale display option under **Settings → Appearance → Charts**. Release 0.34.13 adds global HTTP security policies and UI layout improvements, groups the global User-Agent policy under `global_security`, provides consistent section-based GET/PUT APIs, and moves manual GeoIP refresh to `POST /api/config/geoip/update`. See [Dashboard](DASHBOARD.md). Release 0.34.14 keeps the Tinyauth Nginx-header compatibility patch and dedicated fail-closed 502/504 pages. Release 0.34.15 adds optional Authelia and authentik forward-auth integrations, a shared provider runtime and a single provider-neutral HTML error template. Release 0.34.16 adds optional OIDC central login across unrelated domains. See [Access](ACCESS.md) and [Troubleshooting](TROUBLESHOOTING.md).
## Integrations and operations
+8
View File
@@ -87,3 +87,11 @@ The latest source optimizations were **not all compiled or performance-tested**
6. Compare performance only under matched configurations with controlled repeatable traffic; do **not** label 0.34.0 as faster merely because its source reduces internal work.
For persistent problems, use the feature-specific guide in [Documentation](README.md) and preserve a redacted error example with environment/version and request ID.
## OIDC central login (0.34.16)
- **Login does not start / 502:** verify that the HTTPS Issuer URL is the exact `issuer` from `/.well-known/openid-configuration`, including any path or trailing slash. RustProxy must resolve that address and connect to it with a trusted certificate, or you must configure an explicit internal backend origin for server-side OIDC requests. Discovery, authorization, token, UserInfo and JWKS endpoints must have the same HTTPS origin as the issuer.
- **Redirect URI mismatch:** register the exact `https://APP-HOST/_rustproxy/oidc/callback` value with the identity provider. The callback hostname must be explicitly listed in the protected Vhost hosts and be accessed over HTTPS. Don't protect the IdP's own login Vhost using this OIDC setting.
- **Invalid code, nonce or signature:** ensure that the provider issues an `id_token` using RS256 or ES256 and that a confidential client uses `client_secret_basic` with authorization code and PKCE S256. Repeated callback requests or overwritten browser transaction cookies are refused. A single browser login flow per protected host avoids cookie conflicts.
- **No identity on the backend:** trust only requests through RustProxy. A verified login injects `Remote-Sub`, `Remote-Issuer`, `Remote-User`, and optional profile headers; the application must explicitly consume them. An OIDC session cookie on one app/domain is not a login cookie for another.
- **User removed at the provider but session still works:** local application sessions are independent and expire after the configured `session_ttl_seconds` (one hour by default); visit `/_rustproxy/oidc/logout` on the application origin to clear the local session. RustProxy does not implement back-channel logout or token revocation.