Identity Stack Installation
This guide covers deploying the identity and authentication layer for RavenmaskOS, including Zitadel as the identity provider and OAuth2-proxy for service authentication.
Overview
The Identity Stack provides:
- Zitadel: Full-featured identity provider with OIDC/OAuth2 support
- OAuth2-proxy: Forward authentication proxy for protecting services
- Single Sign-On: Unified authentication across all platform services
Prerequisites
Before proceeding, ensure you have completed:
- Prerequisites - Base system setup
- Core Stack - Docker, Traefik, PostgreSQL, Redis
Zitadel Identity Provider
Create Zitadel Database
First, create a dedicated database for Zitadel:
docker exec -it postgres psql -U ravenhelm -d postgres -c "CREATE DATABASE zitadel OWNER ravenhelm;"
Generate Secrets
Generate the required secrets for Zitadel:
# Generate masterkey (32 bytes, base64 encoded)
ZITADEL_MASTERKEY=$(openssl rand -base64 32)
echo "ZITADEL_MASTERKEY=$ZITADEL_MASTERKEY" >> ~/ravenhelm/secrets/.env
# Generate admin password
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD=$(openssl rand -base64 24)
echo "ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD=$ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD" >> ~/ravenhelm/secrets/.env
Deploy Zitadel
Create ~/ravenhelm/services/zitadel/docker-compose.yml:
services:
zitadel:
container_name: zitadel
image: ghcr.io/zitadel/zitadel:latest
restart: unless-stopped
command: start-from-init --masterkeyFromEnv --tlsMode external
networks:
- ravenhelm_net
environment:
- ZITADEL_DATABASE_POSTGRES_HOST=postgres
- ZITADEL_DATABASE_POSTGRES_PORT=5432
- ZITADEL_DATABASE_POSTGRES_DATABASE=zitadel
- ZITADEL_DATABASE_POSTGRES_USER=ravenhelm
- ZITADEL_DATABASE_POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- ZITADEL_DATABASE_POSTGRES_SSL_MODE=disable
- ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE=disable
- ZITADEL_EXTERNALDOMAIN=auth.ravenhelm.dev
- ZITADEL_EXTERNALPORT=443
- ZITADEL_EXTERNALSECURE=true
- ZITADEL_MASTERKEY=${ZITADEL_MASTERKEY}
- ZITADEL_FIRSTINSTANCE_ORG_NAME=ravenhelm
- ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME=admin@ravenhelm.auth.ravenhelm.dev
- ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD=${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD}
labels:
- traefik.enable=true
- traefik.http.routers.zitadel.rule=Host(\`auth.ravenhelm.dev\`)
- traefik.http.routers.zitadel.entrypoints=websecure
- traefik.http.routers.zitadel.tls.certresolver=letsencrypt
- traefik.http.services.zitadel.loadbalancer.server.port=8080
networks:
ravenhelm_net:
external: true
Start Zitadel:
cd ~/ravenhelm/services/zitadel
docker compose --env-file ~/ravenhelm/secrets/.env up -d
Initial Configuration
- Access Zitadel at https://auth.ravenhelm.dev
- Log in with the admin credentials generated above
- Configure organization settings as needed
OAuth2-Proxy
OAuth2-proxy provides forward authentication for services that don't have native OIDC support.
Create OIDC Application in Zitadel
- In Zitadel, navigate to Projects → Create New Project
- Name it "OAuth2-Proxy"
- Create a new Web Application:
- Name: oauth2-proxy
- Redirect URIs:
https://oauth.ravenhelm.dev/oauth2/callback - Post-logout redirect:
https://oauth.ravenhelm.dev
- Note the Client ID and Client Secret
Deploy OAuth2-Proxy
Add secrets to your environment:
# Generate cookie secret (32 bytes)
OAUTH2_PROXY_COOKIE_SECRET=$(openssl rand -base64 32 | tr -d '\n')
echo "OAUTH2_PROXY_COOKIE_SECRET=$OAUTH2_PROXY_COOKIE_SECRET" >> ~/ravenhelm/secrets/.env
# Add Zitadel client credentials
echo "OAUTH2_PROXY_CLIENT_ID=<your-client-id>" >> ~/ravenhelm/secrets/.env
echo "OAUTH2_PROXY_CLIENT_SECRET=<your-client-secret>" >> ~/ravenhelm/secrets/.env
Create ~/ravenhelm/services/oauth2-proxy/docker-compose.yml:
services:
oauth2-proxy:
container_name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.7.1
restart: unless-stopped
networks:
- ravenhelm_net
command:
- --http-address=0.0.0.0:4180
- --reverse-proxy=true
- --provider=oidc
- --oidc-issuer-url=https://auth.ravenhelm.dev
- --client-id=${OAUTH2_PROXY_CLIENT_ID}
- --client-secret=${OAUTH2_PROXY_CLIENT_SECRET}
- --cookie-secret=${OAUTH2_PROXY_COOKIE_SECRET}
- --cookie-secure=true
- --cookie-domain=.ravenhelm.dev
- --email-domain=*
- --scope=openid profile email
- --skip-provider-button=true
- --whitelist-domain=.ravenhelm.dev
labels:
- traefik.enable=true
# Main OAuth endpoint
- traefik.http.routers.oauth2-proxy.rule=Host(\`oauth.ravenhelm.dev\`)
- traefik.http.routers.oauth2-proxy.entrypoints=websecure
- traefik.http.routers.oauth2-proxy.tls.certresolver=letsencrypt
- traefik.http.services.oauth2-proxy.loadbalancer.server.port=4180
# ForwardAuth middleware
- traefik.http.middlewares.oauth-auth.forwardauth.address=http://oauth2-proxy:4180/oauth2/auth
- traefik.http.middlewares.oauth-auth.forwardauth.trustForwardHeader=true
- traefik.http.middlewares.oauth-auth.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email,X-Auth-Request-Access-Token
networks:
ravenhelm_net:
external: true
Start OAuth2-proxy:
cd ~/ravenhelm/services/oauth2-proxy
docker compose --env-file ~/ravenhelm/secrets/.env up -d
Protecting Services
Using ForwardAuth Middleware
To protect any service with OAuth2 authentication, add the middleware to its Traefik labels:
labels:
- traefik.enable=true
- traefik.http.routers.myservice.rule=Host(\`myservice.ravenhelm.dev\`)
- traefik.http.routers.myservice.entrypoints=websecure
- traefik.http.routers.myservice.tls.certresolver=letsencrypt
- traefik.http.routers.myservice.middlewares=oauth-auth@docker
- traefik.http.services.myservice.loadbalancer.server.port=8080
The key addition is:
traefik.http.routers.myservice.middlewares=oauth-auth@docker
Services Using ForwardAuth
Current services protected by OAuth2-proxy:
- n8n.ravenhelm.dev
- grafana.ravenhelm.dev
- langfuse.ravenhelm.dev
- traefik.ravenhelm.dev (dashboard)
Verification
Test Zitadel
# Check Zitadel health
curl -s https://auth.ravenhelm.dev/debug/healthz
# Check OIDC discovery
curl -s https://auth.ravenhelm.dev/.well-known/openid-configuration | jq .
Test OAuth2-Proxy
# Check OAuth2-proxy ping
curl -s https://oauth.ravenhelm.dev/ping
Test ForwardAuth Flow
- Access a protected service (e.g., https://n8n.ravenhelm.dev)
- You should be redirected to Zitadel for authentication
- After login, you should be redirected back to the service
Troubleshooting
Zitadel Won't Start
Check database connectivity:
docker logs zitadel 2>&1 | grep -i error
docker exec -it postgres psql -U ravenhelm -d zitadel -c "SELECT 1;"
OAuth2-Proxy Redirect Issues
Verify OIDC configuration:
# Check issuer URL is accessible
curl -s https://auth.ravenhelm.dev/.well-known/openid-configuration
# Check OAuth2-proxy logs
docker logs oauth2-proxy 2>&1 | tail -50
Cookie Domain Issues
If authentication works but you're prompted again on different subdomains:
- Ensure
cookie-domain=.ravenhelm.dev(note the leading dot) - Verify
whitelist-domain=.ravenhelm.devis set
Next Steps
- Observability Stack - Deploy Grafana, Loki, Prometheus
- AI/ML Stack - Deploy Langfuse, Ollama, LangGraph