first commit
This commit is contained in:
566
docs/deployment.md
Normal file
566
docs/deployment.md
Normal file
@ -0,0 +1,566 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user