Files
axion1337.chat-gitops/apps/authentik/authentik-blueprints.yaml
T
Thore CimbalandClaude Sonnet 5 c52ff97502
Auto-Deploy on Push / verify-and-notify (push) Canceled after 0s
feat(authentik): capture MAS OIDC Provider/Application as a Blueprint
Closes issue #36. The OAuth2 Provider ("Matrix Authentication Service")
and its Application ("matrix" slug) linking Authentik to MAS were
originally clicked together by hand in the UI and existed nowhere as
code - unlike the flow fixes already captured in authentik-blueprints.yaml.
Losing the Authentik DB would have meant re-creating this from scratch,
including a fresh client_secret that MAS would no longer match.

The client_secret is read via !Env from AUTHENTIK_MAS_OIDC_CLIENT_SECRET,
sourced from a new key in the existing SOPS-encrypted authentik-credentials
Secret, rather than inlined into the blueprint ConfigMap (which isn't
itself encrypted). Value used is the actual live secret already in use,
read directly from the running Authentik DB - not a new/rotated one, so
this changes nothing about the current MAS<->Authentik pairing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 17:56:09 +02:00

284 lines
12 KiB
YAML

apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints
namespace: authentik
data:
matrix-invitation-flow.yaml: |
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: matrix-invitation-flow
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# Reaffirm the flow itself (already created manually; matched by slug)
- model: authentik_flows.flow
state: present
identifiers:
slug: matrix-invitation
id: matrix_invitation_flow
attrs:
name: matrix-invitation
title: matrix-invitation
designation: enrollment
# The prompt stage had accumulated 16 unrelated system validation_policies
# (e.g. default-user-settings-authorization, default-oobe-password-usable)
# from manual UI setup, likely a "select all" slip in the policy picker.
# These crash on an anonymous enrollment context ('AnonymousUser' object
# has no attribute 'group_attributes', etc). A prompt stage needs none here.
- model: authentik_stages_prompt.promptstage
state: present
identifiers:
name: matrix-invitation-prompt
attrs:
validation_policies: []
# Correct stage chain, mirroring the working matrix-enrollment flow:
# Invite -> Prompt (username/email/password) -> Write -> Password -> Login
# Root cause of the original bug: only Invite+Prompt were bound, both at
# order=0, so the flow never wrote the user to the DB or logged them in.
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_invitation_flow
order: 0
attrs:
stage: !Find [authentik_stages_invitation.invitationstage, [name, matrix-enrollment-invitation]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_invitation_flow
order: 1
attrs:
stage: !Find [authentik_stages_prompt.promptstage, [name, matrix-invitation-prompt]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_invitation_flow
order: 2
attrs:
stage: !Find [authentik_stages_user_write.userwritestage, [name, default-source-enrollment-write]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_invitation_flow
order: 3
attrs:
stage: !Find [authentik_stages_password.passwordstage, [name, default-authentication-password]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_invitation_flow
order: 4
attrs:
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-source-enrollment-login]]
# Without an explicit destination, the flow falls back to Authentik's own
# /if/user/ dashboard, which refuses type=external users ("Die Oberflaeche
# kann nur von internen Nutzern geoeffnet werden") - exactly the user type
# these Matrix-only accounts correctly have. Send them to Element instead.
- model: authentik_stages_redirect.redirectstage
state: present
identifiers:
name: matrix-invitation-redirect
id: matrix_invitation_redirect_stage
attrs:
mode: static
target_static: https://axion1337.chat
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_invitation_flow
order: 5
attrs:
stage: !KeyOf matrix_invitation_redirect_stage
matrix-recovery-flow.yaml: |
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: matrix-recovery-flow
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# matrix-recovery existed but had zero stage bindings (dead flow), and the
# real login flow (default-authentication-flow, used by the MAS OAuth2
# provider's authentication_flow) didn't link to it at all - no "Forgot
# password?" link was ever shown. Reuses the same default-recovery-*
# stages the built-in default-recovery-flow already uses successfully,
# plus our own redirect stage instead of falling back to the authentik
# dashboard (blocked for type=external Matrix users).
- model: authentik_flows.flow
state: present
identifiers:
slug: matrix-recovery
id: matrix_recovery_flow
attrs:
designation: recovery
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_recovery_flow
order: 10
attrs:
stage: !Find [authentik_stages_identification.identificationstage, [name, default-recovery-identification]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_recovery_flow
order: 20
attrs:
stage: !Find [authentik_stages_email.emailstage, [name, default-recovery-email]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_recovery_flow
order: 30
attrs:
stage: !Find [authentik_stages_prompt.promptstage, [name, "Change your password"]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_recovery_flow
order: 40
attrs:
stage: !Find [authentik_stages_user_write.userwritestage, [name, default-recovery-user-write]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_recovery_flow
order: 100
attrs:
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-recovery-user-login]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !KeyOf matrix_recovery_flow
order: 110
attrs:
stage: !Find [authentik_stages_redirect.redirectstage, [name, matrix-invitation-redirect]]
# Wire the "Forgot password?" link on the real login flow used by MAS
- model: authentik_stages_identification.identificationstage
state: present
identifiers:
name: default-authentication-identification
attrs:
recovery_flow: !KeyOf matrix_recovery_flow
matrix-mfa-setup-redirect.yaml: |
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: matrix-mfa-setup-redirect
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# 2FA is optional (default-authentication-mfa-validation has
# not_configured_action=skip - login never blocks on missing MFA).
# Users who want to opt in use these built-in single-stage setup flows
# directly (unreachable via /if/user/, which is blocked for type=external
# Matrix accounts). Without a stage after the setup itself, completion
# fell back to the same blocked /if/user/ dashboard - append our redirect.
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !Find [authentik_flows.flow, [slug, default-authenticator-totp-setup]]
order: 10
attrs:
stage: !Find [authentik_stages_redirect.redirectstage, [name, matrix-invitation-redirect]]
- model: authentik_flows.flowstagebinding
state: present
identifiers:
target: !Find [authentik_flows.flow, [slug, default-authenticator-webauthn-setup]]
order: 10
attrs:
stage: !Find [authentik_stages_redirect.redirectstage, [name, matrix-invitation-redirect]]
matrix-brand-default-app.yaml: |
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: matrix-brand-default-app
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# Root cause behind several dead ends: an authenticated user hitting "/"
# with no other destination (e.g. after logging in mid-way through the
# TOTP/WebAuthn setup flows) falls back to Brand.default_application: if
# unset, that's /if/user/, which type=external Matrix accounts can't
# open. Only affects the bare "/" fallback - explicit URLs like
# /if/admin/ are unaffected, so internal/staff access is unchanged.
- model: authentik_brands.brand
state: present
identifiers:
domain: authentik-default
attrs:
default_application: !Find [authentik_core.application, [slug, matrix]]
matrix-oidc-provider.yaml: |
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: matrix-oidc-provider
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# The OIDC Provider + Application linking Authentik to MAS was originally
# clicked together by hand in the UI and existed nowhere as code (issue
# #36): losing the Authentik DB would have meant re-creating this from
# scratch, including a new client_secret that MAS would then no longer
# match. client_secret is read from AUTHENTIK_MAS_OIDC_CLIENT_SECRET
# (see authentik.yaml HelmRelease values) rather than inlined here,
# since this ConfigMap itself is not SOPS-encrypted - the actual value
# lives in the authentik-credentials Secret instead.
- model: authentik_providers_oauth2.oauth2provider
state: present
identifiers:
name: Matrix Authentication Service
id: matrix_mas_provider
attrs:
client_type: confidential
client_id: dHbTAgAgXvjh3VALh220mB3dxcVXAifiXU2ZO3U6
client_secret: !Env AUTHENTIK_MAS_OIDC_CLIENT_SECRET
# Path includes MAS's own upstream-provider ID, not Authentik's -
# must match MAS's config exactly or the OIDC callback breaks.
redirect_uris:
- matching_mode: strict
url: https://account.axion1337.chat/upstream/callback/01KQDJTR1ZVTG8JQ220F5BNBFZ
# Stable across username renames - this is what keeps
# upstream_oauth_links rows valid after e.g. the elbojoloco rename.
sub_mode: hashed_user_id
include_claims_in_id_token: true
access_code_validity: minutes=1
access_token_validity: minutes=5
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
property_mappings:
- !Find [authentik_core.propertymapping, [managed, "goauthentik.io/providers/oauth2/scope-openid"]]
- !Find [authentik_core.propertymapping, [managed, "goauthentik.io/providers/oauth2/scope-email"]]
- !Find [authentik_core.propertymapping, [managed, "goauthentik.io/providers/oauth2/scope-profile"]]
- model: authentik_core.application
state: present
identifiers:
slug: matrix
attrs:
name: aXion1337.chat Accountverwaltung
provider: !KeyOf matrix_mas_provider
meta_description: Matrixclient tailored for aXionCommunity
meta_publisher: aXionGaming
policy_engine_mode: any
open_in_new_tab: false