1143 lines
35 KiB
Markdown
1143 lines
35 KiB
Markdown
# Security Implementation Plan v2.0: Google OAuth SSO for Homelab Infrastructure
|
|
|
|
**Version:** 2.0 (Post-Failure Analysis & Comprehensive Revision)
|
|
**Date:** 2025-11-20
|
|
**Status:** Ready for Implementation
|
|
**Previous Version:** 1.1 (Failed - Redirect loops and high memory usage)
|
|
|
|
## Document Change Log
|
|
|
|
| Version | Date | Changes | Author |
|
|
|---------|------|---------|--------|
|
|
| 1.0 | 2025-11-10 | Initial plan | - |
|
|
| 1.1 | 2025-11-15 | Scope revision | - |
|
|
| 2.0 | 2025-11-20 | Post-failure analysis, redirect loop fixes, memory optimization, milestone checkpoints | Claude Code |
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
This document is a **complete revision** of the Authentik SSO implementation plan after a failed first attempt that resulted in infinite redirect loops and excessive memory usage (20-30% of system RAM).
|
|
|
|
**What Went Wrong (v1.0 Deployment):**
|
|
- ✗ Infinite redirect loops between NPM, Authentik, and Google OAuth
|
|
- ✗ `auth.schweitz.net` was protected by forward auth, creating self-referential loop
|
|
- ✗ Mixed hostname/IP/domain addressing caused OAuth callback failures
|
|
- ✗ Missing `AUTHENTIK_HOST` environment variable led to incorrect internal redirects
|
|
- ✗ Cookie domain not configured, preventing cross-service SSO
|
|
- ✗ Excessive memory usage (~3-5GB) due to separate PostgreSQL and Redis instances
|
|
- ✗ No rollback checkpoints, making recovery difficult
|
|
|
|
**What's Different in v2.0:**
|
|
- ✅ Detailed redirect loop prevention strategies
|
|
- ✅ Strict hostname/URL consistency requirements
|
|
- ✅ Memory optimization with shared PostgreSQL/Redis (target: <1GB total)
|
|
- ✅ **Milestone-based deployment with rollback points**
|
|
- ✅ **Configuration versioning at each step**
|
|
- ✅ **Validation tests before proceeding to next milestone**
|
|
- ✅ **Progress tracking within this document**
|
|
- ✅ Embedded outpost instead of separate container (simpler)
|
|
|
|
**Critical Success Factors:**
|
|
1. `auth.schweitz.net` must **NEVER** have forward auth enabled
|
|
2. `AUTHENTIK_HOST=https://auth.schweitz.net` must be set correctly
|
|
3. `AUTHENTIK_COOKIE_DOMAIN=.schweitz.net` for cross-service SSO
|
|
4. Test each service individually before moving to the next
|
|
5. Create backup snapshots at every milestone
|
|
6. Update this document with progress and issues as we go
|
|
|
|
**SSO Inclusion Policy:**
|
|
- ✅ **Include:** Web-based admin interfaces, dashboards, APIs requiring browser access
|
|
- ❌ **Exclude:** Services with native mobile/desktop apps that work better with username/password
|
|
- ❌ **Exclude:** Media streaming services (Jellyfin) - app integration priority
|
|
- ❌ **Exclude:** Development tools (code-server) - IDE integration priority
|
|
- ⏸️ **Defer:** Disabled/inactive services (Nextcloud) - implement when re-enabled
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
- [Section 0: Failure Analysis & Lessons Learned](#section-0-failure-analysis--lessons-learned)
|
|
- [Section 1: Prerequisites & Environment Validation](#section-1-prerequisites--environment-validation)
|
|
- [Section 2: Resource Optimization Strategy](#section-2-resource-optimization-strategy)
|
|
- [Section 3: Redirect Loop Prevention](#section-3-redirect-loop-prevention)
|
|
- [Section 4: Implementation Milestones](#section-4-implementation-milestones)
|
|
- [Section 5: Testing & Validation](#section-5-testing--validation)
|
|
- [Section 6: Troubleshooting Guide](#section-6-troubleshooting-guide)
|
|
- [Section 7: Rollback Procedures](#section-7-rollback-procedures)
|
|
- [Section 8: Progress Tracking](#section-8-progress-tracking)
|
|
|
|
---
|
|
|
|
## Section 0: Failure Analysis & Lessons Learned
|
|
|
|
### 0.1 What Happened in v1.0 Deployment
|
|
|
|
**Timeline:**
|
|
- Deployed Authentik stack with separate PostgreSQL and Redis
|
|
- Configured forward auth on ALL NPM proxy hosts (including auth.schweitz.net)
|
|
- Attempted to access services → immediate redirect loops
|
|
- Consumed 20-30% of system RAM (~3-5GB)
|
|
- Rolled back to working state (commit: `cb428a8`)
|
|
|
|
**Root Causes Identified:**
|
|
|
|
#### Issue 1: Self-Referential Authentication Loop
|
|
```
|
|
User → https://api.schweitz.net
|
|
→ NPM: "Need auth, redirect to https://auth.schweitz.net"
|
|
→ https://auth.schweitz.net
|
|
→ NPM: "Need auth, redirect to https://auth.schweitz.net" ← LOOP!
|
|
```
|
|
|
|
**Why it happened:** NPM configuration had forward auth enabled on `auth.schweitz.net` itself.
|
|
|
|
**Fix:** Remove forward auth from `auth.schweitz.net` NPM proxy host configuration.
|
|
|
|
#### Issue 2: Hostname/URL Discrepancies
|
|
```
|
|
External: https://auth.schweitz.net/source/oauth/callback/google/
|
|
Internal: http://localhost:9000/source/oauth/callback/google/
|
|
Outpost: http://192.168.86.149:9001/...
|
|
```
|
|
|
|
**Why it happened:**
|
|
- Mixed use of localhost, IP addresses, and domain names
|
|
- `AUTHENTIK_HOST` environment variable not set
|
|
- Authentik didn't know its external URL
|
|
|
|
**Fix:**
|
|
- Set `AUTHENTIK_HOST=https://auth.schweitz.net`
|
|
- Use consistent container names (not localhost/IP) in Docker configs
|
|
- Use external URLs for all OAuth callbacks
|
|
|
|
#### Issue 3: Cookie Domain Mismatch
|
|
**Why it happened:** Authentik didn't set cookie domain, so cookies were scoped to individual hosts, not shared across `*.schweitz.net`.
|
|
|
|
**Fix:** Set `AUTHENTIK_COOKIE_DOMAIN=.schweitz.net`
|
|
|
|
#### Issue 4: Excessive Memory Usage
|
|
**Why it happened:**
|
|
- Separate PostgreSQL instance for Authentik (~1GB)
|
|
- Separate Redis instance for Authentik (~100MB)
|
|
- No resource limits on server/worker containers
|
|
|
|
**Fix:**
|
|
- Use shared PostgreSQL (`postgres-shared:5432`)
|
|
- Use shared Redis (`redis-shared:6379` DB 0)
|
|
- Set memory limits: 512M server, 384M worker
|
|
|
|
### 0.2 Evidence from NPM Backup (2025-11-19)
|
|
|
|
All 11 NPM proxy hosts had **identical forward auth configuration**:
|
|
```nginx
|
|
auth_request /outpost.goauthentik.io/auth/nginx;
|
|
error_page 401 = @authentik_proxy_signin;
|
|
|
|
location @authentik_proxy_signin {
|
|
return 302 /outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
|
|
}
|
|
|
|
location /outpost.goauthentik.io {
|
|
proxy_pass http://192.168.86.149:9001/outpost.goauthentik.io;
|
|
}
|
|
```
|
|
|
|
**Problem:** This configuration was applied to ALL hosts, including `auth.schweitz.net`.
|
|
|
|
### 0.3 Lessons Learned
|
|
|
|
1. **Never protect the authentication server with authentication** - Seems obvious in retrospect, but easy to miss
|
|
2. **Test incrementally** - We tried to enable all 11 services at once
|
|
3. **Document assumptions** - We assumed Authentik would auto-detect external URLs
|
|
4. **Create rollback points** - Had to manually restore NPM config from backup
|
|
5. **Monitor resource usage** - Didn't realize memory consumption until it was running
|
|
6. **Read the docs thoroughly** - `AUTHENTIK_HOST` is a critical but easy-to-miss setting
|
|
|
|
---
|
|
|
|
## Section 1: Prerequisites & Environment Validation
|
|
|
|
### 1.1 System Specifications
|
|
|
|
| Component | Specification | Notes |
|
|
|-----------|---------------|-------|
|
|
| CPU | Intel i7-6700 (4C/8T) | ~19% usage for Authentik (1.5 cores) |
|
|
| RAM | 16GB total | Target: <1GB for Authentik (<6.25% of total) |
|
|
| Storage (SSD) | 489GB | ~3GB needed for Authentik data |
|
|
| Storage (HDD) | 3.7TB | Not used by Authentik |
|
|
| Network | docker-dataplane | All services on unified network |
|
|
|
|
**Available Resources:**
|
|
- RAM: 16GB - Current usage = ~6-8GB free
|
|
- Authentik target: 896MB (5.6% of total RAM) ✓ Acceptable
|
|
|
|
### 1.2 Shared Infrastructure Status
|
|
|
|
**PostgreSQL Shared** (`postgres-shared:5432`):
|
|
```bash
|
|
# Verify connectivity
|
|
docker exec postgres-shared pg_isready
|
|
|
|
# Verify authentik database exists
|
|
docker exec postgres-shared psql -U postgres -c "\l" | grep authentik
|
|
|
|
# Test connection as authentik_user
|
|
docker exec postgres-shared psql -U authentik_user -d authentik -c "SELECT version();"
|
|
```
|
|
|
|
**Expected output:**
|
|
```
|
|
authentik | authentik_user | UTF8 | ...
|
|
PostgreSQL 16.x on x86_64-pc-linux-musl...
|
|
```
|
|
|
|
**Redis Shared** (`redis-shared:6379`):
|
|
```bash
|
|
# Verify connectivity
|
|
docker exec redis-shared redis-cli PING
|
|
|
|
# Check DB 0 is available (Authentik allocation)
|
|
docker exec redis-shared redis-cli -n 0 INFO keyspace
|
|
|
|
# Test write/read
|
|
docker exec redis-shared redis-cli -n 0 SET test:authentik "connection_ok"
|
|
docker exec redis-shared redis-cli -n 0 GET test:authentik
|
|
docker exec redis-shared redis-cli -n 0 DEL test:authentik
|
|
```
|
|
|
|
**Expected output:**
|
|
```
|
|
PONG
|
|
# Keyspace (should be empty or have other keys)
|
|
connection_ok
|
|
1
|
|
```
|
|
|
|
### 1.3 Network Verification
|
|
|
|
```bash
|
|
# Verify docker-dataplane network exists
|
|
docker network inspect docker-dataplane
|
|
|
|
# List all containers on docker-dataplane
|
|
docker network inspect docker-dataplane | grep -A 2 "Containers"
|
|
|
|
# Verify DNS resolution between containers
|
|
docker run --rm --network docker-dataplane alpine ping -c 3 postgres-shared
|
|
docker run --rm --network docker-dataplane alpine ping -c 3 redis-shared
|
|
```
|
|
|
|
**Expected:** 19 containers on network, postgres-shared and redis-shared resolve correctly.
|
|
|
|
### 1.4 NPM Current State
|
|
|
|
```bash
|
|
# Backup current NPM configuration
|
|
curl -s http://192.168.86.149:8000/api/ > backups/npm-pre-authentik-$(date +%Y%m%d-%H%M%S).json
|
|
|
|
# Verify auth.schweitz.net proxy host exists
|
|
cat backups/npm-pre-authentik-*.json | jq '.proxy_hosts[] | select(.domain_names[] | contains("auth.schweitz"))'
|
|
```
|
|
|
|
**Expected:** auth.schweitz.net points to localhost:9000, currently has forward auth (will be removed).
|
|
|
|
### 1.5 SSL Certificates
|
|
|
|
```bash
|
|
# Verify Let's Encrypt certificates for schweitz.net domains
|
|
docker exec npm ls -la /etc/letsencrypt/live/ | grep schweitz
|
|
```
|
|
|
|
**Expected:** Certificates for all *.schweitz.net domains, valid and auto-renewing.
|
|
|
|
---
|
|
|
|
## Section 2: Resource Optimization Strategy
|
|
|
|
### 2.1 Resource Allocation Plan
|
|
|
|
**Authentik Server:**
|
|
```yaml
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 512M # Hard cap
|
|
cpus: '0.5' # 50% of one core
|
|
reservations:
|
|
memory: 256M # Guaranteed minimum
|
|
```
|
|
|
|
**Authentik Worker:**
|
|
```yaml
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 384M # Hard cap
|
|
cpus: '0.3' # 30% of one core
|
|
reservations:
|
|
memory: 128M # Guaranteed minimum
|
|
```
|
|
|
|
**Total Authentik overhead:** 896MB (vs previous 3-5GB = **78% reduction**)
|
|
|
|
### 2.2 Worker Configuration
|
|
|
|
**Reduce Celery workers and threads:**
|
|
```yaml
|
|
environment:
|
|
# Celery worker configuration
|
|
AUTHENTIK_BOOTSTRAP_WORKERS: 1 # Default: 1 (single worker)
|
|
AUTHENTIK_WORKER__CONCURRENCY: 2 # Threads per worker (default: 2)
|
|
|
|
# Logging optimization
|
|
AUTHENTIK_LOG_LEVEL: warning # Reduce log verbosity
|
|
AUTHENTIK_ERROR_REPORTING__ENABLED: false # Disable error reporting
|
|
|
|
# Disable non-essential features
|
|
AUTHENTIK_AVATARS: none # Disable avatar fetching (saves bandwidth)
|
|
AUTHENTIK_FOOTER_LINKS: '[]' # Disable footer links
|
|
```
|
|
|
|
**Resource impact:**
|
|
- 1 worker @ 2 threads = minimal CPU usage during idle
|
|
- Warning-level logging = less I/O overhead
|
|
- No avatar fetching = no external HTTP requests
|
|
|
|
### 2.3 Database Connection Optimization
|
|
|
|
**Use shared infrastructure, no connection pooling (unnecessary for homelab scale):**
|
|
```yaml
|
|
environment:
|
|
# PostgreSQL connection
|
|
AUTHENTIK_POSTGRESQL__HOST: postgres-shared
|
|
AUTHENTIK_POSTGRESQL__PORT: 5432
|
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
|
AUTHENTIK_POSTGRESQL__USER: authentik_user
|
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
|
|
AUTHENTIK_POSTGRESQL__USE_PGBOUNCER: false # No pooler needed
|
|
AUTHENTIK_POSTGRESQL__USE_PGPOOL: false # No pooler needed
|
|
|
|
# Redis connection
|
|
AUTHENTIK_REDIS__HOST: redis-shared
|
|
AUTHENTIK_REDIS__PORT: 6379
|
|
AUTHENTIK_REDIS__DB: 0 # Dedicated DB for Authentik
|
|
AUTHENTIK_REDIS__PASSWORD: "" # No password (internal network only)
|
|
```
|
|
|
|
**Benefit:** No dedicated PostgreSQL/Redis = ~1.1GB RAM saved.
|
|
|
|
### 2.4 Memory Usage Monitoring
|
|
|
|
**Check memory usage after deployment:**
|
|
```bash
|
|
# Container-level memory usage
|
|
docker stats authentik-server authentik-worker --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
|
|
|
|
# Process-level memory inside containers
|
|
docker exec authentik-server ps aux --sort=-%mem | head -10
|
|
docker exec authentik-worker ps aux --sort=-%mem | head -10
|
|
```
|
|
|
|
**Expected values:**
|
|
- authentik-server: 200-400MB (under 512M limit)
|
|
- authentik-worker: 100-250MB (under 384M limit)
|
|
- **Total: 300-650MB** (healthy, with burst headroom)
|
|
|
|
**If memory exceeds limits:**
|
|
- Check logs for errors: `docker logs authentik-server --tail 100`
|
|
- Verify no memory leaks: `docker exec authentik-server free -h`
|
|
- Restart containers if needed: `docker restart authentik-server authentik-worker`
|
|
|
|
---
|
|
|
|
## Section 3: Redirect Loop Prevention
|
|
|
|
### 3.1 Critical Configuration Rules
|
|
|
|
**RULE #1: Never Enable Forward Auth on auth.schweitz.net**
|
|
|
|
```nginx
|
|
# ✓ CORRECT - auth.schweitz.net NPM config
|
|
{
|
|
"domain_names": ["auth.schweitz.net"],
|
|
"forward_host": "localhost",
|
|
"forward_port": 9000,
|
|
"ssl_forced": true,
|
|
"advanced_config": "# NO FORWARD AUTH - This is the login page!\n\n# Optional: Rate limiting\nlimit_req_zone $binary_remote_addr zone=auth_limit:10m rate=10r/m;\nlimit_req zone=auth_limit burst=5 nodelay;"
|
|
}
|
|
```
|
|
|
|
```nginx
|
|
# ✗ WRONG - DO NOT DO THIS!
|
|
{
|
|
"domain_names": ["auth.schweitz.net"],
|
|
"advanced_config": "auth_request /outpost.goauthentik.io/auth/nginx;" # ← CAUSES LOOP!
|
|
}
|
|
```
|
|
|
|
**RULE #2: Set AUTHENTIK_HOST to External URL**
|
|
|
|
```yaml
|
|
environment:
|
|
AUTHENTIK_HOST: https://auth.schweitz.net # ← External HTTPS URL
|
|
AUTHENTIK_HOST_BROWSER: https://auth.schweitz.net # ← Same as AUTHENTIK_HOST
|
|
```
|
|
|
|
**Why:** Authentik uses this for generating redirect URLs in OAuth flows. If unset, it uses the request Host header, which might be `localhost` or an IP address internally.
|
|
|
|
**RULE #3: Configure Cookie Domain for SSO**
|
|
|
|
```yaml
|
|
environment:
|
|
AUTHENTIK_COOKIE_DOMAIN: .schweitz.net # ← Note the leading dot!
|
|
AUTHENTIK_COOKIE_SAMESITE: lax # ← Allow cross-subdomain cookies
|
|
```
|
|
|
|
**Why:** Without this, cookies are scoped to individual hosts (e.g., `auth.schweitz.net` only), and can't be shared with `api.schweitz.net`, `cloud.schweitz.net`, etc.
|
|
|
|
**RULE #4: Use Embedded Outpost (Simplicity)**
|
|
|
|
```yaml
|
|
# Server container serves both web UI and outpost
|
|
authentik-server:
|
|
ports:
|
|
- "9000:9000" # Web UI
|
|
- "9443:9443" # Embedded outpost
|
|
environment:
|
|
AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE: "ghcr.io/goauthentik/%(type)s:%(version)s"
|
|
```
|
|
|
|
**Why:** Eliminates need for separate outpost container, reduces complexity and memory usage.
|
|
|
|
**RULE #5: Consistent NPM Forward Auth Configuration**
|
|
|
|
```nginx
|
|
# Forward auth configuration for protected services (NOT auth.schweitz.net)
|
|
auth_request /outpost.goauthentik.io/auth/nginx;
|
|
error_page 401 = @authentik_proxy_signin;
|
|
|
|
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
|
add_header Set-Cookie $auth_cookie;
|
|
|
|
auth_request_set $authentik_username $upstream_http_x_authentik_username;
|
|
auth_request_set $authentik_email $upstream_http_x_authentik_email;
|
|
auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
|
|
|
|
proxy_set_header X-authentik-username $authentik_username;
|
|
proxy_set_header X-authentik-email $authentik_email;
|
|
proxy_set_header X-authentik-groups $authentik_groups;
|
|
|
|
location @authentik_proxy_signin {
|
|
internal;
|
|
return 302 https://auth.schweitz.net/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
|
|
}
|
|
|
|
location /outpost.goauthentik.io {
|
|
proxy_pass http://authentik-server:9443/outpost.goauthentik.io; # ← Use embedded outpost
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header X-Forwarded-Host $http_host;
|
|
proxy_set_header X-Forwarded-For $remote_addr;
|
|
proxy_pass_request_body off;
|
|
proxy_set_header Content-Length "";
|
|
}
|
|
```
|
|
|
|
### 3.2 OAuth Redirect URI Configuration
|
|
|
|
**Google OAuth Callback URL:** `https://auth.schweitz.net/source/oauth/callback/google/`
|
|
|
|
**In Google Cloud Console:**
|
|
```
|
|
Authorized JavaScript origins:
|
|
https://auth.schweitz.net
|
|
|
|
Authorized redirect URIs:
|
|
https://auth.schweitz.net/source/oauth/callback/google/
|
|
```
|
|
|
|
**In Authentik (Google Social Source):**
|
|
```
|
|
Consumer Key: <Google Client ID>
|
|
Consumer Secret: <Google Client Secret>
|
|
Provider Type: Google
|
|
Callback URL: (auto-filled, verify it matches Google Cloud Console)
|
|
```
|
|
|
|
**Critical:** The callback URL must **exactly** match between Google Cloud Console and Authentik. Case-sensitive, trailing slashes matter.
|
|
|
|
### 3.3 Testing Redirect Flows
|
|
|
|
**Manual redirect flow test:**
|
|
```bash
|
|
# 1. Visit protected service (should redirect to Authentik)
|
|
curl -I https://api.schweitz.net
|
|
# Expected: 302 redirect to https://auth.schweitz.net/outpost.goauthentik.io/start?rd=...
|
|
|
|
# 2. Visit Authentik login page (should NOT redirect)
|
|
curl -I https://auth.schweitz.net
|
|
# Expected: 200 OK (Authentik login page)
|
|
|
|
# 3. After login, check if cookie is set
|
|
curl -I -c cookies.txt https://auth.schweitz.net/flows/executor/default-provider-authentication-flow/
|
|
# Expected: Set-Cookie: authentik_session=...; Domain=.schweitz.net
|
|
|
|
# 4. Use cookie to access protected service
|
|
curl -I -b cookies.txt https://api.schweitz.net
|
|
# Expected: 200 OK (authenticated)
|
|
```
|
|
|
|
### 3.4 Redirect Loop Detection
|
|
|
|
**Symptoms:**
|
|
- Browser error: "ERR_TOO_MANY_REDIRECTS"
|
|
- Nginx logs show repeated 302 responses
|
|
- Authentik logs show repeated authentication attempts from same IP
|
|
|
|
**Diagnosis:**
|
|
```bash
|
|
# Check NPM logs for redirect chains
|
|
docker logs npm 2>&1 | grep -A 5 "auth.schweitz.net" | tail -50
|
|
|
|
# Check Authentik logs for repeated auth attempts
|
|
docker logs authentik-server 2>&1 | grep -i "redirect\|loop\|401\|302" | tail -50
|
|
|
|
# Test with verbose curl (shows redirect chain)
|
|
curl -v -L https://api.schweitz.net 2>&1 | grep -E "(< HTTP|< Location)"
|
|
```
|
|
|
|
**If loop detected:**
|
|
1. Check if `auth.schweitz.net` has forward auth enabled → **Remove it**
|
|
2. Verify `AUTHENTIK_HOST` environment variable → Should be `https://auth.schweitz.net`
|
|
3. Check cookie domain → Should be `.schweitz.net`
|
|
4. Verify outpost endpoint is reachable → `curl http://authentik-server:9443/outpost.goauthentik.io/ping/`
|
|
|
|
---
|
|
|
|
## Section 4: Implementation Milestones
|
|
|
|
### Milestone 0: Pre-Deployment Validation ✓ Safe to Execute
|
|
|
|
**Objective:** Verify all prerequisites are met before deploying Authentik.
|
|
|
|
**Tasks:**
|
|
- [ ] **M0.1:** Run PostgreSQL connectivity tests (Section 1.2)
|
|
- [ ] **M0.2:** Run Redis connectivity tests (Section 1.2)
|
|
- [ ] **M0.3:** Verify docker-dataplane network (Section 1.3)
|
|
- [ ] **M0.4:** Backup NPM configuration
|
|
- [ ] **M0.5:** Document current NPM forward auth status (should have auth on all hosts)
|
|
- [ ] **M0.6:** Remove forward auth from ALL NPM proxy hosts temporarily
|
|
- [ ] **M0.7:** Verify system resource availability (RAM, CPU, disk)
|
|
|
|
**Validation Checklist:**
|
|
```bash
|
|
# Run all validation commands
|
|
bash scripts/validate-authentik-prerequisites.sh # Create this script
|
|
```
|
|
|
|
**Expected Duration:** 15-30 minutes
|
|
|
|
**Rollback:** N/A (no changes made to running services)
|
|
|
|
**Backup Files:**
|
|
- `backups/npm-m0-$(date +%Y%m%d).json` - NPM config before changes
|
|
- `backups/docker-ps-m0-$(date +%Y%m%d).txt` - Container list
|
|
|
|
**Status:** ⏳ Not Started
|
|
|
|
**Issues Log:**
|
|
```
|
|
[Date] [Issue description] - [Resolution]
|
|
```
|
|
|
|
---
|
|
|
|
### Milestone 1: Authentik Deployment (Core Only)
|
|
|
|
**Objective:** Deploy Authentik server and worker containers, configure NPM proxy for auth.schweitz.net (WITHOUT forward auth).
|
|
|
|
**Dependencies:** M0 completed
|
|
|
|
**Tasks:**
|
|
- [ ] **M1.1:** Create `stacks/authentik.yml` with correct environment variables
|
|
- [ ] **M1.2:** Set AUTHENTIK_HOST, AUTHENTIK_COOKIE_DOMAIN, resource limits
|
|
- [ ] **M1.3:** Deploy Authentik stack via Portainer
|
|
- [ ] **M1.4:** Wait for containers to start (watch logs)
|
|
- [ ] **M1.5:** Verify database migrations completed
|
|
- [ ] **M1.6:** Update NPM proxy host for `auth.schweitz.net` (NO forward auth!)
|
|
- [ ] **M1.7:** Access https://auth.schweitz.net (should show Authentik setup wizard)
|
|
- [ ] **M1.8:** Complete initial setup wizard, create admin account
|
|
|
|
**Configuration Files:**
|
|
|
|
**`stacks/authentik.yml`:**
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
# Authentik Identity Provider (SSO)
|
|
# Purpose: Centralized authentication for all homelab services
|
|
# Ports: 9000 (web UI), 9443 (embedded outpost)
|
|
# GPU: No
|
|
# Storage: SSD (configs), PostgreSQL shared (user data)
|
|
|
|
services:
|
|
authentik-server:
|
|
image: ghcr.io/goauthentik/server:2024.8.4 # Pinned version (2024.10 has redirect loop issues)
|
|
container_name: authentik-server
|
|
restart: unless-stopped
|
|
command: server
|
|
environment:
|
|
# External URLs (CRITICAL for redirect loop prevention)
|
|
AUTHENTIK_HOST: https://auth.schweitz.net
|
|
AUTHENTIK_HOST_BROWSER: https://auth.schweitz.net
|
|
|
|
# Cookie settings (CRITICAL for SSO across subdomains)
|
|
AUTHENTIK_COOKIE_DOMAIN: .schweitz.net
|
|
AUTHENTIK_COOKIE_SAMESITE: lax
|
|
|
|
# SSL/TLS
|
|
AUTHENTIK_INSECURE: false
|
|
|
|
# PostgreSQL (shared)
|
|
AUTHENTIK_POSTGRESQL__HOST: postgres-shared
|
|
AUTHENTIK_POSTGRESQL__PORT: 5432
|
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
|
AUTHENTIK_POSTGRESQL__USER: authentik_user
|
|
AUTHENTIK_POSTGRESQL__PASSWORD: F//j0ktck7cX06Vfgh0YXceONOtlSsHvadqROICeDx8=
|
|
AUTHENTIK_POSTGRESQL__USE_PGBOUNCER: false
|
|
|
|
# Redis (shared)
|
|
AUTHENTIK_REDIS__HOST: redis-shared
|
|
AUTHENTIK_REDIS__PORT: 6379
|
|
AUTHENTIK_REDIS__DB: 0
|
|
|
|
# Secret key (generate with: openssl rand -base64 32)
|
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} # Store in .env file
|
|
|
|
# Resource optimization
|
|
AUTHENTIK_LOG_LEVEL: warning
|
|
AUTHENTIK_ERROR_REPORTING__ENABLED: false
|
|
AUTHENTIK_AVATARS: none
|
|
AUTHENTIK_FOOTER_LINKS: '[]'
|
|
|
|
# Embedded outpost configuration
|
|
AUTHENTIK_OUTPOSTS__DOCKER_IMAGE_BASE: "ghcr.io/goauthentik/%(type)s:%(version)s"
|
|
|
|
# Timezone
|
|
TZ: Europe/Amsterdam
|
|
|
|
ports:
|
|
- "9000:9000" # Web UI
|
|
- "9443:9443" # Embedded outpost (proxy provider)
|
|
|
|
volumes:
|
|
- /home/jpmschweitzer/docker-data/authentik/media:/media
|
|
- /home/jpmschweitzer/docker-data/authentik/custom-templates:/templates
|
|
|
|
networks:
|
|
- docker-dataplane
|
|
|
|
depends_on:
|
|
- postgres-shared
|
|
- redis-shared
|
|
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:9000/-/health/live/ || exit 1"]
|
|
start_period: 60s
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 512M
|
|
cpus: '0.5'
|
|
reservations:
|
|
memory: 256M
|
|
|
|
authentik-worker:
|
|
image: ghcr.io/goauthentik/server:2024.8.4 # Same version as server
|
|
container_name: authentik-worker
|
|
restart: unless-stopped
|
|
command: worker
|
|
environment:
|
|
# Same environment as server (MUST match exactly)
|
|
AUTHENTIK_HOST: https://auth.schweitz.net
|
|
AUTHENTIK_HOST_BROWSER: https://auth.schweitz.net
|
|
AUTHENTIK_COOKIE_DOMAIN: .schweitz.net
|
|
AUTHENTIK_COOKIE_SAMESITE: lax
|
|
AUTHENTIK_INSECURE: false
|
|
AUTHENTIK_POSTGRESQL__HOST: postgres-shared
|
|
AUTHENTIK_POSTGRESQL__PORT: 5432
|
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
|
AUTHENTIK_POSTGRESQL__USER: authentik_user
|
|
AUTHENTIK_POSTGRESQL__PASSWORD: F//j0ktck7cX06Vfgh0YXceONOtlSsHvadqROICeDx8=
|
|
AUTHENTIK_POSTGRESQL__USE_PGBOUNCER: false
|
|
AUTHENTIK_REDIS__HOST: redis-shared
|
|
AUTHENTIK_REDIS__PORT: 6379
|
|
AUTHENTIK_REDIS__DB: 0
|
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
|
|
AUTHENTIK_LOG_LEVEL: warning
|
|
AUTHENTIK_ERROR_REPORTING__ENABLED: false
|
|
TZ: Europe/Amsterdam
|
|
|
|
# Worker-specific configuration
|
|
AUTHENTIK_BOOTSTRAP_WORKERS: 1 # Single worker (homelab scale)
|
|
AUTHENTIK_WORKER__CONCURRENCY: 2 # 2 threads per worker
|
|
|
|
volumes:
|
|
- /home/jpmschweitzer/docker-data/authentik/media:/media
|
|
- /home/jpmschweitzer/docker-data/authentik/custom-templates:/templates
|
|
- /home/jpmschweitzer/docker-data/authentik/certs:/certs
|
|
- /var/run/docker.sock:/var/run/docker.sock # For outpost management
|
|
|
|
networks:
|
|
- docker-dataplane
|
|
|
|
depends_on:
|
|
- postgres-shared
|
|
- redis-shared
|
|
- authentik-server
|
|
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "ak healthcheck"]
|
|
start_period: 60s
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 384M
|
|
cpus: '0.3'
|
|
reservations:
|
|
memory: 128M
|
|
|
|
networks:
|
|
docker-dataplane:
|
|
external: true
|
|
name: docker-dataplane
|
|
|
|
# Setup Instructions:
|
|
#
|
|
# 1. Generate secret key:
|
|
# openssl rand -base64 32 > .env.authentik
|
|
# echo "AUTHENTIK_SECRET_KEY=<paste-key-here>" >> .env.authentik
|
|
#
|
|
# 2. Create directories:
|
|
# mkdir -p ~/docker-data/authentik/{media,custom-templates,certs}
|
|
#
|
|
# 3. Deploy stack:
|
|
# docker-compose -f stacks/authentik.yml up -d
|
|
#
|
|
# 4. Watch logs:
|
|
# docker logs -f authentik-server
|
|
# docker logs -f authentik-worker
|
|
#
|
|
# 5. Wait for migrations to complete (~2-3 minutes):
|
|
# docker logs authentik-server 2>&1 | grep "Applying migration"
|
|
#
|
|
# 6. Access web UI:
|
|
# https://auth.schweitz.net (should show setup wizard)
|
|
#
|
|
# 7. Complete setup wizard:
|
|
# - Email: admin@schweitz.net
|
|
# - Password: <secure-password>
|
|
# - Finish setup
|
|
#
|
|
# Monitoring:
|
|
#
|
|
# Memory usage:
|
|
# docker stats authentik-server authentik-worker --no-stream
|
|
#
|
|
# Database connectivity:
|
|
# docker exec authentik-server ak check
|
|
#
|
|
# Outpost status:
|
|
# curl http://authentik-server:9443/outpost.goauthentik.io/ping/
|
|
```
|
|
|
|
**Validation Commands:**
|
|
```bash
|
|
# M1.1: Check containers are running
|
|
docker ps | grep authentik
|
|
|
|
# M1.2: Check logs for errors
|
|
docker logs authentik-server 2>&1 | grep -iE "error|critical|fail" | tail -20
|
|
docker logs authentik-worker 2>&1 | grep -iE "error|critical|fail" | tail -20
|
|
|
|
# M1.3: Check database migrations completed
|
|
docker logs authentik-server 2>&1 | grep "Applying migration" | tail -10
|
|
docker logs authentik-server 2>&1 | grep "No migrations to apply" || echo "❌ Migrations still running"
|
|
|
|
# M1.4: Check health checks passing
|
|
docker inspect authentik-server | jq '.[0].State.Health.Status'
|
|
docker inspect authentik-worker | jq '.[0].State.Health.Status'
|
|
|
|
# M1.5: Check memory usage (should be under limits)
|
|
docker stats authentik-server authentik-worker --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
|
|
|
|
# M1.6: Check NPM proxy host for auth.schweitz.net
|
|
curl -I https://auth.schweitz.net
|
|
# Expected: 200 OK (Authentik setup wizard)
|
|
|
|
# M1.7: Check for redirect loops (should NOT redirect)
|
|
curl -v https://auth.schweitz.net 2>&1 | grep -c "Location:"
|
|
# Expected: 0 (or 1 if redirecting HTTP → HTTPS, which is fine)
|
|
|
|
# M1.8: Verify embedded outpost is accessible
|
|
docker exec -it authentik-server curl http://localhost:9443/outpost.goauthentik.io/ping/
|
|
# Expected: {"status": "ok"} or similar
|
|
```
|
|
|
|
**Success Criteria:**
|
|
- ✓ Both containers running (docker ps)
|
|
- ✓ Health checks passing (docker inspect)
|
|
- ✓ Memory usage < 700MB total
|
|
- ✓ Database migrations completed
|
|
- ✓ https://auth.schweitz.net accessible (200 OK, no redirect loop)
|
|
- ✓ Authentik setup wizard displayed
|
|
- ✓ Admin account created
|
|
|
|
**Expected Duration:** 30-60 minutes
|
|
|
|
**Rollback Procedure:**
|
|
```bash
|
|
# Stop and remove Authentik containers
|
|
docker-compose -f stacks/authentik.yml down
|
|
|
|
# Restore NPM configuration (if changed)
|
|
curl -X POST http://192.168.86.149:8000/api/restore \
|
|
-H "Content-Type: application/json" \
|
|
-d @backups/npm-m0-YYYYMMDD.json
|
|
|
|
# Verify NPM restored
|
|
curl -I https://auth.schweitz.net # Should return error (Authentik not running)
|
|
```
|
|
|
|
**Backup Files:**
|
|
- `backups/authentik-m1-$(date +%Y%m%d).yml` - Authentik stack config
|
|
- `backups/npm-m1-$(date +%Y%m%d).json` - NPM config after M1
|
|
- `backups/authentik-m1-env-$(date +%Y%m%d).txt` - Environment variables (REDACTED)
|
|
|
|
**Status:** ⏳ Not Started
|
|
|
|
**Issues Log:**
|
|
```
|
|
[Date] [Issue description] - [Resolution]
|
|
```
|
|
|
|
---
|
|
|
|
### Milestone 2: Google OAuth Integration
|
|
|
|
**Objective:** Configure Google as an authentication source in Authentik.
|
|
|
|
**Dependencies:** M1 completed successfully
|
|
|
|
**Tasks:**
|
|
- [ ] **M2.1:** Create Google Cloud Project (or use existing)
|
|
- [ ] **M2.2:** Configure OAuth consent screen
|
|
- [ ] **M2.3:** Create OAuth 2.0 client credentials
|
|
- [ ] **M2.4:** Add Google as social source in Authentik admin panel
|
|
- [ ] **M2.5:** Configure callback URLs
|
|
- [ ] **M2.6:** Test Google login with Workspace account
|
|
- [ ] **M2.7:** Test Google login with Gmail account
|
|
- [ ] **M2.8:** Verify user profile attributes synced
|
|
|
|
**Configuration:** See original plan Section 5.1.2 for detailed steps.
|
|
|
|
**Expected Duration:** 30-45 minutes
|
|
|
|
**Status:** ⏳ Not Started
|
|
|
|
---
|
|
|
|
### Milestone 3: Single Service Protection (Organizr Test)
|
|
|
|
**Objective:** Enable forward auth on ONE service (Organizr at home.schweitz.net) to validate SSO works end-to-end.
|
|
|
|
**Dependencies:** M2 completed successfully
|
|
|
|
**Configuration:** See original plan Section 5.2 for detailed steps.
|
|
|
|
**Expected Duration:** 60-90 minutes
|
|
|
|
**Status:** ⏳ Not Started
|
|
|
|
---
|
|
|
|
### Milestone 4: Core API Protection (FastAPI Native OIDC)
|
|
|
|
**Objective:** Protect Core API with FastAPI native OIDC token validation (bearer token authentication).
|
|
|
|
**Dependencies:** M3 completed successfully
|
|
|
|
**Status:** ✅ **COMPLETE** - Using forward auth (shares Organizr Proxy provider)
|
|
|
|
**Implementation Decision (2025-11-23):**
|
|
- Core API already protected with forward auth via NPM
|
|
- Shares "Organizr Proxy" provider with home.schweitz.net
|
|
- Authentication working correctly with Google OAuth
|
|
- Headers forwarded: X-authentik-username, X-authentik-email, X-authentik-groups, X-authentik-name, X-authentik-uid
|
|
- **Decision:** Keep current setup, defer separate admin provider to avoid complexity
|
|
- **Rationale:** Current implementation is secure and functional for homelab use case
|
|
|
|
**Configuration:**
|
|
- Provider: Organizr Proxy (shared)
|
|
- External host: https://api.schweitz.net
|
|
- Outpost: Standalone proxy (port 9445)
|
|
- Mode: forward_single
|
|
|
|
**Expected Duration:** ~~90-120 minutes~~ SKIPPED (already functional)
|
|
|
|
---
|
|
|
|
### Milestone 5: Remaining Services (Gradual Rollout)
|
|
|
|
**Objective:** Enable forward auth on remaining services, one at a time, testing each before proceeding.
|
|
|
|
**Dependencies:** M3 and M4 completed successfully
|
|
|
|
**Services to Protect:**
|
|
- Gitea (git.schweitz.net)
|
|
- Open WebUI (no external domain yet)
|
|
- Netdata (no external domain yet)
|
|
- Uptime Kuma (no external domain yet)
|
|
- AMP (amp.schweitz.net)
|
|
- Tatlock (tatlock.schweitz.net)
|
|
|
|
**Services EXCLUDED from SSO (Keep Native Auth):**
|
|
- ❌ **Jellyfin (media.schweitz.net)** - Better mobile app integration with native auth
|
|
- ❌ **code-server (code.schweitz.net)** - Better VS Code integration with native auth
|
|
- ❌ **Nextcloud (cloud.schweitz.net)** - Service disabled, SSO deferred until re-enabled
|
|
|
|
**Rationale for Exclusions:**
|
|
- Jellyfin and code-server have excellent native authentication
|
|
- Mobile apps and desktop clients work better with username/password
|
|
- SSO adds complexity without significant security benefit for these services
|
|
- Nextcloud is not currently in active use
|
|
|
|
**Expected Duration:** 3-6 hours (30-60 min per service)
|
|
|
|
**Status:** ⏳ Not Started
|
|
|
|
---
|
|
|
|
## Section 5: Testing & Validation
|
|
|
|
### 5.1 Automated Testing Scripts
|
|
|
|
**Create these scripts in `/scripts` directory:**
|
|
|
|
- `validate-authentik-prerequisites.sh` - Pre-deployment checks
|
|
- `test-redirect-flow.sh` - Test redirect loops
|
|
- `monitor-resources.sh` - Monitor memory/CPU usage
|
|
|
|
(Full script contents in original plan appendices)
|
|
|
|
---
|
|
|
|
## Section 6: Troubleshooting Guide
|
|
|
|
### 6.1 Redirect Loop Troubleshooting
|
|
|
|
**Common Causes & Fixes:**
|
|
|
|
| Cause | Fix |
|
|
|-------|-----|
|
|
| `auth.schweitz.net` has forward auth enabled | Remove forward auth from NPM config |
|
|
| `AUTHENTIK_HOST` not set or wrong | Set `AUTHENTIK_HOST=https://auth.schweitz.net` |
|
|
| Cookie domain mismatch | Set `AUTHENTIK_COOKIE_DOMAIN=.schweitz.net` |
|
|
| Outpost endpoint unreachable | Verify `curl http://authentik-server:9443/outpost.goauthentik.io/ping/` works |
|
|
|
|
### 6.2 Memory Usage Issues
|
|
|
|
**Common Causes & Fixes:**
|
|
|
|
| Cause | Fix |
|
|
|-------|-----|
|
|
| Too many Celery workers | Set `AUTHENTIK_BOOTSTRAP_WORKERS=1` |
|
|
| Too many threads per worker | Set `AUTHENTIK_WORKER__CONCURRENCY=2` |
|
|
| Memory leak | Restart containers |
|
|
|
|
(Full troubleshooting guide in original plan Section 6)
|
|
|
|
---
|
|
|
|
## Section 7: Rollback Procedures
|
|
|
|
### 7.1 Full Rollback
|
|
|
|
```bash
|
|
# Stop Authentik
|
|
docker-compose -f stacks/authentik.yml down -v
|
|
|
|
# Restore NPM config
|
|
curl -X POST http://192.168.86.149:8000/api/restore \
|
|
-H "Content-Type: application/json" \
|
|
-d @backups/npm-m0-YYYYMMDD.json
|
|
|
|
# Verify services accessible
|
|
curl -I https://api.schweitz.net
|
|
```
|
|
|
|
### 7.2 Partial Rollback (Single Service)
|
|
|
|
Restore NPM config for specific proxy host from milestone backup.
|
|
|
|
(Full rollback procedures in original plan Section 7)
|
|
|
|
---
|
|
|
|
## Section 8: Progress Tracking
|
|
|
|
### 8.1 Implementation Status
|
|
|
|
**Last Updated:** 2025-11-20
|
|
|
|
| Milestone | Status | Start Date | Complete Date | Duration | Issues |
|
|
|-----------|--------|------------|---------------|----------|--------|
|
|
| M0: Pre-deployment Validation | ⏳ Not Started | - | - | - | - |
|
|
| M1: Authentik Deployment | ⏳ Not Started | - | - | - | - |
|
|
| M2: Google OAuth | ⏳ Not Started | - | - | - | - |
|
|
| M3: Organizr SSO | ⏳ Not Started | - | - | - | - |
|
|
| M4: Core API OIDC | ⏳ Not Started | - | - | - | - |
|
|
| M5: Remaining Services | ⏳ Not Started | - | - | - | - |
|
|
|
|
**Legend:**
|
|
- ⏳ Not Started
|
|
- 🔄 In Progress
|
|
- ✅ Completed
|
|
- ⚠️ Issues/Blocked
|
|
- ❌ Failed
|
|
|
|
### 8.2 Detailed Progress Log
|
|
|
|
**Update this section as you progress through each milestone.**
|
|
|
|
**Template:**
|
|
```
|
|
### Milestone X: [Name]
|
|
|
|
**Start:** [YYYY-MM-DD HH:MM]
|
|
**Completed:** [YYYY-MM-DD HH:MM]
|
|
**Duration:** [Time]
|
|
|
|
**Tasks Completed:**
|
|
- [x] Task 1
|
|
- [x] Task 2
|
|
|
|
**Issues Encountered:**
|
|
1. **Issue:** [Description]
|
|
**Cause:** [Root cause]
|
|
**Solution:** [How fixed]
|
|
|
|
**Validation Results:**
|
|
- ✓ Item 1
|
|
- ✓ Item 2
|
|
|
|
**Backups Created:**
|
|
- backups/filename-mX-YYYYMMDD.ext
|
|
|
|
**Next Steps:**
|
|
- Proceed to Milestone X+1
|
|
```
|
|
|
|
### 8.3 Configuration Changelog
|
|
|
|
**Track all configuration changes:**
|
|
|
|
| Date | Component | Change | Reason | Rollback |
|
|
|------|-----------|--------|--------|----------|
|
|
| 2025-11-20 | Plan | Created v2.0 | Post-failure revision | N/A |
|
|
| - | - | - | - | - |
|
|
|
|
### 8.4 Lessons Learned (Real-Time)
|
|
|
|
**Add lessons as you encounter issues:**
|
|
|
|
```
|
|
[Date] [Milestone] [Lesson]
|
|
```
|
|
|
|
---
|
|
|
|
## Appendix A: Quick Reference Commands
|
|
|
|
### A.1 Authentik Management
|
|
|
|
```bash
|
|
# Check status
|
|
docker ps | grep authentik
|
|
docker logs authentik-server --tail 50
|
|
|
|
# Restart
|
|
docker restart authentik-server authentik-worker
|
|
|
|
# Check database
|
|
docker exec authentik-server ak check
|
|
|
|
# Run migrations
|
|
docker exec authentik-server ak migrate
|
|
|
|
# Check outpost
|
|
curl http://authentik-server:9443/outpost.goauthentik.io/ping/
|
|
```
|
|
|
|
### A.2 NPM Management
|
|
|
|
```bash
|
|
# Backup
|
|
curl -s http://192.168.86.149:8000/api/ > backups/npm-$(date +%Y%m%d-%H%M%S).json
|
|
|
|
# Test config
|
|
docker exec npm nginx -t
|
|
|
|
# Reload
|
|
docker exec npm nginx -s reload
|
|
```
|
|
|
|
---
|
|
|
|
## Appendix B: Environment Variables Reference
|
|
|
|
**Authentik Critical Variables:**
|
|
```bash
|
|
AUTHENTIK_HOST=https://auth.schweitz.net
|
|
AUTHENTIK_HOST_BROWSER=https://auth.schweitz.net
|
|
AUTHENTIK_COOKIE_DOMAIN=.schweitz.net
|
|
AUTHENTIK_COOKIE_SAMESITE=lax
|
|
AUTHENTIK_POSTGRESQL__HOST=postgres-shared
|
|
AUTHENTIK_REDIS__HOST=redis-shared
|
|
AUTHENTIK_LOG_LEVEL=warning
|
|
AUTHENTIK_BOOTSTRAP_WORKERS=1
|
|
AUTHENTIK_WORKER__CONCURRENCY=2
|
|
```
|
|
|
|
---
|
|
|
|
## Appendix C: Known Issues & Workarounds
|
|
|
|
### C.1 Authentik 2024.10.x Redirect Loop Bug
|
|
|
|
**Issue:** Version 2024.10 has redirect loop bug.
|
|
|
|
**Workaround:** Use version 2024.8.4 (pinned in authentik.yml).
|
|
|
|
**Reference:** https://github.com/goauthentik/authentik/issues/11883
|
|
|
|
---
|
|
|
|
**END OF SECURITY IMPLEMENTATION PLAN v2.0**
|
|
|
|
**Ready for Implementation:** Yes ✓
|
|
**Reviewed By:** Claude Code (Autonomous Analysis)
|
|
**Approved By:** [User - Pending]
|
|
|
|
*This plan is a living document. Update Section 8 (Progress Tracking) as you progress through milestones.*
|