Initial commit

This commit is contained in:
Scooby Husky
2026-03-09 20:21:35 -05:00
commit aacb8eebbe
314 changed files with 21766 additions and 0 deletions
@@ -0,0 +1,49 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-argocd
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
argocd.yaml: |-
version: 1
metadata:
name: argocd-oidc
entries:
- model: authentik_providers_oauth2.oauth2provider
id: argocd-provider
state: present
identifiers:
name: ArgoCD
attrs:
name: ArgoCD
client_id: 3791058a7de278045e5ec36be29f7a33d635119b8c786f20c86b185139c28841
client_secret: f787416822f5bf4c46fe9170e63d1bf9520bab7703d53341aaaec107c8c4ba253d96c30b70d23a1c0b5a401ae1ae4bfb5db06092d338e29e0b0f04cd29bc0b36
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://argocd.kube.huskypup.net/auth/callback"
matching_mode: strict
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Internal JWT Certificate"]]
- model: authentik_core.application
id: argocd-application
state: present
identifiers:
slug: argocd
attrs:
name: ArgoCD
slug: argocd
policy_engine_mode: any
provider: !KeyOf argocd-provider
@@ -0,0 +1,63 @@
---
# Ceph Dashboard SAML2 Provider Blueprint for Authentik
# Creates a SAML2 provider for Ceph Dashboard native SSO
# Ceph expects:
# - Audience: https://ceph.kube.huskypup.net/auth/saml2/metadata
# - ACS URL: https://ceph.kube.huskypup.net/auth/saml2
# - Username attribute: "username"
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-ceph
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
ceph.yaml: |-
version: 1
metadata:
name: ceph-dashboard-saml
entries:
# SAML Property Mapping for username attribute (required by Ceph)
- model: authentik_providers_saml.samlpropertymapping
id: ceph-username-mapping
state: present
identifiers:
managed: goauthentik.io/providers/saml/ceph-username
attrs:
name: "Ceph Dashboard SAML: Username"
saml_name: "username"
expression: "return request.user.username"
# SAML2 Provider for Ceph Dashboard
- model: authentik_providers_saml.samlprovider
id: ceph-dashboard-saml-provider
state: present
identifiers:
name: ceph-dashboard-saml
attrs:
name: ceph-dashboard-saml
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
acs_url: "https://ceph.kube.huskypup.net/auth/saml2"
audience: "https://ceph.kube.huskypup.net/auth/saml2/metadata"
sp_binding: post
default_name_id_policy: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
signing_kp: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
sign_response: true
sign_assertion: true
property_mappings:
- !KeyOf ceph-username-mapping
# Application entry
- model: authentik_core.application
id: ceph-dashboard-application
state: present
identifiers:
slug: ceph-dashboard
attrs:
name: Ceph Dashboard
slug: ceph-dashboard
policy_engine_mode: any
provider: !KeyOf ceph-dashboard-saml-provider
meta_launch_url: "https://ceph.kube.huskypup.net"
@@ -0,0 +1,58 @@
---
# DEPRECATED: Ceph Dashboard OIDC Provider Blueprint
# This blueprint was used with oauth2-proxy which has been removed.
# Ceph Dashboard auth is now handled by Istio ext_authz + Authentik forward-auth.
# This file is NOT mounted in Authentik (not in configMaps list).
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-ceph-oidc
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
ceph-oidc.yaml: |-
version: 1
metadata:
name: ceph-dashboard-oidc
entries:
# OAuth2/OIDC Provider for Ceph Dashboard (via oauth2-proxy)
- model: authentik_providers_oauth2.oauth2provider
id: ceph-dashboard-oidc-provider
state: present
identifiers:
name: ceph-dashboard
attrs:
name: ceph-dashboard
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: ceph-dashboard
client_secret: ceph-dashboard-oidc-secret-homelab-2026
redirect_uris: |
https://ceph.kube.huskypup.net/oauth2/callback
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
access_code_validity: minutes=1
access_token_validity: minutes=5
refresh_token_validity: days=30
include_claims_in_id_token: true
sub_mode: user_username
issuer_mode: per_provider
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]]
# Application entry - update existing or create new
- model: authentik_core.application
id: ceph-dashboard-application
state: present
identifiers:
slug: ceph-dashboard
attrs:
name: Ceph Dashboard
slug: ceph-dashboard
policy_engine_mode: any
provider: !KeyOf ceph-dashboard-oidc-provider
meta_launch_url: "https://ceph.kube.huskypup.net"
meta_icon: "https://ceph.io/assets/favicons/favicon.ico"
@@ -0,0 +1,53 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-authentik
namespace: authentik
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:16
instances: 2
# Resource limits to prevent OOM
resources:
requests:
memory: "512Mi"
cpu: "25m"
limits:
memory: "2Gi"
cpu: "250m"
# Spread replicas across different nodes
affinity:
topologyKey: kubernetes.io/hostname
storage:
size: 5Gi
storageClass: rook-ceph-block
primaryUpdateStrategy: unsupervised
# PostgreSQL configuration for better performance
postgresql:
parameters:
max_connections: "200"
shared_buffers: "512MB"
effective_cache_size: "1536MB"
maintenance_work_mem: "128MB"
checkpoint_completion_target: "0.9"
wal_buffers: "16MB"
default_statistics_target: "100"
random_page_cost: "1.1"
effective_io_concurrency: "200"
work_mem: "2621kB"
min_wal_size: "1GB"
max_wal_size: "4GB"
bootstrap:
initdb:
database: app
owner: app
monitoring:
enablePodMonitor: true
@@ -0,0 +1,16 @@
---
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: cnpg-postgres
namespace: authentik
labels:
release: prometheus
spec:
selector:
matchLabels:
cnpg.io/cluster: pg-authentik
podMetricsEndpoints:
- port: metrics
path: /metrics
interval: 30s
@@ -0,0 +1,39 @@
---
apiVersion: generators.external-secrets.io/v1alpha1
kind: Password
metadata:
name: authentik-cnpg-secret
namespace: authentik
spec:
length: 42
digits: 5
symbols: 5
symbolCharacters: "-_$@"
noUpper: false
allowRepeat: true
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: authentik-cnpg-secret
namespace: authentik
spec:
# how often to rotate the DB password
refreshInterval: "24h"
target:
# This will merge the generated password into the existing pg-authentik-app secret
name: pg-authentik-app
creationPolicy: Merge
template:
metadata:
labels:
cnpg.io/reload: "true"
data:
# Override the password field with our ESO-generated password
password: "{{ .password }}"
dataFrom:
- sourceRef:
generatorRef:
apiVersion: generators.external-secrets.io/v1alpha1
kind: Password
name: authentik-cnpg-secret
@@ -0,0 +1,81 @@
---
# Forward Auth Proxy Provider Blueprint for Authentik
#
# Replaces oauth2-proxy with Authentik's built-in forward-auth capability.
# Istio's ext_authz filter calls Authentik's /outpost.goauthentik.io/auth/nginx
# endpoint to authenticate requests to protected services.
#
# Services protected by this provider:
# - Prometheus, Ceph Dashboard, TeslaMate, ESPHome, Frigate, Kiali, Nessus, Netbird
#
# Services with native OIDC are NOT included here (they handle auth themselves):
# - GitLab, ArgoCD, Grafana, n8n, Home Assistant, Rancher, Nextcloud
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-forward-auth
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
forward-auth.yaml: |-
version: 1
metadata:
name: forward-auth-provider
entries:
# ================================================================
# Proxy Provider - Forward Auth (domain mode) for Istio ext_authz
# ================================================================
# forward_domain mode handles ALL subdomains of cookie_domain.
# The embedded outpost matches any *.kube.huskypup.net request.
# Auth session is shared across subdomains via a single cookie.
- model: authentik_providers_proxy.proxyprovider
id: forward-auth-provider
state: present
identifiers:
name: Forward Auth (Istio)
attrs:
name: Forward Auth (Istio)
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
mode: forward_domain
external_host: "https://auth.kube.huskypup.net"
cookie_domain: "kube.huskypup.net"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
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]]
# ================================================================
# Application - Umbrella app for all forward-auth protected services
# ================================================================
- model: authentik_core.application
id: forward-auth-application
state: present
identifiers:
slug: forward-auth
attrs:
name: Protected Services (Forward Auth)
slug: forward-auth
policy_engine_mode: any
provider: !KeyOf forward-auth-provider
# ================================================================
# Outpost - Embedded outpost for forward auth
# Uses Authentik's built-in outpost (no separate deployment needed)
# ================================================================
- model: authentik_outposts.outpost
id: forward-auth-outpost
state: present
identifiers:
name: "authentik Embedded Outpost"
attrs:
type: proxy
providers:
- !KeyOf forward-auth-provider
config:
authentik_host: "https://auth.kube.huskypup.net/"
authentik_host_insecure: true
@@ -0,0 +1,53 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-gitlab
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
gitlab.yaml: |-
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: gitlab-oidc
entries:
# OAuth2/OIDC Provider for GitLab
- model: authentik_providers_oauth2.oauth2provider
id: gitlab-provider
state: present
identifiers:
name: GitLab
attrs:
name: GitLab
client_id: 70b9da5c8166cea0ba504a869824020bce6636
client_secret: 2e9c0c5b7a8969eb782d08bf1bf3d50ad96f8a73d9c18d1e4141816aebe14a622e8064bf5a5bce835d80e89cdc5f4cc6cf4a8c8234556647dc8884888866bd7d
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://gitlab.kube.huskypup.net/users/auth/openid_connect/callback"
matching_mode: strict
enabled: true
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "days=7"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, default]]
# Application for GitLab
- model: authentik_core.application
id: gitlab-application
state: present
identifiers:
slug: gitlab
attrs:
name: GitLab
slug: gitlab
policy_engine_mode: any
provider: !KeyOf gitlab-provider
@@ -0,0 +1,60 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-gitlab-saml
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
gitlab-saml.yaml: |-
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: gitlab-saml
entries:
# SAML Provider for GitLab
- model: authentik_providers_saml.samlprovider
id: gitlab-saml-provider
state: present
identifiers:
name: GitLab SAML
attrs:
name: GitLab SAML
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
# Redirect URI from the GitLab SAML docs
# https://gitlab.kube.huskypup.net/users/auth/saml/callback
acs_url: "https://gitlab.kube.huskypup.net/users/auth/saml/callback"
audience: "https://gitlab.kube.huskypup.net"
issuer: "https://gitlab.kube.huskypup.net"
# SAML-specific settings
service_provider_slo_url: "https://gitlab.kube.huskypup.net/users/auth/saml/slo"
digest_algorithm: "http://www.w3.org/2001/04/xmlenc#sha256"
signature_algorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
require_signing: true
# Property mappings for SAML attributes
property_mappings:
- !Find [authentik_providers_saml.samlpropertymapping, [managed, goauthentik.io/providers/saml/name]]
- !Find [authentik_providers_saml.samlpropertymapping, [managed, goauthentik.io/providers/saml/email]]
- !Find [authentik_providers_saml.samlpropertymapping, [managed, goauthentik.io/providers/saml/username]]
# Signing certificate
signing_key: !Find [authentik_crypto.certificatekeypair, [name, default]]
# Application for GitLab SAML
- model: authentik_core.application
id: gitlab-saml-application
state: present
identifiers:
slug: gitlab-saml
attrs:
name: GitLab SAML
slug: gitlab-saml
policy_engine_mode: any
provider: !KeyOf gitlab-saml-provider
launch_url: "https://gitlab.kube.huskypup.net"
@@ -0,0 +1,99 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-grafana
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
grafana.yaml: |-
version: 1
metadata:
name: grafana-oidc
entries:
# ============================================================================
# AUTO-CREATE GRAFANA GROUPS
# ============================================================================
# These groups control access levels in Grafana via OAuth role mapping:
# - Grafana Admins → Admin role (full access)
# - Grafana Editors → Editor role (can edit dashboards)
# - Grafana Viewers → Viewer role (read-only)
#
# AUTOMATIC ADMIN ACCESS:
# - Anyone in "authentik Admins" automatically gets Grafana Admin access
# - No manual configuration needed!
# ============================================================================
- model: authentik_core.group
id: grafana-admins-group
state: present
identifiers:
name: Grafana Admins
attrs:
name: Grafana Admins
is_superuser: false
# Note: authentik Admins are automatically granted access via role_attribute_path
# in Grafana configuration (see grafana/values.yaml)
- model: authentik_core.group
id: grafana-editors-group
state: present
identifiers:
name: Grafana Editors
attrs:
name: Grafana Editors
is_superuser: false
- model: authentik_core.group
id: grafana-viewers-group
state: present
identifiers:
name: Grafana Viewers
attrs:
name: Grafana Viewers
is_superuser: false
# ============================================================================
# GRAFANA OAUTH2 PROVIDER
# ============================================================================
- model: authentik_providers_oauth2.oauth2provider
id: grafana-provider
state: present
identifiers:
name: Grafana
attrs:
name: Grafana
client_id: bd03e9139dd2063c6c44c4d2f65f51d69de3ba0b6d6b1b9b41c255d2376d2dcc
client_secret: 6b6f2deecfe8fd56cae9c512cc71eedd463d67ff08f24c816b15b15e78ce36bc4f06a2276c5ffe3f67799d935994a32ed32cdc02ec674f279c82d7cfe3ca05d5
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://grafana.kube.huskypup.net/login/generic_oauth"
matching_mode: strict
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, default]]
# ============================================================================
# GRAFANA APPLICATION
# ============================================================================
- model: authentik_core.application
id: grafana-application
state: present
identifiers:
slug: grafana
attrs:
name: Grafana
slug: grafana
policy_engine_mode: any
provider: !KeyOf grafana-provider
@@ -0,0 +1,83 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-guacamole
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
guacamole.yaml: |-
version: 1
metadata:
name: guacamole-oidc
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# ============================================================================
# GUACAMOLE OAUTH2 PROVIDER
# ============================================================================
# This creates the OAuth2 provider that Guacamole will use for authentication.
# The client_id and client_secret must match what's configured in Guacamole.
# ============================================================================
# ============================================================================
# GROUPS SCOPE MAPPING
# ============================================================================
# Custom scope mapping that includes user's group names in the OIDC token.
# ============================================================================
- model: authentik_providers_oauth2.scopemapping
id: guacamole-groups-scope
identifiers:
managed: goauthentik.io/providers/oauth2/guacamole-groups
attrs:
name: "Guacamole Groups Scope"
scope_name: groups
expression: |
return {
"groups": [group.name for group in request.user.ak_groups.all()],
}
- model: authentik_providers_oauth2.oauth2provider
id: guacamole-provider
identifiers:
name: guacamole
attrs:
name: Guacamole
client_id: a55cbe3c6d2ae30c05c86385802ffcfd76a972c22c8d039f000281d4a149fd44
client_secret: 718d4c4816aa68767a6a0da0fa4099d492473c700ba236cbeb64d294762b9548acda7e716ba11b2ad7729d6a1c16c7890b227e3b2dcfc35fd4af1eb0d6662b0f
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://guacamole.kube.huskypup.net/"
matching_mode: strict
- url: "https://guacamole.kube.huskypup.net/guacamole/"
matching_mode: strict
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]]
- !KeyOf guacamole-groups-scope
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "Lets Encrypt K8s Cert"]]
# ============================================================================
# GUACAMOLE APPLICATION
# ============================================================================
# This creates the application entry that users will see in Authentik.
# ============================================================================
- model: authentik_core.application
id: guacamole-application
identifiers:
slug: guacamole
attrs:
name: Guacamole
slug: guacamole
policy_engine_mode: any
provider: !KeyOf guacamole-provider
@@ -0,0 +1,68 @@
---
# Home Assistant OIDC Provider Blueprint for Authentik
#
# This blueprint creates an OAuth2/OIDC provider in Authentik for Home Assistant
# Home Assistant will use the hass-openid custom integration for direct OIDC auth
#
# AUTOMATIC FEATURES:
# - Users authenticate via Authentik OIDC
# - User accounts auto-created in Home Assistant on first login
# - Usernames sync from Authentik (preferred_username)
# - No OAuth2 Proxy needed - direct integration!
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-home-assistant
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
home-assistant.yaml: |-
version: 1
metadata:
name: home-assistant-oidc
entries:
# ============================================================================
# HOME ASSISTANT OAUTH2 PROVIDER
# ============================================================================
# Manual client_id and client_secret for full automation (no random generation)
- model: authentik_providers_oauth2.oauth2provider
id: home-assistant-provider
state: present
identifiers:
name: Home Assistant
attrs:
name: Home Assistant
client_id: ha1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab
client_secret: ha_secret_1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12345678
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://homeassistant.kube.huskypup.net/auth/openid/callback"
matching_mode: strict
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Internal JWT Certificate"]]
# ============================================================================
# HOME ASSISTANT APPLICATION
# ============================================================================
- model: authentik_core.application
id: home-assistant-application
state: present
identifiers:
slug: home-assistant
attrs:
name: Home Assistant
slug: home-assistant
policy_engine_mode: any
provider: !KeyOf home-assistant-provider
@@ -0,0 +1,20 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: authentik
namespace: authentik
spec:
parentRefs:
- name: edge
namespace: gateway
sectionName: https
hostnames:
- auth.kube.huskypup.net
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: authentik-server
port: 80
@@ -0,0 +1,179 @@
# Nginx proxy that rewrites Host header for Authentik ext_authz
#
# Problem: Envoy's ext_authz HTTP filter forwards the ORIGINAL request's Host
# header (e.g., prometheus.kube.huskypup.net) to Authentik. But Authentik's
# embedded outpost only serves /outpost.goauthentik.io/auth/nginx on the
# brand domain (auth.kube.huskypup.net), returning 404 for other hosts.
#
# Solution: This lightweight nginx proxy sits between Istio's ext_authz filter
# and Authentik. It rewrites the Host header to auth.kube.huskypup.net while
# preserving all other headers (X-Forwarded-Host, cookies, etc.) so Authentik
# knows the original service being accessed.
#
# Flow:
# 1. Client → Istio ingress gateway (Host: prometheus.kube.huskypup.net)
# 2. ext_authz filter → this proxy (Host: prometheus.kube.huskypup.net)
# 3. This proxy → Authentik (Host: auth.kube.huskypup.net, X-Forwarded-Host preserved)
# 4. Authentik checks auth, returns 200 (allow) or 302 (redirect to login)
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ext-authz-proxy-config
namespace: authentik
data:
nginx.conf: |
load_module modules/ngx_http_js_module.so;
worker_processes 1;
error_log /dev/stderr warn;
pid /tmp/nginx.pid;
events {
worker_connections 256;
}
http {
access_log /dev/stdout;
proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
js_path /etc/nginx/njs/;
js_import cookie from cookie_domain.js;
server {
listen 4180;
location / {
# Rewrite all paths to the exact Authentik traefik handler path.
# Envoy ext_authz appends the original request path to pathPrefix,
# creating paths like /auth/traefik/ which Authentik's Go router
# doesn't match (exact path only, no trailing slash).
rewrite ^ /outpost.goauthentik.io/auth/traefik break;
proxy_pass http://authentik-server.authentik.svc.cluster.local;
proxy_http_version 1.1;
proxy_set_header Host auth.kube.huskypup.net;
proxy_set_header Connection "";
proxy_pass_request_headers on;
# Add Domain=kube.huskypup.net to Set-Cookie headers from Authentik.
# The outpost creates session cookies without Domain attribute, causing
# browser to scope them to the original request domain (e.g., frigate.kube.huskypup.net).
# The callback goes to auth.kube.huskypup.net, so the cookie must be domain-scoped.
js_header_filter cookie.addDomain;
}
}
}
cookie_domain.js: |
function addDomain(r) {
var cookies = r.headersOut['Set-Cookie'];
if (cookies) {
if (!Array.isArray(cookies)) {
cookies = [cookies];
}
var modified = cookies.map(function(c) {
if (c.indexOf('Domain=') === -1) {
return c + '; Domain=kube.huskypup.net';
}
return c;
});
r.headersOut['Set-Cookie'] = modified;
}
}
export default { addDomain };
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ext-authz-proxy
namespace: authentik
labels:
app: ext-authz-proxy
spec:
replicas: 2
selector:
matchLabels:
app: ext-authz-proxy
template:
metadata:
labels:
app: ext-authz-proxy
spec:
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 4180
protocol: TCP
volumeMounts:
- name: config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
readOnly: true
- name: njs
mountPath: /etc/nginx/njs/cookie_domain.js
subPath: cookie_domain.js
readOnly: true
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 50m
memory: 64Mi
securityContext:
runAsNonRoot: true
runAsUser: 10101
runAsGroup: 10101
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
readinessProbe:
tcpSocket:
port: 4180
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 4180
initialDelaySeconds: 5
periodSeconds: 10
volumes:
- name: config
configMap:
name: ext-authz-proxy-config
- name: njs
configMap:
name: ext-authz-proxy-config
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: ext-authz-proxy
namespace: authentik
labels:
app: ext-authz-proxy
spec:
selector:
app: ext-authz-proxy
ports:
- port: 4180
targetPort: 4180
protocol: TCP
@@ -0,0 +1,63 @@
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: authentik
namespace: authentik
spec:
hosts:
- auth.kube.huskypup.net
gateways:
- istio-system/edge
http:
# Allow NetBird silent auth in an iframe (prompt=none)
- match:
- uri:
prefix: /application/o/authorize/
headers:
response:
remove:
- x-frame-options
set:
content-security-policy: "frame-ancestors https://netbird.kube.huskypup.net"
route:
- destination:
host: authentik-server.authentik.svc.cluster.local
port:
number: 80
# Ensure CORS headers are present even on 401 responses
- match:
- uri:
prefix: /application/o/userinfo/
- uri:
prefix: /application/o/token/
headers:
response:
set:
access-control-allow-origin: "https://netbird.kube.huskypup.net"
access-control-allow-credentials: "true"
access-control-allow-methods: "GET, POST, OPTIONS"
access-control-allow-headers: "authorization, content-type"
vary: "Origin"
route:
- destination:
host: authentik-server.authentik.svc.cluster.local
port:
number: 80
# Forward auth endpoint for Istio ext_authz
- match:
- uri:
prefix: /outpost.goauthentik.io
route:
- destination:
host: authentik-server.authentik.svc.cluster.local
port:
number: 80
# All other traffic goes to Authentik
- route:
- destination:
host: authentik-server.authentik.svc.cluster.local
port:
number: 80
@@ -0,0 +1,36 @@
apiVersion: batch/v1
kind: Job
metadata:
name: authentik-oauth-sync
namespace: authentik
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
argocd.argoproj.io/sync-wave: "1"
spec:
backoffLimit: 3
template:
spec:
serviceAccountName: argocd-hook-sa
containers:
- name: oauth-sync
image: bitnami/kubectl:1.31
command:
- /bin/bash
- -c
- |
set -euo pipefail
echo "=== Authentik PostSync - OAuth Sync ==="
echo "Waiting for Authentik server..."
kubectl -n authentik rollout status deploy/authentik-server --timeout=600s
echo "Waiting for Authentik worker..."
kubectl -n authentik rollout status deploy/authentik-worker --timeout=300s
echo "OAuth sync scripts should be run manually or via a separate automation."
echo "Scripts are in the scripts/ directory of the Homelabv4 repo."
echo "Run: bash scripts/sync-*-oauth.sh"
echo "=== Authentik PostSync Complete ==="
restartPolicy: Never
@@ -0,0 +1,48 @@
apiVersion: batch/v1
kind: Job
metadata:
name: authentik-presync
namespace: authentik
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
backoffLimit: 3
template:
spec:
serviceAccountName: argocd-hook-sa
containers:
- name: presync
image: bitnami/kubectl:1.31
command:
- /bin/bash
- -c
- |
set -euo pipefail
echo "=== Authentik PreSync ==="
# Wait for CNPG cluster to be ready (applied by ArgoCD as sync-wave resource)
echo "Waiting for Authentik PostgreSQL cluster..."
for i in $(seq 1 60); do
PHASE=$(kubectl -n authentik get clusters.postgresql.cnpg.io pg-authentik -o jsonpath='{.status.phase}' 2>/dev/null || echo "")
if [ "$PHASE" = "Cluster in healthy state" ] || [ "$PHASE" = "Healthy" ]; then
echo " PostgreSQL cluster ready"
break
fi
echo " waiting for pg-authentik... (attempt $i/60, phase=$PHASE)"
sleep 5
done
# Generate Authentik secret key if it doesn't exist
if ! kubectl -n authentik get secret authentik >/dev/null 2>&1; then
echo "Generating Authentik secret key..."
SECRET_KEY=$(openssl rand -hex 50)
kubectl -n authentik create secret generic authentik \
--from-literal=AUTHENTIK_SECRET_KEY="$SECRET_KEY"
echo " Authentik secret key generated"
else
echo " Authentik secret already exists"
fi
echo "=== Authentik PreSync Complete ==="
restartPolicy: Never
@@ -0,0 +1,49 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-n8n
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
n8n.yaml: |-
version: 1
metadata:
name: n8n-oidc
entries:
- model: authentik_providers_oauth2.oauth2provider
id: n8n-provider
state: present
identifiers:
name: n8n
attrs:
name: n8n
client_id: e55cbe3c6d2ae30c05c86385802ffcfd76a972c22c8d039f000281d4a149fd44
client_secret: 718d4c4816aa68767a6a0da0fa4099d492473c700ba236cbeb64d294762b9548acda7e716ba11b2ad7729d6a1c16c7890b227e3b2dcfc35fd4af1eb0d6662b0f
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://n8n.kube.huskypup.net/callback"
matching_mode: strict
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
- model: authentik_core.application
id: n8n-application
state: present
identifiers:
slug: n8n
attrs:
name: n8n
slug: n8n
policy_engine_mode: any
provider: !KeyOf n8n-provider
@@ -0,0 +1,93 @@
---
# Netbird OIDC Provider Blueprint for Authentik
# Creates an OAuth2/OIDC provider for Netbird VPN SSO integration
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-netbird
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
netbird.yaml: |-
version: 1
metadata:
name: netbird-oidc
entries:
- model: authentik_providers_oauth2.oauth2provider
id: netbird-provider
state: present
identifiers:
name: Netbird
attrs:
name: Netbird
# NetBird dashboard uses prompt=none for silent auth; this flow avoids consent UI.
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://netbird.kube.huskypup.net/.*"
matching_mode: regex
- url: "http://localhost:53000"
matching_mode: strict
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]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, offline_access]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, "goauthentik.io/api"]]
client_type: public
include_claims_in_id_token: true
sub_mode: user_id
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
# Create VPN User group (used for non-admin NetBird access)
- model: authentik_core.group
id: vpn-user-group
state: present
identifiers:
name: VPN User
attrs:
name: VPN User
is_superuser: false
- model: authentik_core.application
id: netbird-application
state: present
identifiers:
slug: netbird
attrs:
name: Netbird VPN
slug: netbird
policy_engine_mode: any
provider: !KeyOf netbird-provider
# Restrict NetBird access to authentik Admins and VPN User groups
- model: authentik_policies.policybinding
state: present
identifiers:
target: !KeyOf netbird-application
group: !Find [authentik_core.group, [name, "authentik Admins"]]
attrs:
target: !KeyOf netbird-application
group: !Find [authentik_core.group, [name, "authentik Admins"]]
enabled: true
order: 0
negate: false
timeout: 30
- model: authentik_policies.policybinding
state: present
identifiers:
target: !KeyOf netbird-application
group: !Find [authentik_core.group, [name, "VPN User"]]
attrs:
target: !KeyOf netbird-application
group: !Find [authentik_core.group, [name, "VPN User"]]
enabled: true
order: 1
negate: false
timeout: 30
@@ -0,0 +1,52 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-nextcloud
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
nextcloud.yaml: |-
version: 1
metadata:
name: nextcloud-oidc
entries:
- model: authentik_providers_oauth2.oauth2provider
id: nextcloud-provider
state: present
identifiers:
name: Nextcloud
attrs:
name: Nextcloud
client_id: HmTGnUfhCvjFFbUUAne7JLrucNC2X675JicPbEnQ
client_secret: qTUf4NYjzUuAqfNV5D7SFPuuhJJwVltU6U3LAuJVy7dddJWeJSv2B4wKaRxbbHqpIiSfYPDaKujhEysKbOWUnf4n9OHPKJ0bu1I2EzkYtChO1Gq4gUv5EHPTzQlMBPnl
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://nextcloud.kube.huskypup.net/apps/user_oidc/code"
matching_mode: strict
- url: "http://nextcloud.kube.huskypup.net/apps/user_oidc/code"
matching_mode: strict
enabled: true
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "days=7"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Internal JWT Certificate"]]
- model: authentik_core.application
id: nextcloud-application
state: present
identifiers:
slug: nextcloud
attrs:
name: Nextcloud
slug: nextcloud
policy_engine_mode: any
provider: !KeyOf nextcloud-provider
@@ -0,0 +1,77 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-percona-everest
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
percona-everest.yaml: |-
version: 1
metadata:
name: percona-everest-oidc
labels:
blueprints.goauthentik.io/instantiate: "true"
entries:
# ============================================================================
# PERCONA EVEREST OIDC PROVIDER
# ============================================================================
# Everest uses OIDC with PKCE (public client) for authentication.
# The client_id must match server.oidc.clientId in percona-everest/values.yaml.
# ============================================================================
# Custom scope mapping to inject jti claim (required by Everest)
- model: authentik_providers_oauth2.scopemapping
id: percona-everest-jti-mapping
state: present
identifiers:
managed: goauthentik.io/providers/proxy/scope-percona-everest-jti
attrs:
name: "Percona Everest JTI Claim"
scope_name: "everest-jti"
expression: |
import uuid
return {"jti": str(uuid.uuid4())}
- model: authentik_providers_oauth2.oauth2provider
id: percona-everest-provider
state: present
identifiers:
name: Percona Everest
attrs:
name: Percona Everest
client_id: percona-everest-oidc-client-id-static-2025
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://everest.kube.huskypup.net/login-callback"
matching_mode: strict
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]]
- !KeyOf percona-everest-jti-mapping
include_claims_in_id_token: true
client_type: public
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]]
# ============================================================================
# PERCONA EVEREST APPLICATION
# ============================================================================
- model: authentik_core.application
id: percona-everest-application
state: present
identifiers:
slug: percona-everest
attrs:
name: Percona Everest
slug: percona-everest
policy_engine_mode: any
provider: !KeyOf percona-everest-provider
meta_launch_url: "https://everest.kube.huskypup.net"
@@ -0,0 +1,23 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-prometheus
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
prometheus.yaml: |-
version: 1
metadata:
name: prometheus-app
entries:
- model: authentik_core.application
id: prometheus-application
state: present
identifiers:
slug: prometheus
attrs:
name: Prometheus
slug: prometheus
policy_engine_mode: any
@@ -0,0 +1,54 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authentik-blueprints-rancher
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
rancher.yaml: |-
# yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json
version: 1
metadata:
name: rancher-oidc
entries:
- model: authentik_providers_oauth2.oauth2provider
id: rancher-provider
state: present
identifiers:
name: Rancher
attrs:
name: Rancher
client_id: 94a6beeaa91d0d0407cf8af807e8208a611cf3f25ae42161e697a8dccd563449
client_secret: 19ebd4545ba74a93c220d4471af634302c5991204cf650cabd522b0864d7617ded2c59b470ab6de7a5801e7de4c84e4b9741b983170815419c9503d55f849794
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://rancher.kube.huskypup.net/verify-auth"
matching_mode: strict
- url: "https://rancher.kube.huskypup.net"
matching_mode: strict
enabled: true
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]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Internal JWT Certificate"]]
- model: authentik_core.application
id: rancher-application
state: present
identifiers:
slug: rancher
attrs:
name: Rancher
slug: rancher
policy_engine_mode: any
provider: !KeyOf rancher-provider
+177
View File
@@ -0,0 +1,177 @@
# Authentik configuration
authentik:
secret_key: env://AUTHENTIK_SECRET_KEY
postgresql:
host: env://AUTHENTIK_POSTGRESQL__HOST
port: 5432
name: env://AUTHENTIK_POSTGRESQL__NAME
user: env://AUTHENTIK_POSTGRESQL__USER
password: env://AUTHENTIK_POSTGRESQL__PASSWORD
global:
envFrom:
# First secret: Authentik-specific settings (AUTHENTIK_SECRET_KEY)
- secretRef:
name: authentik
# Second secret: Database credentials from CNPG
- secretRef:
name: pg-authentik-app
prefix: AUTHENTIK_POSTGRESQL__
env:
# Configure external URL for proper OIDC discovery responses
- name: AUTHENTIK_URL
value: "https://auth.kube.huskypup.net"
# Override to use the correct field names from pg-authentik-app
- name: AUTHENTIK_POSTGRESQL__HOST
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: host
- name: AUTHENTIK_POSTGRESQL__NAME
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: dbname
- name: AUTHENTIK_POSTGRESQL__USER
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: username
- name: AUTHENTIK_POSTGRESQL__PASSWORD
valueFrom:
secretKeyRef:
name: pg-authentik-app
key: password
- name: AUTHENTIK_POSTGRESQL__PORT
value: "5432"
# Blueprints - Mount ConfigMaps for auto-discovery
blueprints:
configMaps:
- authentik-blueprints-gitlab
- authentik-blueprints-nextcloud
- authentik-blueprints-argocd
- authentik-blueprints-grafana
- authentik-blueprints-forward-auth
- authentik-blueprints-prometheus
- authentik-blueprints-n8n
- authentik-blueprints-ceph
- authentik-blueprints-home-assistant
- authentik-blueprints-guacamole
- authentik-blueprints-percona-everest
- authentik-blueprints-rancher
- authentik-blueprints-netbird
# Enable Prometheus metrics
server:
# Single replica required: the embedded outpost stores forward-auth sessions
# in-memory (no Redis). Multiple replicas cause callback failures because
# the session created during ext_authz check is only on one pod.
replicas: 1
containerSecurityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
metrics:
enabled: true
serviceMonitor:
enabled: true
labels:
release: prometheus
# Resource limits to prevent OOM
resources:
requests:
cpu: 50m
memory: 512Mi
limits:
memory: 1Gi
# Health probes - removed invalid 'enabled' fields
startupProbe:
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 24 # 120 seconds for Authentik startup
readinessProbe:
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
livenessProbe:
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Spread across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: server
topologyKey: kubernetes.io/hostname
worker:
containerSecurityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
metrics:
enabled: true
serviceMonitor:
enabled: true
labels:
release: prometheus
# Resource limits to prevent OOM
resources:
requests:
cpu: 50m
memory: 512Mi
limits:
memory: 1Gi
# Spread across nodes
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/component: worker
topologyKey: kubernetes.io/hostname
# Mount cert-manager secret for auto-import of Let's Encrypt cert
volumeMounts:
- name: certs
mountPath: /certs
readOnly: true
volumes:
- name: certs
secret:
secretName: authentik-tls
optional: true
# Disable bundled Postgres
postgresql:
enabled: false