headscale/docker-dev/docker-compose-oidc-test.yml
Ryan Malloy 5abc3c87b2 OIDC groups implementation
- Add Groups field to User struct with JSON storage
- Include GetGroups() and SetGroups() helper methods
- Extract groups from OIDC claims in FromClaim()
- Add database migration 202509161200 for groups column
- Update config-example.yaml with groups scope
- Add comprehensive documentation and testing
2026-05-21 17:55:31 -06:00

152 lines
4.3 KiB
YAML

services:
# PostgreSQL database for Keycloak
postgres:
image: postgres:15-alpine
container_name: headscale-postgres
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
headscale-net:
ipv4_address: 10.99.0.5
# Keycloak OIDC provider
keycloak:
image: quay.io/keycloak/keycloak:23.0
container_name: headscale-keycloak
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: password
KC_HOSTNAME_STRICT: false
KC_HOSTNAME_STRICT_HTTPS: false
ports:
- "8280:8080" # Keycloak admin console
depends_on:
- postgres
networks:
headscale-net:
ipv4_address: 10.99.0.6
command: start-dev
volumes:
- ./keycloak-config:/opt/keycloak/data/import:ro
# Build Headscale with our OIDC groups changes
headscale:
build:
context: ..
dockerfile: Dockerfile.debug
container_name: headscale-server
volumes:
- ./headscale-config-oidc.yaml:/etc/headscale/config.yaml
- ./acl.hujson:/etc/headscale/acl.hujson
- headscale-data:/var/lib/headscale
ports:
- "8180:8080" # HTTP API
- "9090:9090" # Metrics
- "50443:50443" # gRPC
command: serve
restart: unless-stopped
networks:
headscale-net:
ipv4_address: 10.99.0.10
depends_on:
- keycloak
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
interval: 5s
timeout: 3s
retries: 5
start_period: 30s
# Headplane with OIDC configuration
headplane:
build:
context: ../../headplane
dockerfile: Dockerfile
container_name: headscale-headplane
ports:
- "3000:3000" # Headplane UI
environment:
- HEADPLANE_CONFIG_PATH=/app/config.yaml
volumes:
- ./headplane-config-oidc.yaml:/app/config.yaml:ro
networks:
headscale-net:
ipv4_address: 10.99.0.15
depends_on:
- headscale
restart: unless-stopped
# Test tailscale clients (unchanged)
tailscale-client1:
image: tailscale/tailscale:latest
container_name: tailscale-client1
hostname: client1
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- TS_STATE_DIR=/var/lib/tailscale
- TS_EXTRA_ARGS=--login-server=http://headscale:8080
- TS_HOSTNAME=client1
- TS_AUTHKEY=${TS_AUTHKEY_CLIENT1:-}
- TS_ACCEPT_ROUTES=true
- TS_USERSPACE=false
volumes:
- tailscale-client1-state:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
- ./scripts/client-init.sh:/usr/local/bin/client-init.sh:ro
networks:
headscale-net:
ipv4_address: 10.99.0.21
depends_on:
- headscale
restart: unless-stopped
command: sh -c "tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/var/run/tailscale/tailscaled.sock --tun=userspace-networking & sleep 5 && /usr/local/bin/client-init.sh client1 && wait"
tailscale-client2:
image: tailscale/tailscale:latest
container_name: tailscale-client2
hostname: client2
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- TS_STATE_DIR=/var/lib/tailscale
- TS_EXTRA_ARGS=--login-server=http://headscale:8080
- TS_HOSTNAME=client2
- TS_AUTHKEY=${TS_AUTHKEY_CLIENT2:-}
- TS_ACCEPT_ROUTES=true
- TS_USERSPACE=false
volumes:
- tailscale-client2-state:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
- ./scripts/client-init.sh:/usr/local/bin/client-init.sh:ro
networks:
headscale-net:
ipv4_address: 10.99.0.22
depends_on:
- headscale
restart: unless-stopped
command: sh -c "tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/var/run/tailscale/tailscaled.sock --tun=userspace-networking & sleep 5 && /usr/local/bin/client-init.sh client2 && wait"
networks:
headscale-net:
driver: bridge
ipam:
config:
- subnet: 10.99.0.0/24
gateway: 10.99.0.1
volumes:
headscale-data:
tailscale-client1-state:
tailscale-client2-state:
postgres-data: