# 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 tctl namespace register development docker exec -it tctl namespace register staging docker exec -it 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 ` - 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! 🚀