Files
homelab-design/decisions/0028-authentik-sso-strategy.md
Billy D. b43c80153c docs: add ADRs 0025-0028 for infrastructure patterns
- 0025: Observability stack (Prometheus + ClickStack + OTEL)
- 0026: Tiered storage strategy (Longhorn + NFS)
- 0027: Database strategy (CloudNativePG for PostgreSQL)
- 0028: Authentik SSO strategy (OIDC/SAML identity provider)
2026-02-04 08:55:15 -05:00

14 KiB

Authentik Single Sign-On Strategy

  • Status: accepted
  • Date: 2026-02-04
  • Deciders: Billy
  • Technical Story: Centralize authentication across all homelab applications

Context and Problem Statement

A growing homelab with many self-hosted applications creates authentication sprawl - each app has its own user database, passwords, and session management. This creates poor user experience and security risks.

How do we centralize authentication while maintaining flexibility for different application requirements?

Decision Drivers

  • Single sign-on (SSO) for all applications
  • Centralized user management and lifecycle
  • MFA enforcement across all applications
  • Open-source and self-hosted
  • Low resource requirements for homelab scale

Considered Options

  1. Authentik as OIDC/SAML provider
  2. Keycloak
  3. Authelia + LDAP
  4. Per-application local auth

Decision Outcome

Chosen option: Option 1 - Authentik as OIDC/SAML provider

Authentik provides modern identity management with OIDC, SAML 2.0, LDAP, and SCIM support. Its flow-based authentication engine allows customizable login experiences.

Positive Consequences

  • Clean, modern UI for users and admins
  • Flexible flow-based authentication
  • Built-in MFA (TOTP, WebAuthn, SMS, Duo)
  • Proxy provider for legacy apps
  • SCIM for user provisioning
  • Active development and community

Negative Consequences

  • Python-based (higher memory than Go alternatives)
  • PostgreSQL dependency
  • Some enterprise features require outpost pods

Architecture

                                    ┌─────────────────────┐
                                    │      User           │
                                    └──────────┬──────────┘
                                               │
                                               ▼
                                    ┌─────────────────────┐
                                    │   Ingress/Traefik   │
                                    └──────────┬──────────┘
                                               │
                    ┌──────────────────────────┼──────────────────────────┐
                    │                          │                          │
                    ▼                          ▼                          ▼
         ┌─────────────────┐       ┌─────────────────┐       ┌─────────────────┐
         │  auth.lab.io    │       │  app.lab.io     │       │  app2.lab.io    │
         │   (Authentik)   │       │  (OIDC-enabled) │       │ (Proxy-auth)    │
         └─────────────────┘       └────────┬────────┘       └────────┬────────┘
                    │                       │                         │
                    │    ┌──────────────────┘                         │
                    │    │ OIDC/OAuth2                                │
                    │    │                                            │
                    ▼    ▼                                            ▼
         ┌─────────────────────────────────────────────────────────────────┐
         │                          Authentik                              │
         │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐            │
         │  │   Server    │  │   Worker    │  │   Outpost   │◄───────────┤
         │  │   (API)     │  │  (Tasks)    │  │  (Proxy)    │ Forward    │
         │  └──────┬──────┘  └──────┬──────┘  └─────────────┘ Auth       │
         │         │                │                                     │
         │         └────────┬───────┘                                     │
         │                  │                                             │
         │           ┌──────▼──────┐                                      │
         │           │   Redis     │                                      │
         │           │  (Cache)    │                                      │
         │           └─────────────┘                                      │
         │                                                                │
         └─────────────────────────────┬──────────────────────────────────┘
                                       │
                                ┌──────▼──────┐
                                │ PostgreSQL  │
                                │ (CNPG)      │
                                └─────────────┘

Provider Configuration

OIDC Applications

Application Provider Type Claims Override Notes
Gitea OIDC None Admin mapping via group
Affine OIDC email_verified: true See ADR-0016
Companions OIDC None Custom provider
Grafana OIDC role claim Admin role mapping
ArgoCD OIDC groups claim RBAC integration
MLflow Proxy N/A Forward auth
Open WebUI OIDC None LLM interface

Provider Template

# Example OAuth2/OIDC Provider
apiVersion: authentik.io/v1
kind: OAuth2Provider
metadata:
  name: gitea
spec:
  name: Gitea
  authorizationFlow: default-authorization-flow
  clientId: ${GITEA_CLIENT_ID}
  clientSecret: ${GITEA_CLIENT_SECRET}
  redirectUris:
    - https://git.lab.daviestechlabs.io/user/oauth2/authentik/callback
  signingKey: authentik-self-signed
  propertyMappings:
    - authentik-default-openid
    - authentik-default-email
    - authentik-default-profile

Authentication Flows

Default Login Flow

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Login     │────▶│  Username   │────▶│   Password  │────▶│    MFA      │
│   Stage     │     │   Stage     │     │   Stage     │     │   Stage     │
└─────────────┘     └─────────────┘     └─────────────┘     └──────┬──────┘
                                                                   │
                                                                   ▼
                                                           ┌─────────────┐
                                                           │   Session   │
                                                           │   Created   │
                                                           └─────────────┘

