Files
temporal/IMPLEMENTATION_CHECKLIST.md
Christian Galo 02b4ec9ee3 Add JWT-based authorization support for Temporal server with Keycloak integration
- Create QUICK_REFERENCE.md for a concise guide on setting up temporal authorization.
- Add README_AUTHORIZATION.md detailing the implementation steps and common issues.
- Introduce REVERSE_PROXY_APPROACH.md as an alternative method for authorization using a reverse proxy.
- Implement Dockerfile for building a custom Temporal server with authorization features.
- Add main.go to initialize the custom Temporal server with JWT authorization.
- Create example-keycloak-mapper.json for mapping Keycloak groups to Temporal permissions.
- Add development.yaml for configuring the Temporal server with JWT settings.
- Implement test-authorization.sh script to verify JWT token claims and Temporal server access.
- Include go.mod for managing Go dependencies in the custom server.
- Document troubleshooting steps and customization options in README.md.
2025-10-24 02:10:54 +00:00

444 lines
11 KiB
Markdown

# Temporal Authorization Implementation Checklist
Use this checklist to implement authorization step-by-step.
## ✅ Phase 1: Understanding (15 mins)
- [ ] Read `README_AUTHORIZATION.md` (high-level overview)
- [ ] Review `DIAGRAMS.md` (understand the flow)
- [ ] Read `QUICK_REFERENCE.md` (understand permission format)
- [ ] Understand the concept: Groups → Permissions → Allow/Deny
**Key Concept**: Users in Keycloak groups get permissions like `"namespace:role"` in their JWT, which Temporal uses to decide what they can do.
---
## ✅ Phase 2: Verify Current Setup (15 mins)
- [ ] Verify Temporal UI authentication is working
- [ ] Test that you can login via Keycloak
- [ ] Confirm `TEMPORAL_AUTH_ISSUER_URL` environment variable is set
- [ ] Run test script: `./test-authorization.sh`
- [ ] Note: JWT probably does NOT have `permissions` claim yet (that's OK)
**Expected Result**: You can login, but JWT doesn't have permissions yet.
---
## ✅ Phase 3: Configure Keycloak (30 mins)
### 3.1: Create Groups
Login to Keycloak Admin Console:
- [ ] Navigate to: Groups
- [ ] Create group: `temporal-admins`
- [ ] Create group: `dev-team`
- [ ] Create group: `ops-team`
- [ ] Create group: `viewers`
### 3.2: Add Protocol Mapper
- [ ] Navigate to: Clients → [your-temporal-ui-client]
- [ ] Go to: Client Scopes tab
- [ ] Select the client scope (usually named same as client)
- [ ] Click: Mappers tab
- [ ] Click: Add mapper → By configuration
- [ ] Select: Script Mapper
- [ ] Configure:
- Name: `temporal-permissions`
- Mapper Type: `Script Mapper`
- Token Claim Name: `permissions`
- Claim JSON Type: `JSON`
- Add to ID token: `ON`
- Add to access token: `ON`
- Add to userinfo: `ON`
- Multivalued: `ON`
- Script: Copy from `custom-server/example-keycloak-mapper.json`
- [ ] Click: Save
### 3.3: Customize Mapper (Optional)
Edit the script in the mapper to match your organization:
```javascript
// Example: Map your groups to permissions
if (groupName === 'your-admin-group') {
permissions.add('temporal-system:admin');
}
else if (groupName === 'your-dev-group') {
permissions.add('development:write');
permissions.add('staging:write');
}
// ... etc
```
- [ ] Customize group-to-permission mappings if needed
- [ ] Save changes
### 3.4: Assign Users to Groups
- [ ] Navigate to: Users
- [ ] Select a test user
- [ ] Go to: Groups tab
- [ ] Click: Join Group
- [ ] Add user to `dev-team` (or another group)
- [ ] Repeat for other test users
### 3.5: Verify JWT
- [ ] Run test script again: `./test-authorization.sh`
- [ ] Verify JWT now contains `permissions` array
- [ ] Verify permissions match expected format: `"namespace:role"`
**Expected Result**: JWT contains permissions like `["development:write", "staging:write"]`
---
## ✅ Phase 4: Prepare Custom Server (15 mins)
### 4.1: Review Configuration
- [ ] Review `custom-server/config/development.yaml`
- [ ] Verify JWKS URL format: `https://your-keycloak.com/realms/your-realm/protocol/openid-connect/certs`
- [ ] Update if your realm name is different
### 4.2: Review Server Code
- [ ] Review `custom-server/main.go`
- [ ] Understand: It uses Temporal's default ClaimMapper and Authorizer
- [ ] No code changes needed for basic setup
### 4.3: Create go.sum
```bash
cd /srv/temporal/custom-server
go mod download
go mod tidy
```
- [ ] Run commands above
- [ ] Verify `go.sum` is created
- [ ] Check for any errors
---
## ✅ Phase 5: Update Docker Compose (10 mins)
### 5.1: Backup Current Config
```bash
cp compose.yaml compose.yaml.backup
```
- [ ] Create backup
### 5.2: Update Temporal Service
Edit `compose.yaml`:
```yaml
temporal:
# OLD: image: temporalio/auto-setup:1.29.0
# NEW:
build:
context: ./custom-server
dockerfile: Dockerfile
# ... rest stays the same
```
- [ ] Change from `image:` to `build:`
- [ ] Point to `./custom-server` directory
### 5.3: Add Environment Variable
Make sure this exists in temporal service:
```yaml
environment:
# ... existing vars
- TEMPORAL_AUTH_ISSUER_URL=${TEMPORAL_AUTH_ISSUER_URL}
```
- [ ] Verify `TEMPORAL_AUTH_ISSUER_URL` is in environment
- [ ] Verify it's defined in your `.env` file
---
## ✅ Phase 6: Build and Deploy (15 mins)
### 6.1: Build Custom Server
```bash
cd /srv/temporal
docker-compose build temporal
```
- [ ] Run build command
- [ ] Wait for build to complete (may take 5-10 mins first time)
- [ ] Check for errors
### 6.2: Deploy
#### If using Docker Compose:
```bash
docker-compose down
docker-compose up -d
```
#### If using Docker Swarm:
```bash
docker stack deploy temporal --detach=true -c compose.yaml
```
- [ ] Deploy updated stack
- [ ] Wait for services to start
### 6.3: Verify Deployment
```bash
# Check logs
docker-compose logs temporal
# OR
docker service logs temporal_temporal
# Look for:
# "Starting Temporal Server with JWT Authorization..."
# "All services are started"
```
- [ ] Check logs for startup
- [ ] Verify no errors
- [ ] Confirm server is running
---
## ✅ Phase 7: Create Namespaces (5 mins)
Create namespaces that match your permission names:
```bash
# As admin user (in temporal-admins group)
docker exec -it <temporal-container> tctl namespace register development
docker exec -it <temporal-container> tctl namespace register staging
docker exec -it <temporal-container> tctl namespace register production
```
- [ ] Create `development` namespace
- [ ] Create `staging` namespace
- [ ] Create `production` namespace
- [ ] Create any other namespaces you need
---
## ✅ Phase 8: Test Authorization (30 mins)
### 8.1: Test Admin User
- [ ] Login as user in `temporal-admins` group
- [ ] Verify can access all namespaces
- [ ] Verify can start workflows
- [ ] Verify can terminate workflows
- [ ] Verify can see all operations
### 8.2: Test Developer User
- [ ] Login as user in `dev-team` group
- [ ] Verify can access `development` namespace
- [ ] Verify can start workflow in `development`
- [ ] Verify can access `production` namespace (read-only)
- [ ] Try to start workflow in `production` - should FAIL ✗
- [ ] Verify error message: "PermissionDenied"
### 8.3: Test Viewer User
- [ ] Login as user in `viewers` group
- [ ] Verify can view workflows in all namespaces
- [ ] Try to start any workflow - should FAIL ✗
- [ ] Try to terminate workflow - should FAIL ✗
- [ ] Verify can only perform read operations
### 8.4: Test No-Access User
- [ ] Login as user NOT in any Temporal groups
- [ ] Try to access any namespace
- [ ] Should see: PermissionDenied or no data
### 8.5: Verify Logs
```bash
# Check authorization decisions in logs
docker-compose logs temporal | grep -i "authoriz"
```
- [ ] Check logs show authorization checks
- [ ] Look for Allow/Deny decisions
- [ ] Verify permissions are being extracted from JWT
---
## ✅ Phase 9: Production Hardening (Optional)
### 9.1: Security
- [ ] Use HTTPS for Keycloak (if not already)
- [ ] Use HTTPS for Temporal UI (if not already)
- [ ] Verify JWT tokens have short expiration (15-60 mins)
- [ ] Set up key rotation in Keycloak
- [ ] Review Temporal audit logging
### 9.2: Monitoring
- [ ] Add authorization metrics to monitoring
- [ ] Set up alerts for frequent PermissionDenied errors
- [ ] Monitor JWT validation failures
### 9.3: Documentation
- [ ] Document your permission scheme for team
- [ ] Create onboarding guide for new users
- [ ] Document which groups map to which permissions
- [ ] Create troubleshooting guide
---
## ✅ Phase 10: Maintenance
### 10.1: Adding New Users
- [ ] Add user to Keycloak
- [ ] Assign to appropriate group
- [ ] User can immediately login with correct permissions
### 10.2: Changing Permissions
- [ ] Move user to different group in Keycloak
- [ ] User gets new permissions on next login
- [ ] (JWT refresh may take up to token expiration time)
### 10.3: Adding New Namespaces
- [ ] Create namespace in Temporal
- [ ] Update Keycloak mapper script to include new namespace
- [ ] Users in appropriate groups get access
---
## ❌ Troubleshooting
If things go wrong, check:
### Issue: "PermissionDenied" for all users
**Check**:
- [ ] JWT contains `permissions` claim (run `./test-authorization.sh`)
- [ ] Permissions format is correct: `"namespace:role"`
- [ ] JWKS URL is accessible from Temporal server
- [ ] Temporal server logs show JWT validation success
**Fix**:
- Review Keycloak mapper configuration
- Verify `permissionsClaimName` in config matches JWT claim
- Check network connectivity to Keycloak
### Issue: Server won't start
**Check**:
- [ ] Docker build completed successfully
- [ ] `go.mod` and `go.sum` exist
- [ ] Configuration YAML is valid
- [ ] Environment variables are set
**Fix**:
- Check server logs: `docker logs <container>`
- Verify YAML syntax: `yamllint custom-server/config/development.yaml`
- Rebuild: `docker-compose build --no-cache temporal`
### Issue: JWT signature validation fails
**Check**:
- [ ] JWKS endpoint is correct
- [ ] JWKS endpoint is accessible from container
- [ ] Token hasn't expired
- [ ] Issuer matches expected value
**Fix**:
- Test JWKS: `curl https://keycloak.com/realms/realm/protocol/openid-connect/certs`
- Verify `TEMPORAL_AUTH_ISSUER_URL` environment variable
- Check Temporal can reach Keycloak (network/firewall)
### Issue: UI can't connect to server
**Check**:
- [ ] Temporal server is running
- [ ] No errors in server logs
- [ ] UI can reach server (network)
- [ ] JWT is being passed from UI to server
**Fix**:
- Restart UI: `docker-compose restart ui`
- Check UI logs for auth errors
- Verify UI environment variables are correct
---
## 📊 Success Criteria
You'll know it's working when:
1. ✅ Different users see different things in Temporal UI
2. ✅ Users in `dev-team` can manage dev namespace but not production
3. ✅ Users in `viewers` can only view, not modify
4. ✅ Users in `temporal-admins` can do everything
5. ✅ Users not in any group are denied access
6. ✅ Server logs show authorization checks happening
7. ✅ "PermissionDenied" errors appear for unauthorized actions
---
## 📚 Reference
- **Full Guide**: `AUTHORIZATION_GUIDE.md`
- **Quick Reference**: `QUICK_REFERENCE.md`
- **Flow Diagrams**: `DIAGRAMS.md`
- **Test Script**: `./test-authorization.sh`
- **Alternative Approach**: `REVERSE_PROXY_APPROACH.md`
---
## ⏱️ Time Tracking
- [ ] Phase 1: Understanding (15 mins)
- [ ] Phase 2: Verify Setup (15 mins)
- [ ] Phase 3: Configure Keycloak (30 mins)
- [ ] Phase 4: Prepare Server (15 mins)
- [ ] Phase 5: Update Compose (10 mins)
- [ ] Phase 6: Build & Deploy (15 mins)
- [ ] Phase 7: Create Namespaces (5 mins)
- [ ] Phase 8: Test (30 mins)
**Total**: ~2.5 hours
---
## 🎯 Current Status
Track your progress:
- [ ] Started implementation
- [ ] Keycloak configured
- [ ] Server built
- [ ] Server deployed
- [ ] Basic testing done
- [ ] All test cases passing
- [ ] Production ready
- [ ] Documentation complete
Last updated: _______________
---
Good luck with your implementation! 🚀