authentik: Passkey-only Login für Home Assistant und NetBird #115
@@ -612,3 +612,178 @@ data:
|
||||
identifiers:
|
||||
name: Caddy docs.renner.uno
|
||||
state: absent
|
||||
|
||||
# Passkey-only (WebAuthn) login for selected apps, in two parts:
|
||||
#
|
||||
# 1. A passwordless AUTHENTICATION flow (username → passkey, no
|
||||
# password prompt) bound per-provider, so fresh logins to these
|
||||
# apps never see a password field. auth.renner.uno's own login
|
||||
# (default brand flow) is untouched.
|
||||
# 2. A step-up AUTHORIZATION flow — unlike the authentication flow,
|
||||
# this runs on EVERY interactive authorize, so an existing
|
||||
# password-only SSO session from another app cannot slip into
|
||||
# these apps without presenting a passkey.
|
||||
passkey-stepup.yaml: |
|
||||
version: 1
|
||||
metadata:
|
||||
name: Passkey step-up authorization (homelab)
|
||||
entries:
|
||||
- id: passkey-stepup-flow
|
||||
model: authentik_flows.flow
|
||||
identifiers:
|
||||
slug: passkey-stepup-authorization
|
||||
state: present
|
||||
attrs:
|
||||
name: Passkey step-up authorization
|
||||
title: "Redirecting to %(app)s"
|
||||
designation: authorization
|
||||
# Unauthenticated users are bounced through the default
|
||||
# authentication flow first, then land back here for the
|
||||
# WebAuthn validation — same as the built-in implicit-consent
|
||||
# flow this replaces.
|
||||
authentication: require_authenticated
|
||||
|
||||
- id: passkey-stepup-webauthn-validation
|
||||
model: authentik_stages_authenticator_validate.authenticatorvalidatestage
|
||||
identifiers:
|
||||
name: passkey-stepup-webauthn-validation
|
||||
state: present
|
||||
attrs:
|
||||
device_classes:
|
||||
- webauthn
|
||||
# `configure`, not `deny`: g.renner has Home Assistant access
|
||||
# but no enrolled WebAuthn device (live check 2026-07-07), so
|
||||
# a hard deny would lock her out with no self-service path.
|
||||
# `configure` injects the default WebAuthn enrollment stage
|
||||
# inline — first login without a passkey becomes "enroll one
|
||||
# now, then validate it". Still passkey-only: there is no way
|
||||
# through this stage without a WebAuthn credential.
|
||||
not_configured_action: configure
|
||||
configuration_stages:
|
||||
- !Find [authentik_stages_authenticator_webauthn.authenticatorwebauthnstage, [name, default-authenticator-webauthn-setup]]
|
||||
# Skip re-validation if a passkey was already presented within
|
||||
# the window. Non-zero for two reasons: (1) no double-touch
|
||||
# when the login itself used a passkey seconds earlier;
|
||||
# (2) NetBird's dashboard silently re-authorizes via
|
||||
# /silent-auth (prompt=none) on token expiry — a flow that
|
||||
# always demands interaction would fail those and force a
|
||||
# visible re-login every access-token lifetime.
|
||||
last_auth_threshold: hours=8
|
||||
webauthn_user_verification: preferred
|
||||
|
||||
- model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
target: !KeyOf passkey-stepup-flow
|
||||
stage: !KeyOf passkey-stepup-webauthn-validation
|
||||
order: 10
|
||||
state: present
|
||||
|
||||
# Passwordless authentication flow: identification (username or
|
||||
# email, NO password stage) → WebAuthn validation → login.
|
||||
- id: passkey-passwordless-flow
|
||||
model: authentik_flows.flow
|
||||
identifiers:
|
||||
slug: passkey-passwordless-authentication
|
||||
state: present
|
||||
attrs:
|
||||
name: Passkey passwordless authentication
|
||||
title: "Sign in with your passkey"
|
||||
designation: authentication
|
||||
|
||||
- id: passkey-passwordless-identification
|
||||
model: authentik_stages_identification.identificationstage
|
||||
identifiers:
|
||||
name: passkey-passwordless-identification
|
||||
state: present
|
||||
attrs:
|
||||
user_fields:
|
||||
- username
|
||||
- email
|
||||
|
||||
# SEPARATE stage from the step-up one, and deliberately `deny`:
|
||||
# at this point in an authentication flow the user has only been
|
||||
# *identified* (typed a username), not authenticated — `configure`
|
||||
# here would let anyone who knows a passkey-less username enroll
|
||||
# their own passkey and take over that account. Inline enrollment
|
||||
# for passkey-less users happens exclusively in the authorization
|
||||
# step-up stage above, where require_authenticated guarantees a
|
||||
# fully authenticated session. A passkey-less user therefore
|
||||
# bootstraps via password login on auth.renner.uno, then gets the
|
||||
# enrollment prompt on first app access.
|
||||
- id: passkey-passwordless-webauthn-validation
|
||||
model: authentik_stages_authenticator_validate.authenticatorvalidatestage
|
||||
identifiers:
|
||||
name: passkey-passwordless-webauthn-validation
|
||||
state: present
|
||||
attrs:
|
||||
device_classes:
|
||||
- webauthn
|
||||
not_configured_action: deny
|
||||
last_auth_threshold: seconds=0
|
||||
webauthn_user_verification: preferred
|
||||
|
||||
- model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
target: !KeyOf passkey-passwordless-flow
|
||||
stage: !KeyOf passkey-passwordless-identification
|
||||
order: 10
|
||||
state: present
|
||||
|
||||
- model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
target: !KeyOf passkey-passwordless-flow
|
||||
stage: !KeyOf passkey-passwordless-webauthn-validation
|
||||
order: 20
|
||||
state: present
|
||||
|
||||
- model: authentik_flows.flowstagebinding
|
||||
identifiers:
|
||||
target: !KeyOf passkey-passwordless-flow
|
||||
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-authentication-login]]
|
||||
order: 30
|
||||
state: present
|
||||
|
||||
# Re-point the (previously UI-managed) OAuth2 providers: fresh
|
||||
# logins use the passwordless flow, every authorize passes the
|
||||
# step-up flow. Blueprint apply validates the full serializer, so
|
||||
# the required fields (invalidation_flow, redirect_uris) mirror
|
||||
# the live values as of 2026-07-07 — git owns them from here on;
|
||||
# UI edits to these fields will be reverted on the next apply
|
||||
# cycle.
|
||||
- model: authentik_providers_oauth2.oauth2provider
|
||||
identifiers:
|
||||
name: Homeassistant
|
||||
state: present
|
||||
attrs:
|
||||
authentication_flow: !KeyOf passkey-passwordless-flow
|
||||
authorization_flow: !KeyOf passkey-stepup-flow
|
||||
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
|
||||
client_type: confidential
|
||||
redirect_uris:
|
||||
- url: https://home.renner.uno/auth/openid/callback
|
||||
matching_mode: strict
|
||||
- url: http://homeassistant.srv.renner.uno:8123/auth/openid/callback
|
||||
matching_mode: strict
|
||||
|
||||
- model: authentik_providers_oauth2.oauth2provider
|
||||
identifiers:
|
||||
name: Provider for Netbird
|
||||
state: present
|
||||
attrs:
|
||||
authentication_flow: !KeyOf passkey-passwordless-flow
|
||||
authorization_flow: !KeyOf passkey-stepup-flow
|
||||
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
|
||||
client_type: public
|
||||
redirect_uris:
|
||||
- url: http://localhost:53000
|
||||
matching_mode: strict
|
||||
- url: https://netbird.renner.uno/
|
||||
matching_mode: strict
|
||||
- url: https://netbird.renner.uno/auth
|
||||
matching_mode: strict
|
||||
- url: https://netbird.renner.uno/silent-auth
|
||||
matching_mode: strict
|
||||
- url: https://netbird.renner.uno/peers
|
||||
matching_mode: strict
|
||||
- url: 'https://netbird\.renner\.uno(/.*)?'
|
||||
matching_mode: regex
|
||||
|
||||
@@ -160,10 +160,10 @@ spec:
|
||||
redis:
|
||||
enabled: false
|
||||
|
||||
# Mount the K8s-outpost-integration blueprint so the worker re-points
|
||||
# every Outpost at the in-cluster Kubernetes service connection on
|
||||
# boot and drops the legacy Docker connection inherited from the
|
||||
# Proxmox deployment. See blueprints-configmap.yaml.
|
||||
# Mount the homelab blueprints (K8s outpost integration, passkey
|
||||
# step-up authorization) — every key of the ConfigMap is applied by
|
||||
# the worker on boot and on each apply cycle. See
|
||||
# blueprints-configmap.yaml.
|
||||
blueprints:
|
||||
configMaps:
|
||||
- authentik-blueprints-k8s-outposts
|
||||
|
||||
Reference in New Issue
Block a user