Flow Customization

  • Admin users: Require hardware key (WebAuthn)
  • API access: Service account tokens
  • External users: Email verification + MFA enrollment

Group-Based Authorization

Group Structure

authentik-admins        → Authentik admin access
├── cluster-admins      → Full cluster access
├── gitea-admins        → Git admin
├── monitoring-admins   → Grafana admin
└── ai-platform-admins  → AI/ML admin

authentik-users         → Standard user access  
├── developers          → Git write, monitoring read
├── ml-engineers        → AI/ML services access
└── guests              → Read-only access

Application Group Mapping

# Grafana OIDC config
grafana:
  auth.generic_oauth:
    role_attribute_path: |
      contains(groups[*], 'monitoring-admins') && 'Admin' || 
      contains(groups[*], 'developers') && 'Editor' || 
      'Viewer'

Outpost Deployment

Embedded Outpost (Default)

  • Runs within Authentik server
  • Handles LDAP and Radius
  • Suitable for small deployments

Standalone Outpost (Proxy)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: authentik-outpost-proxy
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: outpost
          image: ghcr.io/goauthentik/proxy
          ports:
            - containerPort: 9000
              name: http
            - containerPort: 9443
              name: https
          env:
            - name: AUTHENTIK_HOST
              value: "https://auth.lab.daviestechlabs.io/"
            - name: AUTHENTIK_TOKEN
              valueFrom:
                secretKeyRef:
                  name: authentik-outpost-token
                  key: token

Forward Auth Integration

For applications without OIDC support:

# Traefik ForwardAuth middleware
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: authentik-forward-auth
spec:
  forwardAuth:
    address: http://authentik-outpost-proxy.authentik.svc:9000/outpost.goauthentik.io/auth/traefik
    trustForwardHeader: true
    authResponseHeaders:
      - X-authentik-username
      - X-authentik-groups
      - X-authentik-email

MFA Enforcement

Policies

User Group MFA Requirement
Admins WebAuthn (hardware key) required
Developers TOTP or WebAuthn required
Guests MFA optional

Device Registration

  • Self-service MFA enrollment
  • Recovery codes generated at setup
  • Admin can reset user MFA

SCIM User Provisioning

When to Use

  • Automatic user creation in downstream apps
  • Group membership sync
  • User deprovisioning on termination

Supported Apps

Currently using SCIM provisioning for:

  • None (manual user creation in apps)

Future consideration for:

  • Gitea organization sync
  • Grafana team sync

Secrets Management Integration

Vault Integration

# External Secret for Authentik DB credentials
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: authentik-db-credentials
  namespace: authentik
spec:
  secretStoreRef:
    kind: ClusterSecretStore
    name: vault
  target:
    name: authentik-db-credentials
  data:
    - secretKey: password
      remoteRef:
        key: kv/data/authentik
        property: db_password
    - secretKey: secret_key
      remoteRef:
        key: kv/data/authentik
        property: secret_key

Monitoring

Prometheus Metrics

Authentik exposes metrics at /metrics:

  • authentik_login_duration_seconds
  • authentik_login_attempt_total
  • authentik_outpost_connected
  • authentik_provider_authorization_total

Grafana Dashboard

  • Login success/failure rates
  • Active sessions
  • Provider usage
  • MFA adoption rates

Alerts

- alert: AuthentikHighLoginFailures
  expr: rate(authentik_login_attempt_total{result="failure"}[5m]) > 10
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: High login failure rate detected

- alert: AuthentikOutpostDisconnected
  expr: authentik_outpost_connected == 0
  for: 5m
  labels:
    severity: critical

Backup and Recovery

What to Backup

  1. PostgreSQL database (via CNPG)
  2. Media files (if custom branding)
  3. Blueprint exports (configuration as code)

Blueprints

Export configuration as YAML for GitOps:

# authentik-blueprints/providers/gitea.yaml
version: 1
metadata:
  name: Gitea OIDC Provider
entries:
  - model: authentik_providers_oauth2.oauth2provider
    identifiers:
      name: gitea
    attrs:
      authorization_flow: !Find [authentik_flows.flow, [slug, default-authorization-flow]]
      # ... provider config

Integration Patterns

Pattern 1: Native OIDC

Best for: Modern applications with OIDC support

App ──OIDC──▶ Authentik ──▶ App (with user info)

Pattern 2: Proxy Forward Auth

Best for: Legacy apps without SSO support

Request ──▶ Traefik ──ForwardAuth──▶ Authentik Outpost
                │                            │
                │◀──────Header injection─────┘
                │
                ▼
              App (reads X-authentik-* headers)

Pattern 3: LDAP Compatibility

Best for: Apps requiring LDAP

App ──LDAP──▶ Authentik Outpost (LDAP) ──▶ Authentik

Resource Requirements

Component CPU Request Memory Request
Server 100m 500Mi
Worker 100m 500Mi
Redis 50m 128Mi
Outpost (each) 50m 128Mi

Future Enhancements

  1. Passkey/FIDO2 - Passwordless authentication
  2. External IdP federation - Google/GitHub as upstream IdP
  3. Conditional access - Device trust, network location policies
  4. Session revocation - Force logout from all apps

References