Enhance Authentik configuration by introducing dedicated authentication flows for public and lab brands, including stricter password policies and MFA requirements. Update README to clarify flow distinctions and invitation enrollment processes. Improve validation in Ansible tasks to ensure all necessary blueprint variables are set, enhancing deployment robustness.

This commit is contained in:
Nikholas Pcenicni
2026-05-14 22:59:40 -04:00
parent 7b337f7128
commit 7fed8820ce
7 changed files with 435 additions and 21 deletions

View File

@@ -41,8 +41,8 @@ Network isolation is enforced at **DNS and the tunnel**, not inside Authentik. O
**Two-Brand model:**
- **Lab Brand** — domain equals **`noble_authentik_host`**: use a **restricted authentication flow** so only operator groups (defaults: **`noble-admins`**, **`authentik Admins`**) can complete sign-in on that hostname. Your bootstrap / break-glass account must remain in one of those groups (see **`noble_authentik_ensure_admin_ui_access`** and **`configure_authentik.py`** group membership).
- **Public Brand(s)** — one Brand per FQDN in **`noble_authentik_ingress_extra_hosts`**: use the stock **`default-authentication-flow`** (or replace with your own flow slug via a forked blueprint later). Assign people to **`noble_authentik_blueprint_public_groups`** and/or **`noble_authentik_blueprint_nikflix_groups`** (defaults include **`nikflix-users`** / **`nikflix-admins`** for the Nikflix hostname); **`noble-admins`** / **`noble-editors`** remain for cluster / Argo / Grafana as today.
- **Lab Brand** — domain equals **`noble_authentik_host`**: restricted authentication flow (**`noble_authentik_blueprint_lab_flow_slug`**) so only operator groups (defaults: **`noble-admins`**, **`authentik Admins`**) can continue past identification; dedicated password stage with **`noble_authentik_blueprint_lab_password_failed_attempts`**, expression-based password strength (**length / character classes / optional zxcvbn**), and MFA stage **`noble-lab-authenticator-validate-strict`** with **`noble_authentik_blueprint_lab_mfa_not_configured_action`** (**`configure`** injects default TOTP setup when no device; **`deny`** blocks; **`skip`** matches stock). WebAuthn passwordless does **not** skip MFA on this flow. Your bootstrap / break-glass account must remain in one of those groups (see **`noble_authentik_ensure_admin_ui_access`** and **`configure_authentik.py`** group membership).
- **Public Brand(s)** — one Brand per FQDN in **`noble_authentik_ingress_extra_hosts`**: authentication flow **`noble_authentik_blueprint_public_auth_flow_slug`** (default **`noble-public-authentication-flow`**) mirrors stock **`default-authentication-flow`** (optional password / MFA skip for WebAuthn passwordless) so you can tune lab vs public independently. Assign people to **`noble_authentik_blueprint_public_groups`** and/or **`noble_authentik_blueprint_nikflix_groups`** (defaults include **`nikflix-users`** / **`nikflix-admins`** for the Nikflix hostname); **`noble-admins`** / **`noble-editors`** remain for cluster / Argo / Grafana as today.
**OAuth note:** Redirect URIs and **`iss`** must stay consistent with the hostname clients use (internal issuer for in-cluster apps vs public issuer is a deliberate choice — avoid mixing both for the same app).
@@ -51,11 +51,26 @@ Network isolation is enforced at **DNS and the tunnel**, not inside Authentik. O
| Key | Purpose |
| --- | --- |
| **`10-noble-public-groups.yaml.j2`** | **`noble_authentik_blueprint_public_groups`** **`noble_authentik_blueprint_extra_directory_groups`** **`noble_authentik_blueprint_nikflix_groups`** → **Group** objects (see **Blueprint: directory groups**). |
| **`20-noble-lab-operator-authentication-flow.yaml.j2`** | Flow **`noble_authentik_blueprint_lab_flow_slug`** + expression policy **`noble_authentik_blueprint_operator_policy_name`** (allowed groups **`noble_authentik_blueprint_lab_operator_groups`**). |
| **`30-noble-brands-domain-split.yaml.j2`** | Brand for **`noble_authentik_host`** → lab flow; one Brand per **`noble_authentik_ingress_extra_hosts`** → default authentication. |
| **`20-noble-lab-operator-authentication-flow.yaml.j2`** | Flow **`noble_authentik_blueprint_lab_flow_slug`**: operator policy **`noble_authentik_blueprint_operator_policy_name`**, lab password/MFA tunables (see **`defaults/main.yml`**). |
| **`21-noble-public-authentication-flow.yaml.j2`** | Flow **`noble_authentik_blueprint_public_auth_flow_slug`** — public sign-in (same optional policies as stock default authentication). |
| **`22-noble-invitation-enrollment-flows.yaml.j2`** | Two **enrollment** flows + **Invitation** stages: public (**`noble_authentik_blueprint_public_invitation_enrollment_flow_slug`**) vs lab (**`noble_authentik_blueprint_lab_invitation_enrollment_flow_slug`**); see **Invitations** below. |
| **`30-noble-brands-domain-split.yaml.j2`** | Brand for **`noble_authentik_host`** → lab flow; one Brand per **`noble_authentik_ingress_extra_hosts`** → public flow slug above. |
Tune titles via **`noble_authentik_blueprint_lab_brand_title`** and **`noble_authentik_blueprint_public_brand_title_prefix`**. After the worker applies blueprints, confirm **System → Brands** and **Flows** in the admin UI; fix any **`!Find`** failures if upstream default stage **names** change between Authentik versions.
#### Invitations (public vs lab)
[Brands](https://docs.goauthentik.io/brands/) do **not** expose a default “enrollment” or “invitation” flow: onboarding is driven by **Directory → Invitations**, where each invitation row selects an **enrollment** flow. The link Authentik shows is:
`https://<host>/if/flow/<enrollment-flow-slug>/?itoken=<invitation-uuid>`
Use **`<host>`** that matches the experience you want:
- **Public / Nikflix** — an FQDN from **`noble_authentik_ingress_extra_hosts`**: use flow slug **`noble_authentik_blueprint_public_invitation_enrollment_flow_slug`** (default **`noble-public-invitation-enrollment`**). New users are added to **`noble_authentik_blueprint_public_invitation_user_group`** (default **`noble-public-users`**; override to **`nikflix-users`** if that is your only audience group). Tune **`noble_authentik_blueprint_public_invitation_user_type`** (**`external`** / **`internal`**) and **`noble_authentik_blueprint_public_invitation_user_path`** as needed.
- **Lab** — **`noble_authentik_host`** only when you intend to onboard someone who will later get **`noble_authentik_blueprint_lab_operator_groups`** access: use **`noble_authentik_blueprint_lab_invitation_enrollment_flow_slug`** (default **`noble-lab-invitation-enrollment`**). The blueprint creates **`noble_authentik_blueprint_lab_invitee_group_name`** (default **`noble-lab-invited`**) and assigns new enrollments there; **promote** people to **`noble-admins`** / **`authentik Admins`** (or your configured operator groups) in the admin UI when they should sign in on the lab URL.
Blueprint **22** does **not** create sample **Invitation** rows (no placeholder emails). Create invitations in the UI after blueprints apply. For richer patterns (prefilled attributes, extra policies), see [Invitations](https://docs.goauthentik.io/users-sources/user/invitations/) and the upstream example blueprint **`flows-invitation-enrollment.yaml`** ([download](https://goauthentik.io/blueprints/example/flows-invitation-enrollment.yaml)). Password strength for enrollment prompts is **not** duplicated from the lab **authentication** flow here; add **Prompt** validation policies or a dedicated policy if you need parity.
#### Blueprint: directory groups
Three inventory lists are concatenated **in this order** into **`10-noble-public-groups.yaml.j2`**:

View File

@@ -68,6 +68,37 @@ noble_authentik_blueprint_lab_operator_groups:
- authentik Admins
noble_authentik_blueprint_lab_brand_title: Noble lab (operators)
noble_authentik_blueprint_public_brand_title_prefix: Noble public
# Public hostname Brand(s) → dedicated authentication flow (**21-noble-public-…** blueprint).
noble_authentik_blueprint_public_auth_flow_slug: noble-public-authentication-flow
# Lab flow: password stage (**failed_attempts_before_cancel**) and strength checks (expression policy; skips when **password** not yet in request context).
noble_authentik_blueprint_lab_password_failed_attempts: 3
noble_authentik_blueprint_lab_password_policy_length_min: 16
noble_authentik_blueprint_lab_password_policy_amount_uppercase: 1
noble_authentik_blueprint_lab_password_policy_amount_lowercase: 1
noble_authentik_blueprint_lab_password_policy_amount_digits: 1
noble_authentik_blueprint_lab_password_policy_amount_symbols: 1
noble_authentik_blueprint_lab_password_policy_check_zxcvbn: true
noble_authentik_blueprint_lab_password_policy_zxcvbn_score_threshold: 3
noble_authentik_blueprint_lab_password_policy_error_message: >-
Lab password policy: at least 16 characters with upper, lower, digit, symbol, and sufficient strength.
# Lab MFA when user has no compatible device: **skip** (like stock), **deny** (block), **configure** (TOTP setup via default stage).
noble_authentik_blueprint_lab_mfa_not_configured_action: configure
# Invitation-based **enrollment** flows (blueprint **22**). Brands do not select enrollment; each **Invitation** picks a flow.
# Link shape: **`https://<host>/if/flow/<slug>/?itoken=<uuid>`** — use the **public** hostname for **`noble_authentik_blueprint_public_invitation_enrollment_flow_slug`** invites.
noble_authentik_blueprint_public_invitation_enrollment_flow_slug: noble-public-invitation-enrollment
noble_authentik_blueprint_lab_invitation_enrollment_flow_slug: noble-lab-invitation-enrollment
noble_authentik_blueprint_public_invitation_flow_name: Noble public invitation enrollment
noble_authentik_blueprint_public_invitation_flow_title: Complete your signup
noble_authentik_blueprint_lab_invitation_flow_name: Noble lab invitation enrollment
noble_authentik_blueprint_lab_invitation_flow_title: Lab access — complete enrollment
# **User write** for public invites: must match an existing **Group** name from **`10-noble-public-groups`** (default **`noble-public-users`**; use **`nikflix-users`** if you only maintain Nikflix groups).
noble_authentik_blueprint_public_invitation_user_group: noble-public-users
noble_authentik_blueprint_public_invitation_user_type: external
noble_authentik_blueprint_public_invitation_user_path: users/noble/public
# Lab invites: blueprint creates **`noble_authentik_blueprint_lab_invitee_group_name`**; add members to **`noble_authentik_blueprint_lab_operator_groups`** manually when they should use the lab URL.
noble_authentik_blueprint_lab_invitee_group_name: noble-lab-invited
noble_authentik_blueprint_lab_invitation_user_type: internal
noble_authentik_blueprint_lab_invitation_user_path: users/noble/lab
noble_authentik_oauth2_proxy_host: oauth2.apps.noble.lab.pcenicni.dev

View File

@@ -90,11 +90,23 @@
+ (noble_authentik_blueprint_nikflix_groups | default([])) | length) > 0
- noble_authentik_blueprint_lab_operator_groups | default([]) | length > 0
- noble_authentik_blueprint_lab_flow_slug | default('') | trim | length > 0
- noble_authentik_blueprint_public_auth_flow_slug | default('') | trim | length > 0
- (noble_authentik_blueprint_lab_mfa_not_configured_action | default('configure') | trim | lower)
in ['skip', 'deny', 'configure']
- noble_authentik_blueprint_public_invitation_enrollment_flow_slug | default('') | trim | length > 0
- noble_authentik_blueprint_lab_invitation_enrollment_flow_slug | default('') | trim | length > 0
- noble_authentik_blueprint_public_invitation_user_group | default('') | trim | length > 0
- noble_authentik_blueprint_lab_invitee_group_name | default('') | trim | length > 0
- (noble_authentik_blueprint_public_invitation_user_type | default('external') | trim | lower) in ['external', 'internal']
- (noble_authentik_blueprint_lab_invitation_user_type | default('internal') | trim | lower) in ['external', 'internal']
fail_msg: >-
When noble_authentik_blueprints_enabled is true, set at least one entry across
noble_authentik_blueprint_public_groups, noble_authentik_blueprint_extra_directory_groups,
and/or noble_authentik_blueprint_nikflix_groups,
plus noble_authentik_blueprint_lab_operator_groups (non-empty) and noble_authentik_blueprint_lab_flow_slug.
plus noble_authentik_blueprint_lab_operator_groups (non-empty), noble_authentik_blueprint_lab_flow_slug,
noble_authentik_blueprint_public_auth_flow_slug, noble_authentik_blueprint_lab_mfa_not_configured_action
(skip, deny, or configure), invitation enrollment flow slugs, noble_authentik_blueprint_public_invitation_user_group,
noble_authentik_blueprint_lab_invitee_group_name, and invitation user_type values (external or internal).
See ansible/roles/noble_authentik/defaults/main.yml and README.
when: noble_authentik_blueprints_enabled | default(false) | bool
@@ -118,6 +130,8 @@
loop:
- 10-noble-public-groups.yaml
- 20-noble-lab-operator-authentication-flow.yaml
- 21-noble-public-authentication-flow.yaml
- 22-noble-invitation-enrollment-flows.yaml
- 30-noble-brands-domain-split.yaml
when: noble_authentik_blueprints_enabled | default(false) | bool

View File

@@ -1,5 +1,4 @@
# Noble — authentication flow for the **lab** hostname Brand: only members of operator groups may continue.
# Reuses default identification / password / MFA / login stages; adds a policy on the password stage binding.
# Noble — **lab** hostname authentication: operator-only, stricter password checks, MFA required (no WebAuthn-PWL skip).
version: 1
metadata:
name: noble-lab-operator-authentication
@@ -11,6 +10,28 @@ entries:
identifiers:
name: Default - Password change flow
required: false
- model: authentik_stages_password.passwordstage
id: noble-lab-password-stage
identifiers:
name: noble-lab-authentication-password
attrs:
backends:
- authentik.core.auth.InbuiltBackend
- authentik.sources.kerberos.auth.KerberosBackend
- authentik.sources.ldap.auth.LDAPBackend
- authentik.core.auth.TokenBackend
configure_flow: !Find [authentik_flows.flow, [slug, default-password-change]]
failed_attempts_before_cancel: {{ noble_authentik_blueprint_lab_password_failed_attempts | int }}
- model: authentik_stages_authenticator_validate.authenticatorvalidatestage
id: noble-lab-authenticator-validate-strict
identifiers:
name: noble-lab-authenticator-validate-strict
attrs:
not_configured_action: {{ noble_authentik_blueprint_lab_mfa_not_configured_action | trim | lower | to_json }}
{% if noble_authentik_blueprint_lab_mfa_not_configured_action | trim | lower == 'configure' %}
configuration_stages:
- !Find [authentik_stages_authenticator_totp.authenticatortotpstage, [name, default-authenticator-totp-setup]]
{% endif %}
- model: authentik_flows.flow
id: flow
identifiers:
@@ -30,7 +51,7 @@ entries:
model: authentik_flows.flowstagebinding
identifiers:
order: 20
stage: !Find [authentik_stages_password.passwordstage, [name, default-authentication-password]]
stage: !KeyOf noble-lab-password-stage
target: !KeyOf flow
attrs:
re_evaluate_policies: true
@@ -38,7 +59,7 @@ entries:
model: authentik_flows.flowstagebinding
identifiers:
order: 30
stage: !Find [authentik_stages_authenticator_validate.authenticatorvalidatestage, [name, default-authentication-mfa-validation]]
stage: !KeyOf noble-lab-authenticator-validate-strict
target: !KeyOf flow
- model: authentik_flows.flowstagebinding
identifiers:
@@ -56,15 +77,43 @@ entries:
return True
return not hasattr(flow_plan.context.get("pending_user"), "backend")
- model: authentik_policies_expression.expressionpolicy
id: noble-lab-authenticator-validate-optional
id: noble-lab-password-strength
identifiers:
name: noble-lab-authenticator-validate-optional
name: noble-lab-password-strength
attrs:
expression: |
flow_plan = request.context.get("flow_plan")
if not flow_plan:
import re
_zxc = {{ noble_authentik_blueprint_lab_password_policy_check_zxcvbn | bool }}
_zxc_thr = {{ noble_authentik_blueprint_lab_password_policy_zxcvbn_score_threshold | int }}
pwd = request.context.get("password")
if not pwd:
return True
msg = {{ noble_authentik_blueprint_lab_password_policy_error_message | trim | to_json }}
if len(pwd) < {{ noble_authentik_blueprint_lab_password_policy_length_min | int }}:
ak_message(msg)
return False
if len(re.findall(r"[A-Z]", pwd)) < {{ noble_authentik_blueprint_lab_password_policy_amount_uppercase | int }}:
ak_message(msg)
return False
if len(re.findall(r"[a-z]", pwd)) < {{ noble_authentik_blueprint_lab_password_policy_amount_lowercase | int }}:
ak_message(msg)
return False
if len(re.findall(r"[0-9]", pwd)) < {{ noble_authentik_blueprint_lab_password_policy_amount_digits | int }}:
ak_message(msg)
return False
sym = sum(1 for c in pwd if (not c.isalnum()) and (not c.isspace()))
if sym < {{ noble_authentik_blueprint_lab_password_policy_amount_symbols | int }}:
ak_message(msg)
return False
if _zxc:
try:
from zxcvbn import zxcvbn
if zxcvbn(pwd[:72])["score"] <= _zxc_thr:
ak_message("Password is too weak for the lab policy.")
return False
except Exception:
pass
return True
return not (flow_plan.context.get("auth_method") == "auth_webauthn_pwl")
- model: authentik_policies_expression.expressionpolicy
id: noble-lab-operators-only
identifiers:
@@ -94,8 +143,6 @@ entries:
failure_result: true
- model: authentik_policies.policybinding
identifiers:
order: 10
target: !KeyOf noble-lab-authenticator-binding
policy: !KeyOf noble-lab-authenticator-validate-optional
attrs:
failure_result: true
order: 15
target: !KeyOf noble-lab-password-binding
policy: !KeyOf noble-lab-password-strength

View File

@@ -0,0 +1,80 @@
# Noble — **public** hostname(s): same behaviour as stock **default-authentication-flow** (optional password / MFA skip for WebAuthn PWL), isolated slug for Brand binding.
version: 1
metadata:
name: noble-public-authentication-flow
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
- model: authentik_blueprints.metaapplyblueprint
attrs:
identifiers:
name: Default - Password change flow
required: false
- model: authentik_flows.flow
id: flow
identifiers:
slug: {{ noble_authentik_blueprint_public_auth_flow_slug | trim | to_json }}
attrs:
name: Noble public sign-in
title: Sign in
designation: authentication
authentication: none
- id: noble-public-identification-binding
model: authentik_flows.flowstagebinding
identifiers:
order: 10
stage: !Find [authentik_stages_identification.identificationstage, [name, default-authentication-identification]]
target: !KeyOf flow
- id: noble-public-password-binding
model: authentik_flows.flowstagebinding
identifiers:
order: 20
stage: !Find [authentik_stages_password.passwordstage, [name, default-authentication-password]]
target: !KeyOf flow
attrs:
re_evaluate_policies: true
- id: noble-public-authenticator-binding
model: authentik_flows.flowstagebinding
identifiers:
order: 30
stage: !Find [authentik_stages_authenticator_validate.authenticatorvalidatestage, [name, default-authentication-mfa-validation]]
target: !KeyOf flow
- model: authentik_flows.flowstagebinding
identifiers:
order: 100
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-authentication-login]]
target: !KeyOf flow
- model: authentik_policies_expression.expressionpolicy
id: noble-public-password-optional
identifiers:
name: noble-public-password-optional
attrs:
expression: |
flow_plan = request.context.get("flow_plan")
if not flow_plan:
return True
return not hasattr(flow_plan.context.get("pending_user"), "backend")
- model: authentik_policies_expression.expressionpolicy
id: noble-public-authenticator-validate-optional
identifiers:
name: noble-public-authenticator-validate-optional
attrs:
expression: |
flow_plan = request.context.get("flow_plan")
if not flow_plan:
return True
return not (flow_plan.context.get("auth_method") == "auth_webauthn_pwl")
- model: authentik_policies.policybinding
identifiers:
order: 10
target: !KeyOf noble-public-password-binding
policy: !KeyOf noble-public-password-optional
attrs:
failure_result: true
- model: authentik_policies.policybinding
identifiers:
order: 10
target: !KeyOf noble-public-authenticator-binding
policy: !KeyOf noble-public-authenticator-validate-optional
attrs:
failure_result: true

