This project demonstrates how to integrate HashiCorp Vault with Keycloak for automated client secret management. It includes scripts for:
- Creating realms and clients in Keycloak
- Storing client secrets in HashiCorp Vault
- Rotating client secrets automatically
- Testing authentication with client secrets from Vault
- Demo Flask application showing integration in action
- Docker and Docker Compose
- Bash shell (for Linux/macOS) or Git Bash/WSL (for Windows)
# Clone the repository
git clone https://github.com/AdityaPrakash2/AutoKeyRotation.git
cd AutoKeyRotation
# Create your environment file from the example
cp .env.example .env
# Edit the .env file to set secure passwords for production
nano .env # or use your preferred editor
# Start all services in the background
# Please allow 60-120 seconds after running this command to ensure all components are fully setup!
docker-compose up -d
# Check running containers
docker ps
# View logs
docker-compose logs -f
# View logs for a specific service
docker-compose logs -f keycloak
docker-compose logs -f vault
docker-compose logs -f flask-app
docker-compose logs -f client-secret-rotation
# Stop all services
docker-compose downThe project consists of several components that work together:
- Keycloak - Identity and access management server
- HashiCorp Vault - Secret management server
- Client Secret Rotation Service - Alpine-based container that manages client secret rotation
- Flask Demo App - Web application that demonstrates the integration
- PostgreSQL - Database for Keycloak
- URL: http://localhost:5001/
- Features:
- Login with Keycloak credentials:
- Username:
test-user - Password:
password
- Username:
- System Status Check (only visible after login)
- Direct Token Retrieval (only visible after login)
- Proper logout functionality
- Login with Keycloak credentials:
- URL: http://localhost:8080/admin/
- Admin Credentials:
- Username: The value of
KEYCLOAK_ADMINfrom your .env file (default:admin) - Password: The value of
KEYCLOAK_ADMIN_PASSWORDfrom your .env file (default:admin)
- Username: The value of
- Key areas to explore:
- Realms > fresh-realm > Clients > fresh-client
- Client settings and credentials
- URL: http://localhost:8201/ui/
- Root Token: The value of
VAULT_DEV_ROOT_TOKEN_IDfrom your .env file (default:root) - Key areas to explore:
- Secrets > kv > keycloak > clients > fresh-realm > fresh-client
- Secret version history shows the rotation history
.
├── docker-compose.yml # Docker services configuration
├── README.md # This documentation
├── ROADMAP.md # Future development plans
├── client-app/ # Demo Flask application
│ ├── app.py # Flask application code
│ ├── Dockerfile # Flask app container definition
│ ├── requirements.txt # Python dependencies
│ └── templates/ # HTML templates for the web UI
├── scripts/ # Core automation scripts
│ ├── auto-initialize.sh # Main initialization script
│ ├── cleanup-realms.sh # Cleans up unnecessary realms
│ ├── create-fresh-realm.sh # Creates realm and client in Keycloak
│ ├── cron-rotate-client-secret.sh # Called by cron for rotation
│ ├── init-vault.sh # Initializes Vault
│ ├── rotate-client-secret.sh # Rotates client secrets
│ ├── setup-vault-integration-fresh.sh # Sets up Vault integration
│ └── update-client-for-webapp.sh # Updates client for web application
└── vault/ # Vault configuration files
-
The rotation process:
- Retrieves the current client secret from both Keycloak and Vault
- Verifies they match to ensure consistency
- Generates a new client secret
- Updates the client secret in Keycloak
- Stores the new secret in Vault
- Tests authentication with the new secret
- Verifies the old secret no longer works
-
Automation:
- A cron job runs daily at 2 AM to rotate client secrets
- Logs are stored in the client_rotation_logs volume
- Secrets are rotated without disrupting client applications (they retrieve the latest secrets from Vault)
-
The Flask app demonstrates proper integration:
- Retrieves the client secret from Vault before authenticating
- Uses separate URLs for internal communication vs. browser redirects
- Properly handles login and logout flows with Keycloak
- Demonstrates extracting user info from JWT tokens
- Implements session cleanup during shutdown
-
Security features:
- API endpoints are protected and require authentication
- Only authenticated users can see system status and token options
- Proper session management with cleanup
To manually rotate the client secret:
docker exec client-secret-rotation /scripts/rotate-client-secret.shTo manually clear all Keycloak sessions:
docker exec client-secret-rotation /scripts/clear-keycloak-sessions.shIf you encounter "invalid_client" errors:
- Check the Keycloak logs:
docker-compose logs keycloak - Verify that the client secrets match between Keycloak and Vault
- Make sure the client is correctly configured in Keycloak (non-public, client credentials enabled)
- Try clearing all sessions:
docker exec client-secret-rotation /scripts/clear-keycloak-sessions.sh - Restart the environment:
docker-compose restart
If you're still logged in after restarting containers with docker-compose down and docker-compose up:
- Flask sessions are stored in browser cookies, and Keycloak sessions may persist in the database
- To completely clear all sessions, run:
docker exec client-secret-rotation /scripts/clear-keycloak-sessions.sh - Additionally, clear your browser cookies for the application domain
- Each restart of the Flask app generates a new secret key, which should invalidate existing sessions
If Vault integration is not working:
- Check Vault's accessibility:
curl http://localhost:8201/v1/sys/health - Verify the Vault token has the correct permissions
- Ensure the secret path is correct
- Check that the KV secrets engine is enabled in Vault
If the Flask demo app is not working properly:
- Check the logs:
docker-compose logs flask-app - Try logging out and clearing sessions:
docker exec client-secret-rotation /scripts/clear-keycloak-sessions.sh - Verify the environment variables in the Docker Compose file
If you're running this project on Windows, you might encounter issues with shell script line endings. Windows uses CRLF line endings, but the scripts need to use LF line endings to run correctly in Docker containers.
A helper batch file is provided to convert scripts to the correct format:
- Install
dos2unixvia Git Bash, WSL, or Chocolatey - Run the
prepare-scripts-for-windows.batfile - Restart your containers if they were already running
Alternatively, you can manually convert the scripts:
# Using Git Bash or WSL
find ./scripts -type f -name "*.sh" -exec dos2unix {} \;The repository includes a .gitattributes file that helps manage line endings correctly. If you're cloning the repository, Git should handle line endings automatically.
- This demo uses the Vault root token and Keycloak admin credentials for simplicity
- In production:
- Use proper access controls and policies in Vault
- Rotate Vault tokens regularly
- Use TLS for all connections between components
This project uses environment variables for configuration to avoid hardcoding sensitive information. The main configuration is loaded from the .env file, which is not included in version control for security reasons.
- Copy the example configuration:
cp .env.example .env - Edit the
.envfile to set appropriate values for your environment - For production deployments, ensure you use strong, unique passwords
- Database Configuration: Controls PostgreSQL database access
- Keycloak Configuration: Sets admin credentials and database access
- Vault Configuration: Configures Vault tokens and access
- Flask App Configuration: Controls the demo application settings
In production environments, consider using a secrets management solution like HashiCorp Vault or AWS Secrets Manager to handle these variables rather than an .env file.