From 24795ec203ad4909d39ddd125c282913297482d6 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sun, 10 May 2026 16:18:42 +0000 Subject: [PATCH] authentik: codify proxy provider TTL + adopt embedded outpost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump access_token_validity to weeks=4 (was hours=168, UI-managed in ignore_changes). Drives the cookie Max-Age and the proxysession.expires TTL — keeps users logged in for 28d instead of 7d. Adopt the embedded outpost into Terraform so the postgres-session-backend fix from earlier today (2026-05-10) is described as code: - kubernetes_json_patches.deployment carries dshm 2Gi tmpfs, resource requests/limits, the app.kubernetes.io/component=server pod label (workaround for goauthentik 2026.2.2 service.py:52 selector mismatch on standalone embedded outposts), and AUTHENTIK_POSTGRESQL__* envFrom the shared `goauthentik` Secret so the postgres session backend can connect to the dbaas cluster. - kubernetes_json_patches.service replaces the controller-set selector (which targets app.kubernetes.io/name=authentik / the goauthentik-server pods) with the outpost's own labels — without this, endpoints are empty and auth-proxy falls back to Basic-Auth realm "Emergency Access". The `managed` field ("goauthentik.io/outposts/embedded") is server-set and not in the Terraform provider's schema, so TF preserves it across applies (writes only fields it knows about). Plan-to-zero verified. --- stacks/authentik/authentik_provider.tf | 121 ++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/stacks/authentik/authentik_provider.tf b/stacks/authentik/authentik_provider.tf index f34214fe..9a20a4ee 100644 --- a/stacks/authentik/authentik_provider.tf +++ b/stacks/authentik/authentik_provider.tf @@ -53,11 +53,130 @@ resource "authentik_provider_proxy" "catchall" { # doesn't require an HCL edit. authorization_flow = data.authentik_flow.default_authorization_implicit_consent.id invalidation_flow = data.authentik_flow.default_provider_invalidation.id + # Cookie / proxysession TTL. Drives `Max-Age` on `authentik_proxy_*` + # cookies and the `expires` column in `authentik_providers_proxy_proxysession`. + # See note on the embedded outpost below — bumping this requires an outpost + # pod restart for the gorilla session store to rebind. + access_token_validity = "weeks=4" lifecycle { - 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] + 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] } } +# ----------------------------------------------------------------------------- +# Embedded outpost record. Adopted into Terraform 2026-05-10 as part of the +# postgres-session-backend fix: +# - `managed` is set server-side to `goauthentik.io/outposts/embedded` so +# the outpost binary's `IsEmbedded()` check returns true → it loads the +# PostgreSQL session backend (PR #16628). The Terraform provider does +# NOT expose `managed` in the schema, so the field is preserved across +# applies (TF only writes fields it knows about). +# - kubernetes_json_patches.deployment carries: +# * dshm 2Gi tmpfs (covers the 2026-04-18 ENOSPC class of issues) +# * resources requests/limits +# * `app.kubernetes.io/component=server` pod label so the K8s service +# selector lights up endpoints (works around goauthentik 2026.2.2 +# service.py:52 selector mismatch on standalone embedded outposts). +# * AUTHENTIK_POSTGRESQL__{HOST,PORT,USER,PASSWORD,NAME} envFrom the +# shared `goauthentik` Secret so the postgres session backend has +# credentials to connect to the dbaas cluster. +# - kubernetes_json_patches.service replaces the controller-set selector +# (which incorrectly targets `app.kubernetes.io/name=authentik`, i.e. +# the goauthentik-server pods) with the outpost's own labels. +# ----------------------------------------------------------------------------- + +resource "authentik_outpost" "embedded" { + name = "authentik Embedded Outpost" + type = "proxy" + protocol_providers = [authentik_provider_proxy.catchall.id] + service_connection = "99e227a7-4562-4888-9660-4c27da678c50" + config = jsonencode({ + log_level = "trace" + docker_labels = null + authentik_host = "https://authentik.viktorbarzin.me/" + docker_network = null + container_image = null + docker_map_ports = true + refresh_interval = "minutes=5" + kubernetes_replicas = 1 + kubernetes_namespace = "authentik" + authentik_host_browser = "" + object_naming_template = "ak-outpost-%(name)s" + authentik_host_insecure = false + kubernetes_service_type = "ClusterIP" + kubernetes_ingress_path_type = null + kubernetes_image_pull_secrets = [] + kubernetes_ingress_class_name = null + kubernetes_disabled_components = [] + kubernetes_ingress_annotations = {} + kubernetes_ingress_secret_name = "authentik-outpost-tls" + kubernetes_httproute_annotations = {} + kubernetes_httproute_parent_refs = [] + kubernetes_json_patches = { + deployment = [ + { + op = "add" + path = "/spec/template/spec/volumes" + value = [{ name = "dshm", emptyDir = { medium = "Memory", sizeLimit = "2Gi" } }] + }, + { + op = "add" + path = "/spec/template/spec/containers/0/volumeMounts" + value = [{ name = "dshm", mountPath = "/dev/shm" }] + }, + { + op = "add" + path = "/spec/template/spec/containers/0/resources" + value = { limits = { memory = "2560Mi" }, requests = { cpu = "100m", memory = "128Mi" } } + }, + { + op = "add" + path = "/spec/template/metadata/labels/app.kubernetes.io~1component" + value = "server" + }, + { + op = "add" + path = "/spec/template/spec/containers/0/env/-" + value = { name = "AUTHENTIK_POSTGRESQL__HOST", valueFrom = { secretKeyRef = { name = "goauthentik", key = "AUTHENTIK_POSTGRESQL__HOST" } } } + }, + { + op = "add" + path = "/spec/template/spec/containers/0/env/-" + value = { name = "AUTHENTIK_POSTGRESQL__PORT", valueFrom = { secretKeyRef = { name = "goauthentik", key = "AUTHENTIK_POSTGRESQL__PORT" } } } + }, + { + op = "add" + path = "/spec/template/spec/containers/0/env/-" + value = { name = "AUTHENTIK_POSTGRESQL__USER", valueFrom = { secretKeyRef = { name = "goauthentik", key = "AUTHENTIK_POSTGRESQL__USER" } } } + }, + { + op = "add" + path = "/spec/template/spec/containers/0/env/-" + value = { name = "AUTHENTIK_POSTGRESQL__PASSWORD", valueFrom = { secretKeyRef = { name = "goauthentik", key = "AUTHENTIK_POSTGRESQL__PASSWORD" } } } + }, + { + op = "add" + path = "/spec/template/spec/containers/0/env/-" + value = { name = "AUTHENTIK_POSTGRESQL__NAME", valueFrom = { secretKeyRef = { name = "goauthentik", key = "AUTHENTIK_POSTGRESQL__NAME" } } } + }, + ] + service = [ + { + op = "replace" + path = "/spec/selector" + value = { + "app.kubernetes.io/managed-by" = "goauthentik.io" + "app.kubernetes.io/name" = "authentik-outpost-proxy" + "goauthentik.io/outpost-name" = "authentik-embedded-outpost" + "goauthentik.io/outpost-type" = "proxy" + "goauthentik.io/outpost-uuid" = "0eecac0797c7443c892505f2f4fe3e47" + } + }, + ] + } + }) +} + # ----------------------------------------------------------------------------- # Default User Login stage — bound to default-authentication-flow. # Adopted into Terraform 2026-05-01 to set session_duration=weeks=4 so users