docs/auth: sync to current auth enum (required/app/public/none)

Replace the legacy `protected = true` reference with the four-tier
`auth` enum that's been live for weeks. Document the anti-exposure
guard (`scripts/check-ingress-auth-comments.py` + `scripts/tg`)
that enforces the inline-comment convention. Fix two stale paths:

  - `stacks/platform/modules/ingress_factory/` → `modules/kubernetes/ingress_factory/`
  - `stacks/platform/modules/traefik/middleware.tf` → `stacks/traefik/modules/traefik/middleware.tf`

Replace the single `protected = true` example with three: a
default Authentik-gated admin UI, an app-managed backend, and an
intentionally-public webhook receiver. Each example shows the
required comment line above the auth assignment.

[ci skip]
This commit is contained in:
Viktor Barzin 2026-05-11 19:28:42 +00:00
parent 85f1e92ad7
commit 205c902de5

View file

@ -44,7 +44,7 @@ graph TB
| Authentik Worker | 2026.2.2 | `stacks/authentik/` | Background task processors (2 replicas) | | Authentik Worker | 2026.2.2 | `stacks/authentik/` | Background task processors (2 replicas) |
| PgBouncer | Latest | `stacks/authentik/` | PostgreSQL connection pooler (3 replicas) | | PgBouncer | Latest | `stacks/authentik/` | PostgreSQL connection pooler (3 replicas) |
| Embedded Outpost | - | Built into Authentik | Forward auth endpoint for Traefik | | Embedded Outpost | - | Built into Authentik | Forward auth endpoint for Traefik |
| Traefik ForwardAuth | - | `ingress_factory` module | Middleware for protected ingresses | | Traefik ForwardAuth | - | `modules/kubernetes/ingress_factory/` | Middleware attached when `auth = "required"` or `"public"` |
| Vault OIDC Method | - | `stacks/vault/` | Human SSO authentication to Vault | | Vault OIDC Method | - | `stacks/vault/` | Human SSO authentication to Vault |
| Vault K8s Auth | - | `stacks/vault/` | Service account JWT authentication | | Vault K8s Auth | - | `stacks/vault/` | Service account JWT authentication |
@ -52,7 +52,16 @@ graph TB
### Forward Authentication Flow ### Forward Authentication Flow
Services configured with `protected = true` in the `ingress_factory` module automatically get Traefik ForwardAuth middleware configured. When an unauthenticated user accesses a protected service: Services pick an auth tier via the `auth` enum on the `ingress_factory` module (default `"required"`, fail-closed):
| Tier | Effect | When to use |
|------|--------|-------------|
| `"required"` | Authentik forward-auth gates every request | Backend has no own user auth — Authentik is the only gate |
| `"app"` | No Authentik middleware; backend's own login is the gate | Backend handles its own user auth (NextAuth, Django, OAuth, bearer-token API) |
| `"public"` | Authentik anonymous binding via `public` outpost | Audit trail without gating; only works for top-level browser navigation |
| `"none"` | No Authentik middleware at all | Anubis-fronted content, webhooks, OAuth callbacks, native-client APIs (CalDAV, WebDAV, Git) |
When `auth = "required"`, an unauthenticated request flows:
1. Request hits Traefik ingress 1. Request hits Traefik ingress
2. ForwardAuth middleware calls Authentik embedded outpost 2. ForwardAuth middleware calls Authentik embedded outpost
@ -64,6 +73,8 @@ Services configured with `protected = true` in the `ingress_factory` module auto
Authentik adds authentication headers (user, email, groups) to forwarded requests. These headers are stripped before reaching the backend to prevent confusion. Authentik adds authentication headers (user, email, groups) to forwarded requests. These headers are stripped before reaching the backend to prevent confusion.
**Anti-exposure guard**: every `auth = "app"` or `auth = "none"` line MUST have a preceding `# auth = "<tier>": <reason>` comment documenting what gates the backend (for `"app"`) or why the endpoint is intentionally public (for `"none"`). The convention is enforced by `scripts/check-ingress-auth-comments.py`, which `scripts/tg` runs on every `plan/apply/destroy/refresh` and blocks the terragrunt invocation if violated. Stack-scoped — each stack documents itself.
### Social Login & Invitation Flow ### Social Login & Invitation Flow
All new users must use an invitation link to register. The invitation-enrollment flow: All new users must use an invitation link to register. The invitation-enrollment flow:
@ -144,8 +155,9 @@ The public client flow:
| Path | Purpose | | Path | Purpose |
|------|---------| |------|---------|
| `stacks/authentik/` | Authentik deployment (servers, workers, PgBouncer) | | `stacks/authentik/` | Authentik deployment (servers, workers, PgBouncer) |
| `stacks/platform/modules/ingress_factory/` | Traefik ForwardAuth middleware config | | `modules/kubernetes/ingress_factory/` | Auth-tier enum + per-ingress middleware composition |
| `stacks/platform/modules/traefik/middleware.tf` | ForwardAuth middleware definition | | `stacks/traefik/modules/traefik/middleware.tf` | ForwardAuth middleware definitions (required + public outposts) |
| `scripts/check-ingress-auth-comments.py` | Comment-convention guard wired into `scripts/tg` |
| `stacks/vault/auth.tf` | Vault OIDC and K8s auth methods | | `stacks/vault/auth.tf` | Vault OIDC and K8s auth methods |
### Vault Paths ### Vault Paths
@ -160,17 +172,40 @@ The public client flow:
- `stacks/platform/` - Traefik ingress with ForwardAuth - `stacks/platform/` - Traefik ingress with ForwardAuth
- `stacks/vault/` - Vault auth methods - `stacks/vault/` - Vault auth methods
### Ingress Protection Example ### Ingress Protection Examples
Authentik-gated admin UI (default):
```hcl ```hcl
module "myapp_ingress" { module "myapp_ingress" {
source = "./modules/ingress_factory" source = "../../modules/kubernetes/ingress_factory"
name = "myapp"
namespace = "myapp"
tls_secret_name = var.tls_secret_name
# auth = "required" is the default — Authentik forward-auth is the gate.
}
```
name = "myapp" Backend with its own user auth (no Authentik in the way):
host = "myapp.viktorbarzin.me" ```hcl
protected = true # Enables ForwardAuth middleware module "myapp_ingress" {
source = "../../modules/kubernetes/ingress_factory"
name = "myapp"
namespace = "myapp"
tls_secret_name = var.tls_secret_name
# auth = "app": myapp uses NextAuth + Google OAuth; mobile clients can't follow Authentik 302.
auth = "app"
}
```
# ... other config Intentionally public webhook receiver:
```hcl
module "myapp_ingress" {
source = "../../modules/kubernetes/ingress_factory"
name = "webhook"
namespace = "webhooks"
tls_secret_name = var.tls_secret_name
# auth = "none": upstream signs payloads with HMAC; no user identity expected.
auth = "none"
} }
``` ```