567 lines
12 KiB
Markdown
567 lines
12 KiB
Markdown
# Deployment Guide
|
|
|
|
Complete guide for deploying the OIDC Identity Provider in both development and production environments.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Development Deployment](#development-deployment)
|
|
2. [Production Deployment](#production-deployment)
|
|
3. [Management Commands](#management-commands)
|
|
4. [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Development Deployment
|
|
|
|
### Quick Start
|
|
|
|
The fastest way to get the OIDC server running for development and testing.
|
|
|
|
#### Step 1: Get the Code
|
|
|
|
```bash
|
|
git clone <your-repo-url> wlkns_auth
|
|
cd wlkns_auth
|
|
```
|
|
|
|
#### Step 2: Configure Environment
|
|
|
|
```bash
|
|
# Copy the production environment template
|
|
cp .env.production .env
|
|
|
|
# Edit if needed (default works for local development)
|
|
nano .env
|
|
```
|
|
|
|
For local development, the default `OIDC_ISSUER=http://localhost:5000` works fine.
|
|
|
|
#### Step 3: Deploy with Docker
|
|
|
|
```bash
|
|
# Build and start services
|
|
docker-compose -f docker-compose.prod.yml up -d
|
|
|
|
# Or use the deployment script
|
|
./deploy.sh
|
|
```
|
|
|
|
#### Step 4: Verify Deployment
|
|
|
|
**Check service status:**
|
|
```bash
|
|
docker-compose -f docker-compose.prod.yml ps
|
|
```
|
|
|
|
**Test health endpoint:**
|
|
```bash
|
|
curl http://localhost:5000/health
|
|
```
|
|
|
|
Expected response:
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"database": "healthy",
|
|
"timestamp": "2025-11-27T09:19:54.558214",
|
|
"version": "1.0.0"
|
|
}
|
|
```
|
|
|
|
### Access Information
|
|
|
|
**OIDC Server:**
|
|
- Base URL: http://localhost:5000
|
|
- Discovery: http://localhost:5000/.well-known/openid-configuration
|
|
- Admin Panel: http://localhost:5000/admin/login
|
|
|
|
**Default Credentials:**
|
|
|
|
*Admin User:*
|
|
- Username: `admin`
|
|
- Password: `admin123`
|
|
- Role: admin
|
|
- Permissions: read:data, write:data, manage:users, manage:settings
|
|
|
|
*Test User:*
|
|
- Username: `test`
|
|
- Password: `test123`
|
|
- Role: user
|
|
- Permissions: read:data
|
|
|
|
**⚠️ IMPORTANT:** Change the admin password immediately after first login!
|
|
|
|
**Default OIDC Client:**
|
|
- Client ID: `test-client`
|
|
- Client Secret: (generated in `.env`)
|
|
- Redirect URIs: `http://localhost:8080/callback`
|
|
- Allowed Scopes: openid, profile, email
|
|
|
|
### Development Testing
|
|
|
|
**1. Test OIDC Discovery:**
|
|
```bash
|
|
curl http://localhost:5000/.well-known/openid-configuration
|
|
```
|
|
|
|
**2. Test Admin Login:**
|
|
1. Open http://localhost:5000/admin/login in browser
|
|
2. Login with `admin` / `admin123`
|
|
3. You should see the admin dashboard
|
|
|
|
**3. Test User Registration:**
|
|
1. Open http://localhost:5000/register
|
|
2. Create a new user account
|
|
3. Login at http://localhost:5000/login
|
|
|
|
**4. Test OIDC Flow (Optional):**
|
|
```bash
|
|
# In a separate terminal
|
|
python3 test_client.py
|
|
```
|
|
Then open http://localhost:8080 and click "Mit OIDC einloggen"
|
|
|
|
---
|
|
|
|
## Production Deployment
|
|
|
|
### Prerequisites
|
|
|
|
- A server with Docker and Docker Compose installed
|
|
- A domain name pointing to your server's IP address
|
|
- Basic familiarity with the command line
|
|
- Ports 80 and 443 open if exposing to the internet
|
|
|
|
### Step 1: Get the Code
|
|
|
|
```bash
|
|
git clone <your-repo-url> wlkns_auth
|
|
cd wlkns_auth
|
|
```
|
|
|
|
### Step 2: Configure the Environment
|
|
|
|
Copy the production environment template:
|
|
|
|
```bash
|
|
cp .env.production .env
|
|
```
|
|
|
|
**Required: Set your public domain:**
|
|
|
|
```bash
|
|
nano .env
|
|
```
|
|
|
|
Change the `OIDC_ISSUER` to your server's public URL:
|
|
```bash
|
|
# Example: OIDC_ISSUER=https://auth.yourdomain.com
|
|
OIDC_ISSUER=https://auth.example.com
|
|
```
|
|
|
|
**Security Checklist:**
|
|
- ✅ Generate new `SECRET_KEY` (done automatically in `.env.production`)
|
|
- ✅ Use strong `POSTGRES_PASSWORD` (done automatically)
|
|
- ✅ Set proper `OIDC_ISSUER` with your domain
|
|
- ✅ Review token lifetimes (`ACCESS_TOKEN_LIFETIME`, etc.)
|
|
|
|
### Step 3: Deploy the Application
|
|
|
|
Run the deployment script:
|
|
|
|
```bash
|
|
./deploy.sh
|
|
```
|
|
|
|
This will:
|
|
1. Build Docker images
|
|
2. Start OIDC server and PostgreSQL
|
|
3. Apply database migrations
|
|
4. Seed initial data
|
|
|
|
### Step 4: Secure the Admin Account
|
|
|
|
**CRITICAL:** Change the default admin password immediately!
|
|
|
|
1. Navigate to `https://<your-domain>/admin/login`
|
|
2. Log in with default credentials:
|
|
- Username: `admin`
|
|
- Password: `admin123`
|
|
3. Go to user list → Edit admin user → Set a strong password
|
|
|
|
### Advanced Production Scenarios
|
|
|
|
#### Scenario A: Using an Existing Nginx Reverse Proxy
|
|
|
|
If you already have Nginx running and want it to manage SSL:
|
|
|
|
1. **Deploy the OIDC Server** following Steps 1-3 above
|
|
|
|
2. **Configure Nginx** with this server block:
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name auth.yourdomain.com;
|
|
|
|
# Your SSL certificate configuration
|
|
ssl_certificate /path/to/your/fullchain.pem;
|
|
ssl_certificate_key /path/to/your/privkey.pem;
|
|
|
|
# SSL hardening (recommended)
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
ssl_prefer_server_ciphers on;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:5000;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
}
|
|
}
|
|
```
|
|
|
|
3. **Test and Reload Nginx:**
|
|
|
|
```bash
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
#### Scenario B: Manual Deployment (Without Docker)
|
|
|
|
While Docker is recommended, you can run the application manually:
|
|
|
|
**1. Install Dependencies:**
|
|
```bash
|
|
# Create virtual environment
|
|
python3 -m venv venv
|
|
source venv/bin/activate
|
|
|
|
# Install dependencies
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
**2. Configure Environment:**
|
|
Create a `.env` file with these required variables:
|
|
```bash
|
|
FLASK_APP=oidc_server.py
|
|
FLASK_ENV=production
|
|
DATABASE_URL=postgresql://user:password@localhost:5432/oidc_db
|
|
OIDC_ISSUER=https://auth.yourdomain.com
|
|
SECRET_KEY=<generate-random-secret>
|
|
```
|
|
|
|
**3. Run Database Migrations:**
|
|
```bash
|
|
flask db upgrade
|
|
flask seed
|
|
```
|
|
|
|
**4. Start the Server:**
|
|
```bash
|
|
# For production, use Gunicorn
|
|
gunicorn --bind 0.0.0.0:5000 "oidc_server:app"
|
|
|
|
# Or with workers
|
|
gunicorn --workers 4 --bind 0.0.0.0:5000 "oidc_server:app"
|
|
```
|
|
|
|
---
|
|
|
|
## Management Commands
|
|
|
|
### Service Control
|
|
|
|
```bash
|
|
# View logs (all services)
|
|
docker-compose -f docker-compose.prod.yml logs -f
|
|
|
|
# View logs (specific service)
|
|
docker-compose -f docker-compose.prod.yml logs -f oidc_server
|
|
docker-compose -f docker-compose.prod.yml logs -f postgres
|
|
|
|
# Stop services
|
|
docker-compose -f docker-compose.prod.yml down
|
|
|
|
# Start services
|
|
docker-compose -f docker-compose.prod.yml up -d
|
|
|
|
# Restart services
|
|
docker-compose -f docker-compose.prod.yml restart
|
|
|
|
# Rebuild and restart
|
|
docker-compose -f docker-compose.prod.yml up -d --build
|
|
```
|
|
|
|
### Database Operations
|
|
|
|
**Run Migrations:**
|
|
```bash
|
|
docker exec -e FLASK_APP=oidc_server.py oidc_server flask db upgrade
|
|
```
|
|
|
|
**Seed Database:**
|
|
```bash
|
|
docker exec -e FLASK_APP=oidc_server.py oidc_server flask seed
|
|
```
|
|
|
|
**Access PostgreSQL:**
|
|
```bash
|
|
docker exec -it oidc_postgres psql -U oidc_user -d oidc_db
|
|
```
|
|
|
|
**Query Users:**
|
|
```bash
|
|
docker exec oidc_postgres psql -U oidc_user -d oidc_db -c "SELECT username, email, is_admin, role FROM users;"
|
|
```
|
|
|
|
**Create Database Backup:**
|
|
```bash
|
|
# Create backup directory
|
|
mkdir -p backups
|
|
|
|
# Create compressed backup
|
|
docker exec oidc_postgres pg_dump -U oidc_user -d oidc_db | gzip > backups/oidc_backup_$(date +%Y%m%d_%H%M%S).sql.gz
|
|
```
|
|
|
|
**Restore from Backup:**
|
|
```bash
|
|
# Stop the application
|
|
docker-compose -f docker-compose.prod.yml down
|
|
|
|
# Start only PostgreSQL
|
|
docker-compose -f docker-compose.prod.yml up -d postgres
|
|
|
|
# Restore backup
|
|
gunzip -c backups/oidc_backup_20251127_120000.sql.gz | docker exec -i oidc_postgres psql -U oidc_user -d oidc_db
|
|
|
|
# Start all services
|
|
docker-compose -f docker-compose.prod.yml up -d
|
|
```
|
|
|
|
### Updating the Application
|
|
|
|
To update to the latest version:
|
|
|
|
```bash
|
|
# Pull latest code
|
|
git pull
|
|
|
|
# Rebuild and restart
|
|
docker-compose -f docker-compose.prod.yml up -d --build
|
|
|
|
# Apply any new migrations
|
|
docker exec -e FLASK_APP=oidc_server.py oidc_server flask db upgrade
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Services Won't Start
|
|
|
|
```bash
|
|
# Check logs for errors
|
|
docker-compose -f docker-compose.prod.yml logs
|
|
|
|
# Check if ports are already in use
|
|
sudo netstat -tlnp | grep 5000
|
|
sudo netstat -tlnp | grep 5432
|
|
|
|
# Check Docker service status
|
|
sudo systemctl status docker
|
|
```
|
|
|
|
### Database Connection Issues
|
|
|
|
```bash
|
|
# Verify PostgreSQL is healthy
|
|
docker-compose -f docker-compose.prod.yml ps postgres
|
|
|
|
# Test database connection
|
|
docker exec oidc_postgres pg_isready -U oidc_user -d oidc_db
|
|
|
|
# Check database logs
|
|
docker-compose -f docker-compose.prod.yml logs postgres
|
|
```
|
|
|
|
### "Bad Gateway" from Nginx
|
|
|
|
This usually means the OIDC server container is not running:
|
|
|
|
```bash
|
|
# Check container status
|
|
docker-compose -f docker-compose.prod.yml ps
|
|
|
|
# View OIDC server logs
|
|
docker-compose -f docker-compose.prod.yml logs oidc_server
|
|
|
|
# Restart the service
|
|
docker-compose -f docker-compose.prod.yml restart oidc_server
|
|
```
|
|
|
|
### "Invalid Credentials" on Login
|
|
|
|
```bash
|
|
# Ensure database was seeded
|
|
docker exec -e FLASK_APP=oidc_server.py oidc_server flask seed
|
|
|
|
# Check if users exist
|
|
docker exec oidc_postgres psql -U oidc_user -d oidc_db -c "SELECT * FROM users;"
|
|
|
|
# Verify default password hasn't been changed
|
|
```
|
|
|
|
### Container Keeps Restarting
|
|
|
|
```bash
|
|
# Check container logs for errors
|
|
docker logs oidc_server --tail=100
|
|
|
|
# Common issues:
|
|
# - Missing environment variables
|
|
# - Database connection failure
|
|
# - Syntax errors in Python files
|
|
# - Missing JWT keys
|
|
|
|
# Check environment variables
|
|
docker exec oidc_server env | grep FLASK
|
|
```
|
|
|
|
### "Invalid Redirect URI" Error
|
|
|
|
Make sure the `redirect_uri` your client application is using is listed in that client's configuration in the admin dashboard.
|
|
|
|
```bash
|
|
# Check client configuration
|
|
docker exec oidc_postgres psql -U oidc_user -d oidc_db -c "SELECT client_id, redirect_uris FROM clients;"
|
|
```
|
|
|
|
### "Invalid Client ID" Error
|
|
|
|
Ensure the `client_id` is correct and the client exists:
|
|
|
|
```bash
|
|
# List all clients
|
|
docker exec oidc_postgres psql -U oidc_user -d oidc_db -c "SELECT * FROM clients;"
|
|
```
|
|
|
|
---
|
|
|
|
## OIDC Endpoints Reference
|
|
|
|
### Discovery Document
|
|
```
|
|
GET http://localhost:5000/.well-known/openid-configuration
|
|
```
|
|
|
|
### Authorization Endpoint
|
|
```
|
|
GET http://localhost:5000/authorize
|
|
```
|
|
Parameters:
|
|
- `client_id`: Client identifier
|
|
- `redirect_uri`: Callback URL
|
|
- `response_type`: `code`
|
|
- `scope`: `openid profile email`
|
|
- `state`: CSRF protection token
|
|
|
|
### Token Endpoint
|
|
```
|
|
POST http://localhost:5000/token
|
|
```
|
|
Parameters:
|
|
- `grant_type`: `authorization_code`
|
|
- `code`: Authorization code
|
|
- `redirect_uri`: Same as authorization
|
|
- `client_id`: Client identifier
|
|
- `client_secret`: Client secret
|
|
|
|
### UserInfo Endpoint
|
|
```
|
|
GET http://localhost:5000/userinfo
|
|
Authorization: Bearer <access_token>
|
|
```
|
|
|
|
### Health Check
|
|
```
|
|
GET http://localhost:5000/health
|
|
```
|
|
|
|
---
|
|
|
|
## Security Checklist
|
|
|
|
### Production Security
|
|
|
|
- ✅ Change default admin password
|
|
- ✅ Use HTTPS (via Nginx reverse proxy)
|
|
- ✅ Set strong `SECRET_KEY`
|
|
- ✅ Use strong database passwords
|
|
- ✅ Enable firewall (only expose 80/443)
|
|
- ✅ Regular database backups
|
|
- ✅ Keep Docker images updated
|
|
- ✅ Review audit logs regularly
|
|
- ✅ Configure rate limiting appropriately
|
|
- ✅ Use environment variables for secrets
|
|
|
|
### Active Security Features
|
|
|
|
- bcrypt password hashing
|
|
- RS256 JWT signing
|
|
- Session security (HttpOnly, SameSite)
|
|
- Rate limiting on login endpoints
|
|
- Audit logging
|
|
- Non-root Docker user
|
|
- Strong generated secrets
|
|
|
|
---
|
|
|
|
## What's Working
|
|
|
|
✅ Docker Compose deployment
|
|
✅ PostgreSQL database with persistence
|
|
✅ User authentication (bcrypt hashing)
|
|
✅ Admin panel with CRUD operations
|
|
✅ OIDC discovery endpoint
|
|
✅ Authorization endpoint
|
|
✅ Token endpoint
|
|
✅ UserInfo endpoint
|
|
✅ Health check endpoint
|
|
✅ Rate limiting
|
|
✅ Audit logging
|
|
✅ Database migrations
|
|
✅ Multi-client support
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
### Immediate Actions
|
|
|
|
1. Change default admin password
|
|
2. Set up HTTPS with reverse proxy
|
|
3. Configure automated database backups
|
|
4. Set up monitoring and log aggregation
|
|
|
|
### Optional Improvements
|
|
|
|
1. Fix JWKS endpoint (known issue with public key format)
|
|
2. Implement refresh tokens
|
|
3. Add PKCE support for public clients
|
|
4. Add email verification
|
|
5. Implement 2FA/MFA
|
|
6. Set up automated testing
|
|
|
|
---
|
|
|
|
For more information, see:
|
|
- [Architecture Documentation](architecture.md)
|
|
- [Testing Guide](testing.md)
|
|
- [Project Roadmap](todo.md)
|