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)
This commit is contained in:
415
decisions/0028-authentik-sso-strategy.md
Normal file
415
decisions/0028-authentik-sso-strategy.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
# 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)
|
||||
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
- 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:
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
|
||||
* [Authentik Documentation](https://goauthentik.io/docs/)
|
||||
* [Authentik GitHub](https://github.com/goauthentik/authentik)
|
||||
* [OIDC Specification](https://openid.net/specs/openid-connect-core-1_0.html)
|
||||
Reference in New Issue
Block a user