View File

@@ -0,0 +1,227 @@
# Noble — two **enrollment** flows (public vs lab) with separate **Invitation** stages (invitation token required).
# Create rows under **Directory → Invitations** in the admin UI and pick the matching flow; share links with the
# correct **Host** so the right Brand applies. Does **not** ship example **Invitation** objects (no prefilled emails).
version: 1
metadata:
name: noble-invitation-enrollment-flows
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
- model: authentik_core.group
id: noble-lab-invited-group
identifiers:
name: {{ noble_authentik_blueprint_lab_invitee_group_name | trim | to_json }}
attrs:
is_superuser: false
attributes:
"noble.ak/audience": lab
"noble.ak/role": lab-invited
- model: authentik_flows.flow
id: noble-inv-flow-public
identifiers:
slug: {{ noble_authentik_blueprint_public_invitation_enrollment_flow_slug | trim | to_json }}
attrs:
name: {{ noble_authentik_blueprint_public_invitation_flow_name | trim | to_json }}
title: {{ noble_authentik_blueprint_public_invitation_flow_title | trim | to_json }}
designation: enrollment
authentication: require_unauthenticated
- model: authentik_flows.flow
id: noble-inv-flow-lab
identifiers:
slug: {{ noble_authentik_blueprint_lab_invitation_enrollment_flow_slug | trim | to_json }}
attrs:
name: {{ noble_authentik_blueprint_lab_invitation_flow_name | trim | to_json }}
title: {{ noble_authentik_blueprint_lab_invitation_flow_title | trim | to_json }}
designation: enrollment
authentication: require_unauthenticated
- model: authentik_stages_invitation.invitationstage
id: noble-inv-stage-public
identifiers:
name: noble-invitation-enrollment-invitation-public
attrs:
continue_flow_without_invitation: false
- model: authentik_stages_invitation.invitationstage
id: noble-inv-stage-lab
identifiers:
name: noble-invitation-enrollment-invitation-lab
attrs:
continue_flow_without_invitation: false
- id: noble-inv-prompt-field-username
model: authentik_stages_prompt.prompt
identifiers:
name: noble-inv-enroll-field-username
attrs:
field_key: username
label: Username
type: username
required: true
placeholder: Username
placeholder_expression: false
order: 0
- id: noble-inv-prompt-field-password
model: authentik_stages_prompt.prompt
identifiers:
name: noble-inv-enroll-field-password
attrs:
field_key: password
label: Password
type: password
required: true
placeholder: Password
placeholder_expression: false
order: 1
- id: noble-inv-prompt-field-password-repeat
model: authentik_stages_prompt.prompt
identifiers:
name: noble-inv-enroll-field-password-repeat
attrs:
field_key: password_repeat
label: Password (repeat)
type: password
required: true
placeholder: Password (repeat)
placeholder_expression: false
order: 2
- id: noble-inv-prompt-field-name
model: authentik_stages_prompt.prompt
identifiers:
name: noble-inv-enroll-field-name
attrs:
field_key: name
label: Name
type: text
required: true
placeholder: Name
placeholder_expression: false
order: 0
- id: noble-inv-prompt-field-email
model: authentik_stages_prompt.prompt
identifiers:
name: noble-inv-enroll-field-email
attrs:
field_key: email
label: Email
type: email
required: true
placeholder: Email
placeholder_expression: false
order: 1
- id: noble-inv-prompt-stage-credentials
model: authentik_stages_prompt.promptstage
identifiers:
name: noble-inv-enroll-prompt-credentials
attrs:
fields:
- !KeyOf noble-inv-prompt-field-username
- !KeyOf noble-inv-prompt-field-password
- !KeyOf noble-inv-prompt-field-password-repeat
- id: noble-inv-prompt-stage-details
model: authentik_stages_prompt.promptstage
identifiers:
name: noble-inv-enroll-prompt-details
attrs:
fields:
- !KeyOf noble-inv-prompt-field-name
- !KeyOf noble-inv-prompt-field-email
- id: noble-inv-user-write-public
model: authentik_stages_user_write.userwritestage
identifiers:
name: noble-inv-enroll-user-write-public
attrs:
user_creation_mode: always_create
user_type: {{ noble_authentik_blueprint_public_invitation_user_type | trim | lower | to_json }}
user_path_template: {{ noble_authentik_blueprint_public_invitation_user_path | trim | to_json }}
create_users_group: !Find [authentik_core.group, [name, {{ noble_authentik_blueprint_public_invitation_user_group | trim | to_json }}]]
- id: noble-inv-user-write-lab
model: authentik_stages_user_write.userwritestage
identifiers:
name: noble-inv-enroll-user-write-lab
attrs:
user_creation_mode: always_create
user_type: {{ noble_authentik_blueprint_lab_invitation_user_type | trim | lower | to_json }}
user_path_template: {{ noble_authentik_blueprint_lab_invitation_user_path | trim | to_json }}
create_users_group: !KeyOf noble-lab-invited-group
- id: noble-inv-user-login
model: authentik_stages_user_login.userloginstage
identifiers:
name: noble-inv-enroll-user-login
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-public
stage: !KeyOf noble-inv-stage-public
order: 5
attrs:
evaluate_on_plan: true
re_evaluate_policies: true
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-public
stage: !KeyOf noble-inv-prompt-stage-credentials
order: 10
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-public
stage: !KeyOf noble-inv-prompt-stage-details
order: 15
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-public
stage: !KeyOf noble-inv-user-write-public
order: 20
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-public
stage: !KeyOf noble-inv-user-login
order: 100
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-lab
stage: !KeyOf noble-inv-stage-lab
order: 5
attrs:
evaluate_on_plan: true
re_evaluate_policies: true
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-lab
stage: !KeyOf noble-inv-prompt-stage-credentials
order: 10
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-lab
stage: !KeyOf noble-inv-prompt-stage-details
order: 15
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-lab
stage: !KeyOf noble-inv-user-write-lab
order: 20
- model: authentik_flows.flowstagebinding
identifiers:
target: !KeyOf noble-inv-flow-lab
stage: !KeyOf noble-inv-user-login
order: 100

View File

@@ -1,4 +1,4 @@
# Noble — Brands so **Host** selects authentication flow: lab hostname → operator-only flow; extra hosts → default login.
# Noble — Brands so **Host** selects authentication flow: lab hostname → operator-only hardened flow; extra hosts → public flow (**21**).
version: 1
metadata:
name: noble-brands-domain-split
@@ -21,7 +21,7 @@ entries:
attrs:
default: false
title: {{ ((noble_authentik_blueprint_public_brand_title_prefix | default('Noble public')) ~ ' (' ~ (host | trim) ~ ')') | to_json }}
flow_authentication: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
flow_authentication: !Find [authentik_flows.flow, [slug, {{ noble_authentik_blueprint_public_auth_flow_slug | trim | to_json }}]]
flow_invalidation: !Find [authentik_flows.flow, [slug, default-invalidation-flow]]
flow_user_settings: !Find [authentik_flows.flow, [slug, default-user-settings-flow]]
{% endfor %}