Files
vps/docs/sso-integration-plan.md
service 1e1a528a5e Initial commit: VPS setup documentation
Add comprehensive documentation for VPS setup and configuration including:
- Project instructions
- VPS1 starting point configuration
- VPS1 current state documentation
- VPS1 todo list

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 07:43:24 +01:00

642 lines
20 KiB
Markdown

# SSO Integration Plan: Gitea & Immich with Netbird Zitadel
**Date:** 2026-01-25
**Status:** Planning Phase
**Identity Provider:** Netbird Zitadel (https://nb.phiiiil.de)
## Executive Summary
This plan details the integration of Gitea and Immich with the existing Netbird Zitadel Identity Provider for centralized Single Sign-On (SSO) authentication.
**Benefits:**
- Unified authentication across all services
- Centralized user management via Netbird dashboard
- No need to remember multiple passwords
- Secure OAuth2/OIDC flow with PKCE
- Easy user provisioning and deprovisioning
## Prerequisites
### Infrastructure ✅
- [x] Netbird running with Zitadel at https://nb.phiiiil.de
- [x] Gitea deployed at https://git.phiiiil.de (OAuth2 already enabled)
- [x] Immich deployed at https://immich.phiiiil.de
- [x] DNS records configured and SSL certificates active
- [x] OIDC discovery endpoint accessible: https://nb.phiiiil.de/.well-known/openid-configuration
### Access Required
- [ ] Netbird admin credentials (to access Zitadel console)
- [ ] Gitea admin credentials (user: `phil`, password: `j8bKvIl3AtIp5aTG`)
- [ ] Immich admin credentials
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────┐
│ User Browser │
└────────────────────┬────────────────────────────────────────┘
│ 1. Click "Login with SSO"
┌─────────────────────────────────────────────────────────────┐
│ Gitea/Immich (Application) │
│ - Redirects to Zitadel │
│ - Client ID & Client Secret │
└────────────────────┬────────────────────────────────────────┘
│ 2. OAuth2 Authorization Request
┌─────────────────────────────────────────────────────────────┐
│ Netbird Zitadel (Identity Provider) │
│ - Authenticates user │
│ - Issues authorization code │
│ - Returns to application with code │
└────────────────────┬────────────────────────────────────────┘
│ 3. Exchange code for tokens
┌─────────────────────────────────────────────────────────────┐
│ Application validates tokens & creates user session │
└─────────────────────────────────────────────────────────────┘
```
## Phase 1: Zitadel Configuration
### Step 1.1: Access Zitadel Console
1. Navigate to https://nb.phiiiil.de
2. Login with Netbird admin credentials
3. Access Zitadel console via https://nb.phiiiil.de/ui
**Note:** The first access may require setting up the Zitadel admin account if not already done.
### Step 1.2: Create Gitea OIDC Application
#### 1.2.1 Create Project
1. Go to **Projects****New Project**
2. Configure:
- **Name:** `Gitea`
- **Project Role:** Select/create appropriate role
3. Click **Create**
4. Note the **Project ID** for reference
#### 1.2.2 Create Application
1. Navigate to the new **Gitea** project
2. Go to **Applications****New**
3. Configure:
- **Application Name:** `gitea`
- **Application Type:** Web Application
- **Redirect URIs:**
- `https://git.phiiiil.de/user/oauth2/zitadel/callback`
- **Post Logout URIs:**
- `https://git.phiiiil.de/`
- **Authentication Method:** PKCE (recommended)
- **Scopes:** `openid profile email`
4. Click **Continue**
#### 1.2.3 Save Credentials
After creating, save the following in a secure location:
- **Client ID:** (will be displayed)
- **Client Secret:** (click "Reveal" to copy)
**Store these securely** - they will be needed for Gitea configuration.
### Step 1.3: Create Immich OIDC Application
#### 1.3.1 Create Project
1. Go to **Projects****New Project**
2. Configure:
- **Name:** `Immich`
- **Project Role:** Select/create appropriate role
3. Click **Create**
4. Note the **Project ID** for reference
#### 1.3.2 Create Application
1. Navigate to the new **Immich** project
2. Go to **Applications****New**
3. Configure:
- **Application Name:** `immich`
- **Application Type:** Web Application
- **Redirect URIs:**
- `https://immich.phiiiil.de/auth/login`
- `https://immich.phiiiil.de/user-settings`
- **Post Logout URIs:**
- `https://immich.phiiiil.de/`
- **Authentication Method:** PKCE
- **Scopes:** `openid profile email`
4. Click **Continue**
#### 1.3.3 Save Credentials
- **Client ID:** (will be displayed)
- **Client Secret:** (click "Reveal" to copy)
## Phase 2: Gitea Configuration
### Step 2.1: Access Gitea Admin Panel
1. Navigate to https://git.phiiiil.de
2. Login with admin credentials:
- **Username:** `phil`
- **Password:** `j8bKvIl3AtIp5aTG`
### Step 2.2: Configure OAuth2 Authentication
**Via Web UI:**
1. Go to **Administration** (gear icon → Authentication Sources)
2. Click **Add Authentication Source****OAuth2**
3. Configure:
```
Authentication Name: Netbird Zitadel
OAuth2 Provider: OpenID Connect
Client ID: [from Zitadel Step 1.2.3]
Client Secret: [from Zitadel Step 1.2.3]
OpenID Connect Discovery Endpoint:
https://nb.phiiiil.de/.well-known/openid-configuration
Auto-discover Email Address: ✅ Enabled
Scopes: openid profile email
Email Authentication Field: Email
Update Avatar: ✅ Enabled
Group Claims: (optional, leave empty)
```
4. Click **Create Authentication Source**
### Step 2.3: Configure User Settings
**Via Web UI:**
1. Go to **Site Administration** → **Authentication**
2. Enable:
- **Show "Sign In" button on login page**
- **Automatically create users for OAuth2**
- **Hide login form if only OAuth2 is available** (optional)
3. Click **Save**
**Verify Configuration:**
```bash
# Check Gitea logs for any OAuth errors
docker logs gitea | grep -i oauth
```
### Step 2.4: Test Gitea SSO
1. Logout of Gitea
2. Go to https://git.phiiiil.de
3. Click **Sign In with Netbird Zitadel**
4. You should be redirected to Zitadel login
5. Authenticate with Netbird credentials
6. Should be redirected back to Gitea, logged in
**Expected Result:**
- User is created automatically in Gitea
- Email address synced from Zitadel
- Avatar updated (if available in Zitadel)
## Phase 3: Immich Configuration
### Step 3.1: Access Immich Admin Panel
1. Navigate to https://immich.phiiiil.de
2. Login with admin credentials
### Step 3.2: Configure OAuth2
**Via Web UI:**
1. Go to **Administration** → **Settings** → **Authentication**
2. Under **OAuth**, click **Enable** or **Add OAuth**
3. Configure:
```
OAuth Button Display Name: Login with Netbird
OAuth Button Link URL: [auto-generated]
Client ID: [from Zitadel Step 1.3.3]
Client Secret: [from Zitadel Step 1.3.3]
Issuer URL: https://nb.phiiiil.de
Authorization Endpoint: https://nb.phiiiil.de/oauth/v2/authorize
Token Endpoint: https://nb.phiiiil.de/oauth/v2/token
User Info Endpoint: https://nb.phiiiil.de/oidc/v1/userinfo
Scope: openid profile email
Auto Registering: ✅ Enabled
Auto Linking: ✅ Enabled
Storage Label Claim: email
```
4. Click **Save**
**Alternative: Via Environment Variables**
Edit `/home/phil/docker/immich-app/.env` and add:
```bash
# OAuth2/OIDC Configuration
IMMICH_OAUTH_ENABLED=true
IMMICH_OAUTH_BUTTON_TEXT="Login with Netbird"
IMMICH_OAUTH_ISSUER_URL=https://nb.phiiiil.de
IMMICH_OAUTH_CLIENT_ID=[from Zitadel]
IMMICH_OAUTH_CLIENT_SECRET=[from Zitadel]
IMMICH_OAUTH_AUTO_REGISTER=true
IMMICH_OAUTH_STORAGE_LABEL_CLAIM=email
IMMICH_OAUTH_SCOPE=openid profile email
```
Then restart Immich:
```bash
cd /home/phil/docker/immich-app
docker compose restart immich-server
```
### Step 3.3: Test Immich SSO
1. Logout of Immich
2. Go to https://immich.phiiiil.de
3. Click **Login with Netbird**
4. Authenticate with Netbird credentials
5. Should be redirected back to Immich, logged in
**Expected Result:**
- User is created automatically in Immich
- Email address synced from Zitadel
- User can access their photo library
## Phase 4: Testing & Verification
### Step 4.1: Gitea Verification
**Test Checklist:**
- [ ] Login page shows "Sign In with Netbird Zitadel" button
- [ ] Clicking button redirects to Zitadel login
- [ ] After authentication, user is logged into Gitea
- [ ] User profile shows correct email from Zitadel
- [ ] User avatar is imported (if available)
- [ ] Logout works correctly
- [ ] Can login again with SSO
**Verify User Sync:**
```bash
# Check Gitea database for new user
docker exec -it gitea-db psql -U gitea -d gitea -c "SELECT * FROM user WHERE login_name LIKE '%@%';"
```
### Step 4.2: Immich Verification
**Test Checklist:**
- [ ] Login page shows "Login with Netbird" button
- [ ] Clicking button redirects to Zitadel login
- [ ] After authentication, user is logged into Immich
- [ ] User can access photos
- [ ] User settings show correct email from Zitadel
- [ ] Logout works correctly
- [ ] Can login again with SSO
**Verify User Creation:**
```bash
# Check Immich database for OAuth user
docker exec -it immich_postgres psql -U postgres -d immich -c "SELECT id, email, oauthId FROM \"user\" WHERE email LIKE '%@%';"
```
### Step 4.3: Cross-Service Testing
**Test that:**
- [ ] Logging into Zitadel automatically logs into both Gitea and Immich (single sign-on)
- [ ] Logout from one service doesn't affect other services
- [ ] New users created in Zitadel can access both applications
## Phase 5: Security Configuration
### Step 5.1: Enable HTTPS Only
**Gitea:**
- Already enforced via Caddy reverse proxy
- Ensure `GITEA__server__PROTOCOL=https` is set (should be)
**Immich:**
- Already enforced via Caddy reverse proxy
### Step 5.2: Configure Token Expiration
**In Zitadel:**
1. Go to **Settings** → **Token Configuration**
2. Set reasonable token lifetimes:
- **Access Token:** 1 hour
- **Refresh Token:** 30 days
- **ID Token:** 1 hour
### Step 5.3: Enable PKCE
**Verify both applications are using PKCE:**
- Gitea: ✅ Already configured in Zitadel
- Immich: ✅ Supported via OAuth2 flow
### Step 5.4: Review Scopes
**Minimal recommended scopes:**
- `openid` - Required for OIDC
- `profile` - User name and basic info
- `email` - Email address for user identification
**Optional scopes:**
- `groups` - Group membership (not currently used)
- `address` - Physical address (not needed)
- `phone` - Phone number (not needed)
## Phase 6: Backup & Rollback
### Pre-Integration Backup
**Before starting, run a full backup:**
```bash
/home/phil/docker/backup/backup.sh
```
**Verify backup completed:**
```bash
ls -lah /mnt/backup/latest/
```
### Rollback Procedures
**If Gitea SSO fails:**
1. Login with local admin account (`phil` / `j8bKvIl3AtIp5aTG`)
2. Go to **Administration** → **Authentication Sources**
3. Delete the Netbird Zitadel OAuth source
4. Users can still login with local passwords
**If Immich SSO fails:**
1. Login with local admin account
2. Go to **Administration** → **Settings** → **Authentication**
3. Disable OAuth or remove the configuration
4. Restart Immich:
```bash
cd /home/phil/docker/immich-app
docker compose restart immich-server
```
**Complete rollback:**
```bash
# Restore Gitea database
gunzip < /mnt/backup/latest/gitea-db.sql.gz | docker exec -i gitea-db psql -U gitea gitea
# Restore Immich database
gunzip < /mnt/backup/latest/immich-db.sql.gz | docker exec -i immich_postgres psql -U postgres immich
```
## Phase 7: User Migration
### Option A: Manual Migration (Recommended for Small Teams)
1. Create user accounts in Zitadel with same email addresses
2. Users login via SSO
3. Applications automatically create user accounts
4. Manual data association may be needed (repositories, photos, etc.)
### Option B: Automated Mapping
**For Gitea:**
- Set up email matching between Git local users and Zitadel users
- Enable **Automatically create users for OAuth2**
- First OAuth login will create new Gitea account
- Manual migration of repositories may be needed
**For Immich:**
- Enable **Auto Registering** and **Auto Linking**
- First OAuth login will create new Immich account
- **WARNING:** Photos are tied to user accounts - migration may be complex
- Consider testing with a test user first
## Phase 8: Documentation & Maintenance
### Step 8.1: Update Documentation
Update `/home/phil/Schreibtisch/Privat/vps/vps1-state-25012026.md`:
- Add SSO configuration section
- Document Client IDs (encrypted) and where they're stored
- Add troubleshooting section
Update `/home/phil/Schreibtisch/Privat/vps/docs/deployment-summary.md`:
- Mark OIDC SSO as completed
- Add SSO URLs to quick reference
### Step 8.2: Maintenance Tasks
**Monthly:**
- Review OAuth2 token usage in Zitadel
- Check for failed authentication attempts
- Review user access
**Quarterly:**
- Rotate client secrets (recommended)
- Review and update scopes
- Audit user access
## Implementation Checklist
### Pre-Implementation
- [ ] Create full backup of all databases
- [ ] Verify backup integrity
- [ ] Document current authentication state
- [ ] Prepare rollback procedures
### Zitadel Configuration
- [ ] Access Zitadel console
- [ ] Create Gitea project
- [ ] Create Gitea application
- [ ] Save Gitea Client ID and Secret
- [ ] Create Immich project
- [ ] Create Immich application
- [ ] Save Immich Client ID and Secret
### Gitea Integration
- [ ] Configure OAuth2 in Gitea admin
- [ ] Enable auto-user creation
- [ ] Test Gitea SSO login
- [ ] Verify user creation
- [ ] Test Gitea logout
### Immich Integration
- [ ] Configure OAuth2 in Immich admin
- [ ] Enable auto-user registration
- [ ] Test Immich SSO login
- [ ] Verify user creation
- [ ] Test Immich logout
### Testing & Verification
- [ ] Test Gitea SSO full flow
- [ ] Test Immich SSO full flow
- [ ] Test cross-service SSO
- [ ] Verify user data sync
- [ ] Test logout functionality
### Documentation
- [ ] Update vps1-state-25012026.md
- [ ] Update deployment-summary.md
- [ ] Document Client IDs securely
- [ ] Create user guide for SSO login
## Troubleshooting
### Issue: "Invalid redirect URI"
**Symptoms:**
- Error in Zitadel logs about redirect URI mismatch
- OAuth flow fails during redirect
**Solution:**
1. Check exact redirect URI in application logs
2. Compare with Zitadel application configuration
3. Ensure protocol (http vs https) matches
4. Ensure no trailing slashes
**Gitea correct URI:** `https://git.phiiiil.de/user/oauth2/zitadel/callback`
**Immich correct URI:** `https://immich.phiiiil.de/auth/login`
### Issue: "Client authentication failed"
**Symptoms:**
- Token endpoint returns 401 Unauthorized
- Error about invalid client_secret
**Solution:**
1. Verify Client ID matches exactly
2. Reveal and copy Client Secret again from Zitadel
3. Check for extra spaces or characters
4. Regenerate Client Secret in Zitadel if needed
### Issue: "User not created automatically"
**Symptoms:**
- OAuth login succeeds but no user created
- User sees "Access denied" or similar
**Solution:**
**Gitea:**
- Go to **Authentication** → **Enable "Automatically create users"**
- Check for email conflicts with existing users
**Immich:**
- Enable **Auto Registering** in OAuth settings
- Enable **Auto Linking** to match existing users by email
### Issue: "Discovery endpoint not accessible"
**Symptoms:**
- Application cannot fetch OIDC configuration
- Error connecting to `https://nb.phiiiil.de/.well-known/openid-configuration`
**Solution:**
1. Check Caddy is running: `docker ps | grep caddy`
2. Test endpoint manually: `curl https://nb.phiiiil.de/.well-known/openid-configuration`
3. Check Caddy logs: `docker logs netbird-caddy-1 | grep openid`
4. Verify firewall allows connection to port 443
### Issue: "Avatar not syncing"
**Symptoms:**
- User logs in successfully but avatar not updated
**Solution:**
**Gitea:**
- Enable **Update Avatar** in OAuth configuration
- Ensure Zitadel profile includes avatar URL
- Check Gitea logs for avatar fetch errors
**Immich:**
- Avatar may need manual upload after first login
- Immich doesn't always fetch avatar from IdP
## Success Criteria
The integration will be considered successful when:
1. **Gitea:**
- Users can login via "Sign In with Netbird Zitadel"
- User accounts are created automatically
- Email addresses are synced from Zitadel
- Existing functionality (repositories, SSH) still works
2. **Immich:**
- Users can login via "Login with Netbird"
- User accounts are created automatically
- Email addresses are synced from Zitadel
- Photo access and functionality preserved
3. **Security:**
- All authentication uses OAuth2/OIDC with PKCE
- HTTPS enforced for all communications
- Token lifetimes are reasonable
- No security warnings in browser console
4. **Usability:**
- Login process takes < 10 seconds
- Single sign-on works across services
- Logout works correctly
- User experience is intuitive
## Timeline Estimate
- **Phase 1 (Zitadel Config):** 30 minutes
- **Phase 2 (Gitea Config):** 20 minutes
- **Phase 3 (Immich Config):** 20 minutes
- **Phase 4 (Testing):** 30 minutes
- **Phase 5 (Security Config):** 15 minutes
- **Phase 6 (Backups):** 10 minutes
- **Phase 7 (User Migration):** Variable (depends on users)
- **Phase 8 (Documentation):** 30 minutes
**Total:** ~2.5 hours (excluding user migration)
## Post-Implementation Tasks
1. **Monitor logs** for first 24-48 hours:
```bash
# Gitea OAuth logs
docker logs gitea | grep -i oauth
# Immich OAuth logs
docker logs immich_server | grep -i oauth
# Caddy/OAuth routing logs
docker logs netbird-caddy-1 | grep -i oauth
```
2. **Check Zitadel dashboard** regularly:
- Active sessions
- Failed login attempts
- Token issuance
3. **User feedback:**
- Gather user experience feedback
- Document any issues or improvements needed
## Appendix: OAuth2 Endpoints Reference
**Zitadel (Netbird):**
- **Issuer:** `https://nb.phiiiil.de`
- **Discovery:** `https://nb.phiiiil.de/.well-known/openid-configuration`
- **Authorization:** `https://nb.phiiiil.de/oauth/v2/authorize`
- **Token:** `https://nb.phiiiil.de/oauth/v2/token`
- **UserInfo:** `https://nb.phiiiil.de/oidc/v1/userinfo`
- **JWKS:** `https://nb.phiiiil.de/oauth/v2/keys`
- **End Session:** `https://nb.phiiiil.de/oidc/v1/end_session`
**Application Redirect URIs:**
- **Gitea:** `https://git.phiiiil.de/user/oauth2/zitadel/callback`
- **Immich:** `https://immich.phiiiil.de/auth/login`
## Notes
- This plan assumes Netbird admin access is available
- Client secrets should be stored securely (consider using a password manager)
- Test with a test user first before migrating all users
- Immich user migration may require additional consideration for photo ownership
- Gitea SSH key access is independent of OAuth and continues to work
---
**Document Version:** 1.0
**Last Updated:** 2026-01-25
**Status:** Ready for Implementation