From d02eb5ec5055ad9bc7c09689d03830a6328c3cfd Mon Sep 17 00:00:00 2001 From: Ronni Baslund Date: Wed, 10 Jun 2026 07:53:49 +0200 Subject: [PATCH] fix(authentik): pin chart 2026.5.2, grant_types allowlist, portal redirect URI - Pin the helm-controller chart version (unset = silent latest upgrades) and move the image tag under global.image per the 2026.5 chart layout. - Authentik 2026.5 enforces a per-provider grant_types allowlist; empty list rejected every authorize request. Allow authorization_code + refresh_token for portal and operator providers. - Fix the portal redirect URI to the nuxt-oidc-auth callback path. - Serve the auth ingress on :80 with a per-router HTTPS redirect so the cert-manager HTTP-01 solver keeps working. --- .../blueprints/operator-application.yaml | 6 ++++++ .../blueprints/portal-application.yaml | 8 ++++++- .../production/fleet/authentik/helmchart.yaml | 19 +++++++++++++---- .../fleet/authentik/redirect-middleware.yaml | 21 +++++++++++++++++++ .../production/fleet/authentik/values.yaml | 12 ++++++++--- 5 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 infrastructure/production/fleet/authentik/redirect-middleware.yaml diff --git a/infrastructure/production/fleet/authentik/blueprints/operator-application.yaml b/infrastructure/production/fleet/authentik/blueprints/operator-application.yaml index ecbb368..d6a6df6 100644 --- a/infrastructure/production/fleet/authentik/blueprints/operator-application.yaml +++ b/infrastructure/production/fleet/authentik/blueprints/operator-application.yaml @@ -44,6 +44,12 @@ entries: - !Find [authentik_providers_oauth2.scopemapping, [managed, "goauthentik.io/providers/oauth2/scope-profile"]] sub_mode: hashed_user_id issuer_mode: per_provider + # Authentik 2026.5+ enforces a per-provider grant_types allowlist; an empty + # list rejects every authorize request ("Invalid grant_type for provider"). + # authorization_code = login; refresh_token = offline_access silent refresh. + grant_types: + - authorization_code + - refresh_token - id: operator-application model: authentik_core.application diff --git a/infrastructure/production/fleet/authentik/blueprints/portal-application.yaml b/infrastructure/production/fleet/authentik/blueprints/portal-application.yaml index 4e63348..151e69c 100644 --- a/infrastructure/production/fleet/authentik/blueprints/portal-application.yaml +++ b/infrastructure/production/fleet/authentik/blueprints/portal-application.yaml @@ -32,13 +32,19 @@ entries: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]] redirect_uris: - matching_mode: strict - url: https://app.dezky.eu/api/auth/callback + url: https://app.dezky.eu/auth/oidc/callback property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [managed, "goauthentik.io/providers/oauth2/scope-openid"]] - !Find [authentik_providers_oauth2.scopemapping, [managed, "goauthentik.io/providers/oauth2/scope-email"]] - !Find [authentik_providers_oauth2.scopemapping, [managed, "goauthentik.io/providers/oauth2/scope-profile"]] sub_mode: hashed_user_id issuer_mode: per_provider + # Authentik 2026.5+ enforces a per-provider grant_types allowlist; an empty + # list rejects every authorize request ("Invalid grant_type for provider"). + # authorization_code = login; refresh_token = offline_access silent refresh. + grant_types: + - authorization_code + - refresh_token - id: portal-application model: authentik_core.application diff --git a/infrastructure/production/fleet/authentik/helmchart.yaml b/infrastructure/production/fleet/authentik/helmchart.yaml index 3eade5a..ade1d2e 100644 --- a/infrastructure/production/fleet/authentik/helmchart.yaml +++ b/infrastructure/production/fleet/authentik/helmchart.yaml @@ -1,6 +1,6 @@ # Authentik via the k3s Helm controller. valuesContent mirrors values.yaml -# (keep them in sync). Version intentionally unpinned for the first install — -# PIN the resolved chart version here once it's up (see RUNBOOK.md). +# (keep them in sync). valuesContent here is the LIVE source — values.yaml is +# just a human-readable mirror, not consumed by helm-controller. # # The 'authentik-secret' Secret must exist in dezky-auth BEFORE this (it carries # AUTHENTIK_SECRET_KEY + the DB/Redis/bootstrap creds via global.envFrom). @@ -12,12 +12,18 @@ metadata: spec: repo: https://charts.goauthentik.io chart: authentik + # Pinned: helm-controller reconciles on a loop and pulls the LATEST chart when + # version is unset — a successful reconcile would then silently upgrade + # authentik. Keep == the deployed version. + version: 2026.5.2 targetNamespace: dezky-auth createNamespace: true valuesContent: |- - image: - tag: "2026.5.2" global: + # Image moved under global.image in chart 2026.5.x; the old top-level + # `image:` key now hard-fails the chart's deprecation guard (deprectations.yaml). + image: + tag: "2026.5.2" envFrom: - secretRef: name: authentik-secret @@ -45,6 +51,11 @@ spec: ingressClassName: traefik annotations: cert-manager.io/cluster-issuer: letsencrypt-prod + # Serve on :80 too so the cert-manager ACME HTTP-01 solver can answer + # on port 80 at renewal; redirect-https bounces other traffic to HTTPS. + # (Middleware lives in authentik/redirect-middleware.yaml.) + traefik.ingress.kubernetes.io/router.entrypoints: web,websecure + traefik.ingress.kubernetes.io/router.middlewares: dezky-auth-redirect-https@kubernetescrd hosts: - auth.dezky.eu paths: diff --git a/infrastructure/production/fleet/authentik/redirect-middleware.yaml b/infrastructure/production/fleet/authentik/redirect-middleware.yaml new file mode 100644 index 0000000..c9989bb --- /dev/null +++ b/infrastructure/production/fleet/authentik/redirect-middleware.yaml @@ -0,0 +1,21 @@ +# HTTP→HTTPS redirect for the authentik ingress (auth.dezky.eu), in the +# dezky-auth namespace so it can be referenced by the Helm-rendered ingress. +# +# Replaces the former global Traefik entrypoint redirect, which broke ACME +# HTTP-01 (see ../traefik/helmchartconfig.yaml). Attached to the authentik +# router via values.yaml ingress.annotations so the cert-manager solver can +# still answer the challenge on :80 at renewal. +# +# Referenced from the Ingress as: dezky-auth-redirect-https@kubernetescrd +# +# NOTE: applied out-of-band (kubectl apply -f), not part of the authentik Helm +# release — the chart only renders the Deployment/Service/Ingress. +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: redirect-https + namespace: dezky-auth +spec: + redirectScheme: + scheme: https + permanent: true diff --git a/infrastructure/production/fleet/authentik/values.yaml b/infrastructure/production/fleet/authentik/values.yaml index 2fee60d..a5d5dfe 100644 --- a/infrastructure/production/fleet/authentik/values.yaml +++ b/infrastructure/production/fleet/authentik/values.yaml @@ -8,10 +8,11 @@ # pulls latest). After it's up, pin the installed chart + image versions here + # in RUNBOOK.md for reproducibility. -image: - tag: "2026.5.2" # deployed version (latest chart as of 2026-06-08) - global: + # Image moved under global.image in chart 2026.5.x; the old top-level `image:` + # key now hard-fails the chart's deprecation guard. + image: + tag: "2026.5.2" # deployed version; pinned == spec.version in helmchart.yaml # AUTHENTIK_SECRET_KEY, AUTHENTIK_POSTGRESQL__PASSWORD, AUTHENTIK_REDIS__PASSWORD, # AUTHENTIK_BOOTSTRAP_PASSWORD, AUTHENTIK_BOOTSTRAP_TOKEN envFrom: @@ -45,6 +46,11 @@ server: ingressClassName: traefik annotations: cert-manager.io/cluster-issuer: letsencrypt-prod + # Serve on :80 too so the cert-manager ACME HTTP-01 solver can answer on + # port 80 at renewal; redirect-https bounces other traffic to HTTPS. + # (Middleware lives in authentik/redirect-middleware.yaml.) + traefik.ingress.kubernetes.io/router.entrypoints: web,websecure + traefik.ingress.kubernetes.io/router.middlewares: dezky-auth-redirect-https@kubernetescrd hosts: - auth.dezky.eu paths: