Skip to main content

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:

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

  1. Access Zitadel at https://auth.ravenhelm.dev
  2. Log in with the admin credentials generated above
  3. 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

  1. In Zitadel, navigate to ProjectsCreate New Project
  2. Name it "OAuth2-Proxy"
  3. Create a new Web Application:
    • Name: oauth2-proxy
    • Redirect URIs: https://oauth.ravenhelm.dev/oauth2/callback
    • Post-logout redirect: https://oauth.ravenhelm.dev
  4. 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

  1. Access a protected service (e.g., https://n8n.ravenhelm.dev)
  2. You should be redirected to Zitadel for authentication
  3. 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

If authentication works but you're prompted again on different subdomains:

  • Ensure cookie-domain=.ravenhelm.dev (note the leading dot)
  • Verify whitelist-domain=.ravenhelm.dev is set

Next Steps