# OIDC Authentication and Role Mapping Headplane supports authentication via external identity providers using OpenID Connect (OIDC), with automatic role assignment based on group membership. This enables enterprise-grade, role-based access control integrated with your existing identity infrastructure. ## Features - **Single Sign-On (SSO)**: Seamless authentication with popular identity providers - **Automatic Role Assignment**: Users receive appropriate roles based on OIDC group membership - **Zero-Trust Security**: New users get minimal access until proper groups are assigned - **Dynamic Updates**: User roles update automatically on each login - **Configurable Mapping**: Customize which groups map to which roles for your organization ## Basic Configuration ### 1. Identity Provider Setup First, configure your identity provider to work with Headplane: === "Keycloak" 1. Create a new client for Headplane 2. Set client protocol to `openid-connect` 3. Set access type to `confidential` 4. Add redirect URI: `https://your-headplane.com/admin/oidc/callback` 5. Configure group membership mapper (see [Group Configuration](#group-configuration)) === "Azure AD" 1. Create new App Registration 2. Add redirect URI: `https://your-headplane.com/admin/oidc/callback` 3. Enable ID tokens 4. Configure API permissions for `GroupMember.Read.All` 5. Add groups claim to ID tokens === "Okta" 1. Create new Web Application 2. Add redirect URI: `https://your-headplane.com/admin/oidc/callback` 3. Configure group claims in token 4. Set grant types to Authorization Code ### 2. Headplane Configuration Configure OIDC in your `config.yaml`: ```yaml oidc: # OIDC provider configuration issuer: "https://your-provider.com/realm" client_id: "headplane-client" client_secret: "your-client-secret" # Include groups scope for role mapping scope: "openid email profile groups" # Headplane callback URL redirect_uri: "https://your-headplane.com/admin/oidc/callback" # API key for Headscale communication headscale_api_key: "your-headscale-api-key" # Optional: Disable API key login (force OIDC only) disable_api_key_login: false ``` ### 3. Headscale Configuration Ensure Headscale is configured to extract and store OIDC groups: ```yaml oidc: issuer: "https://your-provider.com/realm" client_id: "headscale-client" client_secret: "your-client-secret" scope: ["openid", "profile", "email", "groups"] # Include groups ``` ## Role Mapping ### Default Role Hierarchy Headplane uses a hierarchical role system where the highest privilege group determines the final role: 1. **Owner** - Full system access including user management 2. **Admin** - Administrative access to all features 3. **Network Admin** - Network configuration and routing 4. **IT Admin** - Machine and user management 5. **Auditor** - Read-only access for compliance 6. **Member** - Zero capabilities (no UI access) ### Configuring Role Mapping Add role mapping configuration to automatically assign roles based on OIDC groups: ```yaml oidc: # ... other OIDC configuration ... # Custom role mapping for your organization role_mapping: owner: ["ceo", "cto", "headplane-owners"] admin: ["it-admins", "platform-team", "administrators"] network_admin: ["network-team", "devops", "infrastructure"] it_admin: ["helpdesk", "support-team", "it-staff"] auditor: ["compliance", "audit-team", "security"] ``` ### Group Matching Groups are matched using several strategies: 1. **Exact Match**: Group name exactly matches mapping configuration 2. **Case Insensitive**: `Admin`, `admin`, and `ADMIN` all match 3. **Partial Match**: Groups containing keywords like `admin`, `network`, `audit` ### Example Role Mappings by Organization Type === "Corporate IT" ```yaml role_mapping: owner: ["cto", "it-director"] admin: ["senior-admin", "platform-lead"] network_admin: ["network-ops", "infrastructure"] it_admin: ["helpdesk", "desktop-support"] auditor: ["compliance", "security-team"] ``` === "Healthcare" ```yaml role_mapping: owner: ["chief-information-officer"] admin: ["hipaa-admin", "system-admin"] network_admin: ["clinical-infrastructure"] it_admin: ["medical-devices", "clinical-support"] auditor: ["hipaa-compliance", "privacy-officer"] ``` === "Financial Services" ```yaml role_mapping: owner: ["compliance-officer", "risk-management"] admin: ["fintech-admin", "trading-systems"] network_admin: ["market-data", "trading-infrastructure"] it_admin: ["client-support", "operations"] auditor: ["sox-audit", "regulatory-compliance"] ``` ## Group Configuration ### Keycloak Group Setup 1. **Create Groups**: Create groups in Keycloak that match your role mapping 2. **Group Membership Mapper**: - Name: `groups` - Mapper Type: `Group Membership` - Token Claim Name: `groups` - Add to ID token: ✓ - Add to access token: ✓ - Add to userinfo: ✓ - Full group path: ✗ (recommended) ### Azure AD Group Setup 1. **Create Security Groups**: Create groups in Azure AD 2. **Configure Group Claims**: - Go to Token Configuration - Add groups claim - Select "Security groups" - Include in ID tokens and Access tokens ### Okta Group Setup 1. **Create Groups**: Create groups in Okta 2. **Configure Claims**: - Go to Claims (ID Token) - Add claim named `groups` - Value type: Groups - Filter: Matches regex `.*` ## Security Model ### Zero-Trust Approach - **Default Deny**: New users receive `member` role with zero capabilities - **Explicit Allow**: Only users with recognized groups get elevated privileges - **Regular Validation**: Group membership checked on every login - **Audit Trail**: All role assignments logged for compliance ### First User Bootstrap The first OIDC user automatically receives the `owner` role regardless of group membership, ensuring administrative access is available for initial setup. ### Role Capabilities | Role | Capabilities | |------|-------------| | **Owner** | Full access + user management + system configuration | | **Admin** | All features except owner-level user management | | **Network Admin** | Network configuration, DNS, routing, machine management | | **IT Admin** | Machine management, user support, limited network access | | **Auditor** | Read-only access to all features for compliance | | **Member** | No UI access (can only use Tailscale client) | ## Advanced Configuration ### Custom Profile Picture Sources Choose where profile pictures are sourced from: ```yaml oidc: # Use OIDC provider pictures (default) profile_picture_source: "oidc" # Or use Gravatar based on email profile_picture_source: "gravatar" ``` ### Extra Authentication Parameters Pass additional parameters to the authorization endpoint: ```yaml oidc: extra_params: prompt: "select_account" # Force account selection domain_hint: "example.com" # Azure AD domain hint acr_values: "mfa" # Request multi-factor auth ``` ### Token Endpoint Configuration Customize how tokens are exchanged: ```yaml oidc: # Method for client authentication token_endpoint_auth_method: "client_secret_post" # or "client_secret_basic" # Manual endpoint configuration (if discovery fails) authorization_endpoint: "https://provider.com/auth" token_endpoint: "https://provider.com/token" userinfo_endpoint: "https://provider.com/userinfo" ``` ## Monitoring and Troubleshooting ### Enable Debug Logging Set environment variable for detailed OIDC logs: ```bash HEADPLANE_DEBUG_LOG=true ``` ### Common Issues **Groups not appearing in roles:** - Verify `groups` scope is included in OIDC configuration - Check identity provider group mapper configuration - Ensure user is member of mapped groups **Wrong role assigned:** - Review role mapping configuration for group name matching - Check for case sensitivity issues - Verify group hierarchy (highest privilege wins) **First login fails:** - Ensure redirect URI matches exactly in identity provider - Check client secret is correct - Verify Headscale API key is valid and has sufficient permissions ### Validation Steps 1. **Test OIDC Flow**: Use identity provider's test tools to verify token contents 2. **Check Groups**: Verify `groups` claim appears in ID token or UserInfo response 3. **Review Logs**: Check Headplane logs for role assignment messages 4. **Database Check**: Verify groups are stored in Headplane user database ## Migration from Manual Roles ### Gradual Migration Strategy 1. **Deploy with Feature Disabled**: Deploy OIDC role mapping but keep manual roles 2. **Test with Pilot Users**: Enable role mapping for select test users 3. **Validate Mappings**: Ensure all groups map to expected roles 4. **Full Rollout**: Enable role mapping for all users 5. **Cleanup**: Remove manual role assignments after validation ### Backup and Rollback Before enabling OIDC role mapping: ```bash # Backup current user roles sqlite3 /var/lib/headplane/headplane.db \ "SELECT id, sub, caps FROM users;" > user_roles_backup.sql # Rollback if needed sqlite3 /var/lib/headplane/headplane.db < user_roles_backup.sql ``` ## Integration with Headscale Headplane's OIDC role mapping works in conjunction with Headscale's OIDC group storage: 1. **Headscale** extracts groups from OIDC claims and stores them in the database 2. **Headplane** reads groups from Headscale users and maps them to roles 3. **Dynamic Updates** ensure role changes take effect on next login 4. **Consistent State** between Headscale groups and Headplane roles This integration provides a complete enterprise identity solution while maintaining separation of concerns between the VPN control plane (Headscale) and management interface (Headplane). For more information about Headscale OIDC configuration, see the [Headscale OIDC documentation](https://headscale.net/ref/oidc/).