Browse Source

docs(auth): document trusted-header SSO env + add .env.example

- docs/advanced/config/optional-config.md: TRUSTED_PROXY_* env table + security note
- docker-compose.yml: commented trusted-header SSO env block
- .env.example: full example env incl trusted-header SSO section

Makes the reverse-proxy SSO fully configurable via .env / docker-compose, and
documents the trust model (shared secret is the boundary; fails closed).

Authored By: Culpur Defense Inc.
pull/2693/head
Culpur Defense Inc. 5 days ago
parent
commit
3a618324e4
  1. 37
      .env.example
  2. 11
      docker-compose.yml
  3. 25
      docs/content/advanced/config/optional-config.md

37
.env.example

@ -0,0 +1,37 @@
# wg-easy — example environment file
#
# Copy to `.env` and adjust. All variables are OPTIONAL; wg-easy runs with
# sensible defaults and an interactive setup wizard if none are set.
# See docs: advanced/config/optional-config and advanced/config/unattended-setup.
# ── General ────────────────────────────────────────────────────────────────
# PORT=51821
# HOST=0.0.0.0
# INSECURE=false
# DISABLE_IPV6=false
# ── Unattended first-run setup (only used on first start) ───────────────────
# INIT_ENABLED=true
# INIT_USERNAME=admin
# INIT_PASSWORD=change-me-to-something-long
# INIT_HOST=vpn.example.com
# INIT_PORT=51820
# INIT_DNS=1.1.1.1,8.8.8.8
# ── Trusted-Header SSO (reverse-proxy authentication) ───────────────────────
# Have wg-easy trust an identity your authenticating reverse proxy (Authentik,
# Authelia, oauth2-proxy, …) has already verified, instead of showing its own
# login form. Disabled unless TRUSTED_PROXY_ENABLED=true.
#
# SECURITY: TRUSTED_PROXY_SECRET is the trust boundary. A client can forge any
# header, so the proxy must inject this secret and it must be unreachable by end
# users. The feature fails closed if enabled without a secret.
#
# TRUSTED_PROXY_ENABLED=true
# TRUSTED_PROXY_SECRET= # generate: openssl rand -hex 32
# TRUSTED_PROXY_SECRET_HEADER=x-wg-proxy-secret
# TRUSTED_PROXY_HEADER=x-authentik-username
# TRUSTED_PROXY_EMAIL_HEADER=x-authentik-email
# TRUSTED_PROXY_NAME_HEADER=x-authentik-name
# TRUSTED_PROXY_DEFAULT_ROLE=client # or: admin
# TRUSTED_PROXY_IPS= # optional CSV source-IP allowlist (defense-in-depth)

11
docker-compose.yml

@ -8,6 +8,17 @@ services:
# - PORT=51821
# - HOST=0.0.0.0
# - INSECURE=false
#
# Trusted-Header SSO (behind an authenticating reverse proxy).
# Disabled unless TRUSTED_PROXY_ENABLED=true. See docs: advanced/config/optional-config.
# - TRUSTED_PROXY_ENABLED=true
# - TRUSTED_PROXY_SECRET=${TRUSTED_PROXY_SECRET} # required; the proxy injects this
# - TRUSTED_PROXY_SECRET_HEADER=x-wg-proxy-secret
# - TRUSTED_PROXY_HEADER=x-authentik-username
# - TRUSTED_PROXY_EMAIL_HEADER=x-authentik-email
# - TRUSTED_PROXY_NAME_HEADER=x-authentik-name
# - TRUSTED_PROXY_DEFAULT_ROLE=client # or admin
# - TRUSTED_PROXY_IPS= # optional source-IP allowlist
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy

25
docs/content/advanced/config/optional-config.md

@ -20,3 +20,28 @@ You will however still see a IPv6 address in the Web UI, but it won't be used.
This option can be removed in the future, as more devices support IPv6.
///
## Trusted-Header SSO (Reverse-Proxy Authentication)
If wg-easy runs behind an authenticating reverse proxy (e.g. Authentik, Authelia, or oauth2-proxy in forward-auth mode), you can have wg-easy trust the identity the proxy has already verified instead of showing its own login form. When enabled, the proxy asserts the username via a header and wg-easy establishes a session for that user, provisioning the account on first sight.
This is **disabled by default**. Stock behaviour is unchanged unless you set `TRUSTED_PROXY_ENABLED=true`.
| Env | Default | Example | Description |
| ---------------------------- | ------------------- | ---------------------- | ----------------------------------------------------------------------------------------------- |
| `TRUSTED_PROXY_ENABLED` | `false` | `true` | Enables trusted-header SSO. |
| `TRUSTED_PROXY_SECRET` | _(none)_ | `a1b2c3…` (32+ bytes) | Shared secret the proxy injects. **Required** when enabled; feature fails closed if unset. |
| `TRUSTED_PROXY_SECRET_HEADER`| `x-wg-proxy-secret` | `x-proxy-secret` | Header carrying the shared secret. |
| `TRUSTED_PROXY_HEADER` | `x-authentik-username` | `x-forwarded-user` | Header carrying the verified username. |
| `TRUSTED_PROXY_EMAIL_HEADER` | `x-authentik-email` | `x-forwarded-email` | Optional header carrying the user's email. |
| `TRUSTED_PROXY_NAME_HEADER` | `x-authentik-name` | `x-forwarded-name` | Optional header carrying the user's display name. |
| `TRUSTED_PROXY_IPS` | _(empty)_ | `10.0.0.2,10.0.0.3` | Optional allowlist of proxy source IPs (defense-in-depth). Left empty when a NAT hides the peer. |
| `TRUSTED_PROXY_DEFAULT_ROLE` | `client` | `admin` | Role for auto-provisioned users (`client` or `admin`). The first-ever user is always `admin`. |
/// warning | Security — the secret is the trust boundary
A raw client can forge any header. **The `TRUSTED_PROXY_SECRET` is what proves a request actually came from your proxy** — the proxy must inject it and it must never be reachable by end users. Do not enable this feature without a strong secret, and make sure the header can only be set by the proxy (not passed through from the client). The optional `TRUSTED_PROXY_IPS` allowlist is a second layer, but note that container NAT often rewrites the source IP to a gateway address, making it non-discriminating on its own — the secret is mandatory, the IP list is not.
Provisioned SSO users have no local password and cannot log in via the password form. Set `TRUSTED_PROXY_DEFAULT_ROLE` deliberately.
///

Loading…
Cancel
Save