--- apiVersion: v1 kind: ConfigMap metadata: name: authentik-blueprints namespace: authentik data: common.yaml: | version: 1 metadata: name: BlumeOps Common Identity labels: blueprints.goauthentik.io/description: "Shared groups and identity resources" entries: # admins group — gates access to admin-only applications - model: authentik_core.group id: admins-group identifiers: name: admins attrs: name: admins mfa.yaml: | version: 1 metadata: name: BlumeOps MFA Enforcement labels: blueprints.goauthentik.io/description: "Require MFA on default authentication flow" entries: # Require MFA — force_setup prompts users without MFA to enroll. - model: authentik_stages_authenticator_validate.authenticatorvalidatestage identifiers: name: default-authentication-mfa-validation attrs: not_configured_action: configure device_classes: - totp - webauthn - static configuration_stages: - !Find [authentik_stages_authenticator_totp.authenticatortotpstage, [name, default-authenticator-totp-setup]] - !Find [authentik_stages_authenticator_static.authenticatorstaticstage, [name, default-authenticator-static-setup]] grafana.yaml: | version: 1 metadata: name: BlumeOps Grafana SSO labels: blueprints.goauthentik.io/description: "Grafana OIDC provider and application" entries: # OAuth2 provider for Grafana - model: authentik_providers_oauth2.oauth2provider id: grafana-provider identifiers: name: Grafana attrs: name: Grafana authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: confidential client_id: grafana client_secret: !Env AUTHENTIK_GRAFANA_CLIENT_SECRET redirect_uris: - matching_mode: strict url: https://grafana.ops.eblu.me/login/generic_oauth - matching_mode: strict url: https://grafana.tail8d86e.ts.net/login/generic_oauth signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Grafana application — linked to the OAuth2 provider - model: authentik_core.application id: grafana-app identifiers: slug: grafana attrs: name: Grafana slug: grafana provider: !KeyOf grafana-provider meta_launch_url: https://grafana.ops.eblu.me policy_engine_mode: any # Policy binding — restrict Grafana to admins group - model: authentik_policies.policybinding identifiers: order: 0 target: !KeyOf grafana-app group: !Find [authentik_core.group, [name, admins]] attrs: target: !KeyOf grafana-app group: !Find [authentik_core.group, [name, admins]] order: 0 enabled: true negate: false timeout: 30 forgejo.yaml: | version: 1 metadata: name: BlumeOps Forgejo SSO labels: blueprints.goauthentik.io/description: "Forgejo OIDC provider and application" entries: # OAuth2 provider for Forgejo - model: authentik_providers_oauth2.oauth2provider id: forgejo-provider identifiers: name: Forgejo attrs: name: Forgejo authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: confidential client_id: forgejo client_secret: !Env AUTHENTIK_FORGEJO_CLIENT_SECRET redirect_uris: - matching_mode: strict url: https://forge.eblu.me/user/oauth2/authentik/callback signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Forgejo application — linked to the OAuth2 provider - model: authentik_core.application id: forgejo-app identifiers: slug: forgejo attrs: name: Forgejo slug: forgejo provider: !KeyOf forgejo-provider meta_launch_url: https://forge.eblu.me policy_engine_mode: any # Policy binding — restrict Forgejo to admins group - model: authentik_policies.policybinding identifiers: order: 0 target: !KeyOf forgejo-app group: !Find [authentik_core.group, [name, admins]] attrs: target: !KeyOf forgejo-app group: !Find [authentik_core.group, [name, admins]] order: 0 enabled: true negate: false timeout: 30 zot.yaml: | version: 1 metadata: name: BlumeOps Zot SSO labels: blueprints.goauthentik.io/description: "Zot OIDC provider, application, and CI identity" entries: # artifact-workloads group (CI push identity) - model: authentik_core.group id: artifact-workloads-group identifiers: name: artifact-workloads attrs: name: artifact-workloads # Service account for CI push (admin sets password via UI after deploy) - model: authentik_core.user id: zot-ci-user identifiers: username: zot-ci attrs: username: zot-ci name: Zot CI Service Account type: service_account is_active: true groups: - !KeyOf artifact-workloads-group # OAuth2 provider for Zot - model: authentik_providers_oauth2.oauth2provider id: zot-provider identifiers: name: Zot attrs: name: Zot authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: confidential client_id: zot client_secret: !Env AUTHENTIK_ZOT_CLIENT_SECRET redirect_uris: - matching_mode: strict url: https://registry.ops.eblu.me/zot/auth/callback/oidc signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Zot application — linked to the OAuth2 provider - model: authentik_core.application id: zot-app identifiers: slug: zot attrs: name: Zot Registry slug: zot provider: !KeyOf zot-provider meta_launch_url: https://registry.ops.eblu.me policy_engine_mode: any # Policy binding — allow admins group access to Zot - model: authentik_policies.policybinding identifiers: order: 0 target: !KeyOf zot-app group: !Find [authentik_core.group, [name, admins]] attrs: target: !KeyOf zot-app group: !Find [authentik_core.group, [name, admins]] order: 0 enabled: true negate: false timeout: 30 # Policy binding — allow artifact-workloads group access to Zot (CI push) - model: authentik_policies.policybinding identifiers: order: 1 target: !KeyOf zot-app group: !KeyOf artifact-workloads-group attrs: target: !KeyOf zot-app group: !KeyOf artifact-workloads-group order: 1 enabled: true negate: false timeout: 30 argocd.yaml: | version: 1 metadata: name: BlumeOps ArgoCD SSO labels: blueprints.goauthentik.io/description: "ArgoCD OIDC provider and application" entries: # OAuth2 provider for ArgoCD - model: authentik_providers_oauth2.oauth2provider id: argocd-provider identifiers: name: ArgoCD attrs: name: ArgoCD authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: public client_id: argocd redirect_uris: - matching_mode: strict url: https://argocd.ops.eblu.me/auth/callback - matching_mode: strict url: https://argocd.tail8d86e.ts.net/auth/callback - matching_mode: strict url: http://localhost:8085/auth/callback signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # ArgoCD application — linked to the OAuth2 provider - model: authentik_core.application id: argocd-app identifiers: slug: argocd attrs: name: ArgoCD slug: argocd provider: !KeyOf argocd-provider meta_launch_url: https://argocd.ops.eblu.me policy_engine_mode: any # Policy binding — restrict ArgoCD to admins group - model: authentik_policies.policybinding identifiers: order: 0 target: !KeyOf argocd-app group: !Find [authentik_core.group, [name, admins]] attrs: target: !KeyOf argocd-app group: !Find [authentik_core.group, [name, admins]] order: 0 enabled: true negate: false timeout: 30 jellyfin.yaml: | version: 1 metadata: name: BlumeOps Jellyfin SSO labels: blueprints.goauthentik.io/description: "Jellyfin OIDC provider and application" entries: # OAuth2 provider for Jellyfin - model: authentik_providers_oauth2.oauth2provider id: jellyfin-provider identifiers: name: Jellyfin attrs: name: Jellyfin authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: confidential client_id: jellyfin client_secret: !Env AUTHENTIK_JELLYFIN_CLIENT_SECRET redirect_uris: - matching_mode: strict url: https://jellyfin.ops.eblu.me/sso/OID/redirect/authentik signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Jellyfin application — all authenticated users allowed (no policy binding) - model: authentik_core.application id: jellyfin-app identifiers: slug: jellyfin attrs: name: Jellyfin slug: jellyfin provider: !KeyOf jellyfin-provider meta_launch_url: https://jellyfin.ops.eblu.me policy_engine_mode: all paperless.yaml: | version: 1 metadata: name: BlumeOps Paperless SSO labels: blueprints.goauthentik.io/description: "Paperless-ngx OIDC provider and application" entries: # OAuth2 provider for Paperless-ngx (confidential client) - model: authentik_providers_oauth2.oauth2provider id: paperless-provider identifiers: name: Paperless attrs: name: Paperless authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: confidential client_id: paperless client_secret: !Env AUTHENTIK_PAPERLESS_CLIENT_SECRET redirect_uris: - matching_mode: strict url: https://paperless.ops.eblu.me/accounts/oidc/authentik/login/callback/ - matching_mode: strict url: https://paperless.tail8d86e.ts.net/accounts/oidc/authentik/login/callback/ signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Paperless application — all authenticated users allowed - model: authentik_core.application id: paperless-app identifiers: slug: paperless attrs: name: Paperless slug: paperless provider: !KeyOf paperless-provider meta_launch_url: https://paperless.ops.eblu.me policy_engine_mode: all mealie.yaml: | version: 1 metadata: name: BlumeOps Mealie SSO labels: blueprints.goauthentik.io/description: "Mealie OIDC provider and application" entries: # OAuth2 provider for Mealie (confidential — Mealie requires client_secret) - model: authentik_providers_oauth2.oauth2provider id: mealie-provider identifiers: name: Mealie attrs: name: Mealie authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: confidential client_id: mealie client_secret: !Env AUTHENTIK_MEALIE_CLIENT_SECRET redirect_uris: - matching_mode: strict url: https://meals.ops.eblu.me/login - matching_mode: strict url: https://meals.tail8d86e.ts.net/login signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Mealie application — all authenticated users allowed (admin mapped via OIDC_ADMIN_GROUP) - model: authentik_core.application id: mealie-app identifiers: slug: mealie attrs: name: Mealie slug: mealie provider: !KeyOf mealie-provider meta_launch_url: https://meals.ops.eblu.me policy_engine_mode: all heph.yaml: | version: 1 metadata: name: BlumeOps Heph SSO labels: blueprints.goauthentik.io/description: "Hephaestus hub OIDC (device-code) provider, application, and device-code flow" entries: # Device-code flow (RFC 8628). authentik ships no default for this, so we # create one and bind it to the brand below. An empty stage_configuration # flow is sufficient: the already-authenticated user just confirms the code. - model: authentik_flows.flow id: device-code-flow identifiers: slug: default-device-code-flow attrs: name: Device code flow title: Device code flow slug: default-device-code-flow designation: stage_configuration authentication: require_authenticated # Enable the device-code grant globally by binding the flow to the default # brand (domain authentik-default). Partial update — only sets this field. - model: authentik_brands.brand identifiers: domain: authentik-default attrs: flow_device_code: !KeyOf device-code-flow # OAuth2 provider for heph — PUBLIC client (device-code + PKCE, no secret). # client_id doubles as the token audience the hub verifies (--oidc-audience heph), # and the app slug 'heph' is the issuer path (/application/o/heph/). - model: authentik_providers_oauth2.oauth2provider id: heph-provider identifiers: name: Heph attrs: name: Heph authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: public client_id: heph # CLI/TUI use the device-code grant (no redirect). The heph-pwa browser # login uses Authorization Code + PKCE, which DOES redirect back to the # app's origin — register those here (Authentik also keys token-endpoint # CORS off these origins). Trailing slash matters: the PWA's redirect_uri # is its base dir, e.g. https://heph.ops.eblu.me/. redirect_uris: - matching_mode: strict url: https://heph.ops.eblu.me/ - matching_mode: strict url: http://localhost:8787/ # local dev (hephd --web-root) signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] sub_mode: hashed_user_id include_claims_in_id_token: true # Heph application — linked to the OAuth2 provider - model: authentik_core.application id: heph-app identifiers: slug: heph attrs: name: Hephaestus slug: heph provider: !KeyOf heph-provider meta_launch_url: https://heph.ops.eblu.me policy_engine_mode: any # Policy binding — restrict heph to admins group (single-owner, sensitive data) - model: authentik_policies.policybinding identifiers: order: 0 target: !KeyOf heph-app group: !Find [authentik_core.group, [name, admins]] attrs: target: !KeyOf heph-app group: !Find [authentik_core.group, [name, admins]] order: 0 enabled: true negate: false timeout: 30