- 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.
444 lines
11 KiB
Markdown
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! 🚀
|