- 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.
11 KiB
11 KiB
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_URLenvironment variable is set - Run test script:
./test-authorization.sh - Note: JWT probably does NOT have
permissionsclaim 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
- Name:
- Click: Save
3.3: Customize Mapper (Optional)
Edit the script in the mapper to match your organization:
// 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
permissionsarray - 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
cd /srv/temporal/custom-server
go mod download
go mod tidy
- Run commands above
- Verify
go.sumis created - Check for any errors
✅ Phase 5: Update Docker Compose (10 mins)
5.1: Backup Current Config
cp compose.yaml compose.yaml.backup
- Create backup
5.2: Update Temporal Service
Edit compose.yaml:
temporal:
# OLD: image: temporalio/auto-setup:1.29.0
# NEW:
build:
context: ./custom-server
dockerfile: Dockerfile
# ... rest stays the same
- Change from
image:tobuild: - Point to
./custom-serverdirectory
5.3: Add Environment Variable
Make sure this exists in temporal service:
environment:
# ... existing vars
- TEMPORAL_AUTH_ISSUER_URL=${TEMPORAL_AUTH_ISSUER_URL}
- Verify
TEMPORAL_AUTH_ISSUER_URLis in environment - Verify it's defined in your
.envfile
✅ Phase 6: Build and Deploy (15 mins)
6.1: Build Custom Server
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:
docker-compose down
docker-compose up -d
If using Docker Swarm:
docker stack deploy temporal --detach=true -c compose.yaml
- Deploy updated stack
- Wait for services to start
6.3: Verify Deployment
# 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:
# 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
developmentnamespace - Create
stagingnamespace - Create
productionnamespace - Create any other namespaces you need
✅ Phase 8: Test Authorization (30 mins)
8.1: Test Admin User
- Login as user in
temporal-adminsgroup - 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-teamgroup - Verify can access
developmentnamespace - Verify can start workflow in
development✓ - Verify can access
productionnamespace (read-only) - Try to start workflow in
production- should FAIL ✗ - Verify error message: "PermissionDenied"
8.3: Test Viewer User
- Login as user in
viewersgroup - 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
# 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
permissionsclaim (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
permissionsClaimNamein config matches JWT claim - Check network connectivity to Keycloak
Issue: Server won't start
Check:
- Docker build completed successfully
go.modandgo.sumexist- 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_URLenvironment 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:
- ✅ Different users see different things in Temporal UI
- ✅ Users in
dev-teamcan manage dev namespace but not production - ✅ Users in
viewerscan only view, not modify - ✅ Users in
temporal-adminscan do everything - ✅ Users not in any group are denied access
- ✅ Server logs show authorization checks happening
- ✅ "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! 🚀