authentik: long-lived authenticated sessions, short-lived anonymous ones
- Adopt UserLoginStage (default-authentication-login) into Terraform and pin session_duration=weeks=4 so users stay logged in across browser restarts. There is no Brand.session_duration in 2026.2.x; UserLoginStage is the only correct lever. - Cap anonymous Django sessions at 2h via AUTHENTIK_SESSIONS__UNAUTHENTICATED_AGE on server + worker pods (default is days=1). Bots, healthcheckers, and partial flows now get reaped within 2h instead of accumulating for a day. Implementation note: the env var is injected via server.env / worker.env rather than authentik.sessions.unauthenticated_age, because authentik.existingSecret.secretName is set, which makes the chart skip rendering its own AUTHENTIK_* Secret. authentik.* values are therefore inert in this stack -- this is documented in .claude/reference/authentik-state.md so future edits use the right surface. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
dfbf6faf3d
commit
40a6cd067b
3 changed files with 60 additions and 0 deletions
|
|
@ -119,3 +119,18 @@ Removed bindings from:
|
|||
- `default-source-authentication` (PK: via policybindingmodel `1a779f24`) — Google/GitHub/Facebook OAuth
|
||||
|
||||
Policy still exists with 0 bindings. If brute-force protection is needed, bind to the **password stage** (not the flow level).
|
||||
|
||||
## Session Duration (2026-05-01)
|
||||
|
||||
Pinned via Terraform in `stacks/authentik/`:
|
||||
|
||||
| Knob | Value | Surface | Effect |
|
||||
|------|-------|---------|--------|
|
||||
| `UserLoginStage.session_duration` on `default-authentication-login` | `weeks=4` | `authentik_stage_user_login.default_login` in `authentik_provider.tf` | Authenticated users stay logged in 4 weeks across browser restarts. No sliding refresh — resets on each login. |
|
||||
| `AUTHENTIK_SESSIONS__UNAUTHENTICATED_AGE` (server + worker) | `hours=2` | `server.env` + `worker.env` in `modules/authentik/values.yaml` | Anonymous Django sessions (bots, healthcheckers, partial flows) are reaped within 2h instead of the 1d default. |
|
||||
|
||||
Notes:
|
||||
- There is **no** `Brand.session_duration`; `UserLoginStage` is the only correct lever for authenticated session lifetime.
|
||||
- Embedded outpost session storage moved from `/dev/shm` → Postgres table `authentik_providers_proxy_proxysession` in authentik 2025.10. The 2026-04-18 `/dev/shm`-fill outage class is no longer load-bearing in 2026.2.2; the `unauthenticated_age` cap is still the right lever for anonymous-session bloat from external monitors.
|
||||
- `ProxyProvider.access_token_validity` and `remember_me_offset` stay UI-managed via `ignore_changes`.
|
||||
- The `unauthenticated_age` env var is injected via `server.env` / `worker.env` (not `authentik.sessions.unauthenticated_age`) because we set `authentik.existingSecret.secretName: goauthentik`, which makes the chart skip rendering its own `AUTHENTIK_*` Secret. The `authentik.*` value block is therefore inert in this stack — anything new under `authentik.*` must use the `*.env` arrays instead. The same applies to the existing `authentik.cache.*`, `authentik.web.*`, `authentik.worker.*` blocks (currently inert; live values come from the orphaned, helm-keep-policy `goauthentik` Secret created by chart 2025.10.3 before `existingSecret` was introduced).
|
||||
|
|
|
|||
|
|
@ -57,3 +57,34 @@ resource "authentik_provider_proxy" "catchall" {
|
|||
ignore_changes = [property_mappings, jwt_federation_sources, skip_path_regex, internal_host, basic_auth_enabled, basic_auth_password_attribute, basic_auth_username_attribute, intercept_header_auth, access_token_validity]
|
||||
}
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Default User Login stage — bound to default-authentication-flow.
|
||||
# Adopted into Terraform 2026-05-01 to set session_duration=weeks=4 so users
|
||||
# stay logged in across browser restarts. There is no Brand.session_duration
|
||||
# in authentik 2026.2.x — UserLoginStage is the correct knob.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
data "authentik_stage" "default_authentication_login" {
|
||||
name = "default-authentication-login"
|
||||
}
|
||||
|
||||
import {
|
||||
to = authentik_stage_user_login.default_login
|
||||
id = data.authentik_stage.default_authentication_login.id
|
||||
}
|
||||
|
||||
resource "authentik_stage_user_login" "default_login" {
|
||||
name = "default-authentication-login"
|
||||
session_duration = "weeks=4"
|
||||
lifecycle {
|
||||
# Pin only session_duration; everything else stays UI-managed so the
|
||||
# plan doesn't churn unrelated knobs (e.g. remember_me_offset toggles).
|
||||
ignore_changes = [
|
||||
remember_me_offset,
|
||||
terminate_other_sessions,
|
||||
geoip_binding,
|
||||
network_binding,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ authentik:
|
|||
|
||||
server:
|
||||
replicas: 3
|
||||
# Anonymous Django sessions (no completed login: bots, healthcheckers,
|
||||
# partial flows) expire in 2h. Default is days=1. Once login completes,
|
||||
# UserLoginStage.session_duration takes over via request.session.set_expiry.
|
||||
# Injected via server.env (not authentik.sessions.*) because we use
|
||||
# authentik.existingSecret.secretName, which makes the chart skip
|
||||
# rendering the AUTHENTIK_* secret — so the values block doesn't reach env.
|
||||
env:
|
||||
- name: AUTHENTIK_SESSIONS__UNAUTHENTICATED_AGE
|
||||
value: "hours=2"
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
|
|
@ -70,6 +79,11 @@ global:
|
|||
|
||||
worker:
|
||||
replicas: 3
|
||||
# Same unauthenticated_age cap as server — both the server (Django session
|
||||
# middleware) and worker (cleanup tasks) need to see the value.
|
||||
env:
|
||||
- name: AUTHENTIK_SESSIONS__UNAUTHENTICATED_AGE
|
||||
value: "hours=2"
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue