This project demonstrates the ability to use Postgres as user storage provider of Keycloak with cloud-native runtime configuration support and separated database architecture.
Important: This project now uses separated databases for better security and maintainability:
- Keycloak Internal Database: Stores realms, clients, tokens, sessions (Port 5433)
- User Storage Database: Contains your external user data for federation (Port 5434)
- β Runtime Configuration: Environment variables read at runtime (no build-time injection)
- β Cloud Ready: Native support for environment-based configuration
- β Docker Hub Compatible: Generic images that work across all environments
- β 12-Factor App Compliant: Follows modern cloud-native principles
- β CI/CD Friendly: "Build once, deploy everywhere" approach
- β
View-Based Access: Uses
v_oidc_usersview for secure, read-only data access - β Read-Only Operations: All write operations (INSERT, UPDATE, DELETE) are disabled
- β
Minimal Permissions: Dedicated
oidc_userwith SELECT-only database permissions - β Column Filtering: Only OIDC-required fields exposed through database view
- β User Validation: Only validated users accessible through OIDC authentication
The following software is required to work build it locally:
- Git 2.2.1 or later
- Docker Engine or Docker Desktop 1.9 or later
- Maven 3.8.5 or later
- Java 17 or later
See the links above for installation instructions on your platform. You can verify the versions are installed and running:
$ git --version
$ curl -V
$ mvn -version
$ docker --version
$ java --version
# Environment variables for secure view-based access
DB_USER=oidc_user
DB_PASSWORD=your_secure_password
DB_AUTHUSER_TABLE=v_oidc_usersBenefits:
- Enhanced security through PostgreSQL view filtering
- Read-only access prevents accidental data modification
- Only validated users are accessible through OIDC
- Minimal database permissions for the application user
# Environment variables for direct table access
DB_USER=obp
DB_PASSWORD=f
DB_AUTHUSER_TABLE=authuserSee the configuration examples below for detailed setup instructions.
Postgres - database for which we want to store User Federation.
Keycloak - KC container with custom certificate, for use over https. The container is described in Dockerfile.
The project includes GitHub Actions workflows for automated builds and deployments:
- Automated container builds on pushes to main branch
- Multi-architecture support with alternative Dockerfiles
- Dependency updates via Dependabot
- Container signing with Cosign for security
The project includes a comprehensive OBP Theme that transforms Keycloak's login experience to match the Open Bank Project Portal design system:
- Modern Dark Theme: Elegant glassmorphism UI with backdrop blur effects
- OBP Branding: Official logos, colors, and typography (Plus Jakarta Sans)
- Portal Design Consistency: Matches OBP Portal's visual identity and user experience
- OKLCH Color System: Modern color palette with primary (dark blue/gray) and secondary (teal/green) colors
- Responsive Design: Mobile-first approach optimized for all devices
- Accessibility Features: WCAG 2.1 compliance with high contrast support
- Internationalization: Multi-language support with customizable messages
The project supports two deployment modes:
- CI/CD Deployment (always build & replace - automated environments):
# Standard CI/CD deployment $ ./development/run-local-postgres-cicd.sh # Themed CI/CD deployment $ ./development/run-local-postgres-cicd.sh --themed
themes/obp/
βββ theme.properties # Theme configuration
βββ login/ # Login theme files
β βββ login.ftl # Custom login template
β βββ messages/ # Internationalization
β β βββ messages_en.properties # English messages
β βββ resources/ # Static resources
β βββ css/
β β βββ styles.css # Main stylesheet
β βββ img/ # OBP logos and assets
β βββ obp_logo.png
β βββ logo2x-1.png
β βββ favicon.png
After deploying with --themed, activate the OBP theme:
- Access Admin Console: https://localhost:8443/admin
- Go to Realm Settings > Themes
- Set Login Theme to "obp"
- Save changes
Complete Documentation: See the theme structure and activation sections below for comprehensive theming guide, customization options, and development workflow.
Validate your themed deployment setup by running the deployment script:
$ ./development/run-local-postgres-cicd.sh --themedThis script checks all prerequisites, validates theme files, and ensures proper configuration.
The database connection and Keycloak settings are now configured using runtime environment variables instead of build-time configuration. This enables cloud-native deployments with Docker Hub hosted images, and modern CI/CD pipelines.
Complete Documentation:
- docs/CICD_DEPLOYMENT.md - CI/CD deployment guide
- env.sample - Environment configuration reference
-
Copy and configure environment variables:
$ cp env.sample .env $ nano .env # Edit with your actual configuration -
Validate your configuration:
$ ./development/run-local-postgres-cicd.sh
-
Run the application:
# CI/CD deployment (always build & replace) $ ./development/run-local-postgres-cicd.sh --themed -
Test themed deployment (optional):
$ ./development/run-local-postgres-cicd.sh --themed
Note: For local PostgreSQL deployments, the
--validateflag automatically runs validation checks during startup.
-
Copy the example environment file:
$ cp env.sample .env
-
Edit the
.envfile with your actual configuration values:# Keycloak Admin Configuration KEYCLOAK_ADMIN=your-admin KEYCLOAK_ADMIN_PASSWORD=your-admin-password # Keycloak's Internal Database Configuration KC_DB_USERNAME=keycloak KC_DB_PASSWORD=secure-keycloak-password # User Storage Database Configuration USER_STORAGE_DB_USER=obp USER_STORAGE_DB_PASSWORD=secure-user-storage-password DB_USER=obp DB_PASSWORD=secure-user-storage-password
-
Validate your configuration (recommended):
$ ./development/run-local-postgres-cicd.sh
This script will:
- Validate all required variables are set
- Check database connectivity
- Build and deploy the application
- Provide clear success/failure feedback
Documentation Resources:
- env.sample: Complete environment variable reference with examples and security notes
- docs/CICD_DEPLOYMENT.md: CI/CD-style deployment guide for automated environments
- development/README.md: Development tools and scripts documentation
- Available scripts: Only 3 development scripts are included (see development directory)
| Variable | Default | Description |
|---|---|---|
| Keycloak Admin | ||
KEYCLOAK_ADMIN |
admin |
Keycloak admin username |
KEYCLOAK_ADMIN_PASSWORD |
admin |
Keycloak admin password |
| Keycloak Database | ||
KC_DB_USERNAME |
keycloak |
Keycloak's internal database username |
KC_DB_PASSWORD |
keycloak_changeme |
Keycloak's internal database password |
KC_DB_URL |
jdbc:postgresql://keycloak-postgres:5432/keycloak |
Keycloak's internal database URL |
| User Storage Database | ||
DB_URL |
jdbc:postgresql://user-storage-postgres:5432/obp_mapped |
User storage database URL |
| Port Configuration | ||
KC_DB_PORT |
5433 |
Keycloak database external port |
USER_STORAGE_DB_PORT |
5434 |
User storage database external port |
DB_USER |
obp |
User storage database username |
DB_PASSWORD |
changeme |
User storage database password |
| Configuration | ||
KC_HOSTNAME_STRICT |
false |
Hostname strict mode |
HIBERNATE_DDL_AUTO |
validate |
Schema validation mode for user storage |
Docker setup uses Keycloak in container with external PostgreSQL for OBP user federation:
-
Use configuration with external PostgreSQL:
$ cp .env.external-postgres .env $ # Edit .env with your database settings $ docker-compose up -
Required setup:
# External PostgreSQL must have: DB_USER=oidc_user DB_PASSWORD=your_password DB_DRIVER=org.postgresql.Driver DB_DIALECT=org.hibernate.dialect.PostgreSQLDialect OBP_AUTHUSER_PROVIDER=your_provider
The development/ directory contains local development scripts:
- Deployment:
./development/run-local-postgres-cicd.sh- Main deployment script (with --themed option) - Management:
./development/manage-container.sh- Interactive container management - PostgreSQL:
./development/pg.sh- Simple PostgreSQL container setup
See development/README.md for complete documentation of all development tools.
The project provides two focused deployment approaches:
| Method | Use Case | Build Strategy | Best For |
|---|---|---|---|
CI/CD (run-local-postgres-cicd.sh) |
Automated pipelines | Always rebuild | CI/CD, production deployments |
# Standard deployment without themes
./development/run-local-postgres-cicd.shFeatures:
- Conditional rebuilds for faster iteration
- Comprehensive validation and testing
- Interactive feedback and guidance
- Container management helpers
# Automated, reproducible deployments (always fresh build)
./development/run-local-postgres-cicd.sh --themed
# Standard CI/CD deployment
./development/run-local-postgres-cicd.shFeatures:
- Always builds from scratch (no caching issues)
- JAR checksum-based cache invalidation
- Fail-fast error handling
- Structured pipeline output
- Health checks with timeout
# Manage running containers interactively
./development/manage-container.sh
# Set up PostgreSQL container (if needed)
./development/pg.shπ Detailed Guides:
- docs/CICD_DEPLOYMENT.md - Complete CI/CD documentation
The project supports cloud-native deployment patterns:
-
Runtime Configuration (Recommended - Cloud-Native):
# Build once (no environment variables needed) $ mvn clean package $ docker build -t obp-keycloak-provider . # Deploy anywhere with runtime config $ docker run -e KC_DB_URL="jdbc:postgresql://keycloak-host:5432/keycloak" \ -e KC_DB_USERNAME="keycloak_user" \ -e KC_DB_PASSWORD="keycloak_password" \ -e DB_URL="jdbc:postgresql://user-storage-host:5432/obp_mapped" \ -e DB_USER="obp_user" \ -e DB_PASSWORD="obp_password" \ obp-keycloak-provider
-
Environment Variables Deployment:
$ export DB_URL="jdbc:postgresql://localhost:5432/obp_mapped" $ export DB_USER="obp" $ export DB_PASSWORD="obp_password" $ docker run --env-file .env obp-keycloak-provider
-
Docker Compose (Runtime Config):
$ docker-compose -f docker-compose.runtime.yml up
-
CI/CD builds using GitHub Actions workflows:
- Single generic build for all environments
- Container signing and publishing to Docker Hub
- Multi-architecture support with runtime configuration
When you run the deployment scripts, they start the Keycloak container and follow the logs. When you press Ctrl+C, the script exits but the container continues running in the background.
After pressing Ctrl+C:
- The container remains accessible at http://localhost:8000 and https://localhost:8443
- Use
./development/manage-container.shfor an interactive container management menu - Or use these direct commands:
- View logs:
docker logs -f obp-keycloak - Stop container:
docker stop obp-keycloak - Remove container:
docker rm obp-keycloak - Stop and remove:
docker stop obp-keycloak && docker rm obp-keycloak
- View logs:
Warning: I recommend using your own database, cause not all systems will have a database at
localhostavailable to thedockercontainer.
To deploy the container use the script :
$ development/pg.shThe script deploys the container locally.
It uses port : 5434 (changed from 5432 to avoid conflicts with system PostgreSQL).
The system now uses two separate databases:
- Keycloak's Internal Database: Stores realms, clients, tokens, and Keycloak's own data (accessible on localhost:5433)
- User Storage Database: Contains your external user data that Keycloak federates (accessible on localhost:5434)
Important: Due to recent fixes, the user storage database now runs on port 5434 instead of 5432 to avoid conflicts with system PostgreSQL installations.
In the User Storage Database, the authuser table must be created by a database administrator:
β οΈ CRITICAL: Theauthusertable is READ-ONLY for the Keycloak User Storage Provider and MUST be created by a database administrator with appropriate permissions. Keycloak setup scripts cannot create this table due to read-only access restrictions.
π SETUP REQUIREMENT: The authuser table must exist before running Keycloak. INSERT, UPDATE, and DELETE operations are not supported through Keycloak. Users must be managed through other means outside of Keycloak.
-- ===============================================
-- DATABASE ADMINISTRATOR SETUP REQUIRED
-- ===============================================
-- This SQL must be executed by a database administrator
-- with CREATE privileges on the obp_mapped database.
-- The Keycloak application has READ-ONLY access only.
CREATE TABLE public.authuser (
id bigserial NOT NULL,
firstname varchar(100) NULL,
lastname varchar(100) NULL,
email varchar(100) NULL,
username varchar(100) NULL,
password_pw varchar(48) NULL,
password_slt varchar(20) NULL,
provider varchar(100) NULL,
locale varchar(16) NULL,
validated bool NULL,
user_c int8 NULL,
createdat timestamp NULL,
updatedat timestamp NULL,
timezone varchar(32) NULL,
superuser bool NULL,
passwordshouldbechanged bool NULL,
CONSTRAINT authuser_pk PRIMARY KEY (id)
);
-- Grant READ-ONLY access to Keycloak user
GRANT SELECT ON public.authuser TO obp;
GRANT USAGE ON SEQUENCE authuser_id_seq TO obp;Database Setup Requirements:
- π Table must be created by database administrator BEFORE running Keycloak
- π Keycloak user (obp) needs only SELECT permissions on authuser table
- π Database administrator must create table structure and indexes
Keycloak Provider Limitations:
- β User authentication and login
- β User profile viewing
- β Password validation
- π΄ User creation through Keycloak (disabled - read-only access)
- π΄ User profile updates through Keycloak (disabled - read-only access)
- π΄ User deletion through Keycloak (disabled - read-only access)
- π΄ Table creation through setup scripts (disabled - insufficient permissions)
Users must be added to the authuser table using external database administration tools outside of Keycloak.
KC is deployed in a custom container.
To deploy the KC container, I created a Dockerfile file in which :
- I create a certificate for
httpsaccess - I add a provider
obp-keycloak-provider
Build once, deploy everywhere with runtime configuration:
# Build the provider (no environment variables needed)
$ mvn clean package
# Run with CI/CD deployment
$ ./development/run-local-postgres-cicd.sh --themedFor compatibility, you can still use the legacy build script:
$ ./development/run-local-postgres-cicd.shNote: The legacy approach uses build-time configuration which is not recommended for production deployments. Use the cloud-native approach for Docker Hub deployments.
After launching, go to https://localhost:8443 in your browser. To log in to KC, use admin credentials :
user : admin
pass : adminClick the User federation tab .
The provider obp-keycloak-provider is in list of providers.
# Pull generic image
docker pull your-org/obp-keycloak-provider:latest
# Run with environment-specific configuration
docker run -e KC_DB_URL="jdbc:postgresql://keycloak-prod-db:5432/keycloak" \
-e KC_DB_USERNAME="keycloak_prod_user" \
-e KC_DB_PASSWORD="secure_keycloak_password" \
-e DB_URL="jdbc:postgresql://user-storage-prod-db:5432/obp" \
-e DB_USER="obp_prod_user" \
-e DB_PASSWORD="secure_user_storage_password" \
your-org/obp-keycloak-provider:latest# Deploy and validate the setup
./development/run-local-postgres-cicd.shThe following critical issues have been resolved:
- Fixed JDBC URL Configuration: Corrected malformed
KC_DB_URLdefault value indocker-compose.runtime.yml - Resolved Port Conflicts: Changed user-storage-postgres to port 5434 to avoid conflicts with system PostgreSQL
- Fixed SQL Syntax Error: Removed incomplete SQL statement in database initialization script
- Updated Environment Variables: All configuration now properly supports the separated database architecture
- Keycloak Internal Database:
localhost:5433(unchanged) - User Storage Database:
localhost:5434(changed from 5432) - Keycloak Application:
localhost:8000(HTTP) andlocalhost:8443(HTTPS)
If you encounter connection issues:
- Run the deployment script which validates configuration:
./development/run-local-postgres-cicd.sh - Check for port conflicts:
ss -tulpn | grep :5432ornetstat -tulpn | grep :5432 - Review the setup documentation in the
docs/directory
- Environment Configuration - Environment variable reference
- CI/CD Deployment - Automated deployment guide for pipelines
- Docker Compose - Runtime configuration example
