The Identity Management Problem in Growing Infrastructure
Picture a team of 45 engineers managing credentials across 12 separate internal web apps. Every Jenkins dashboard, internal wiki, Grafana monitor, and staging cluster maintains its own siloed user database.
Onboarding a new engineer means manually generating accounts across five or six consoles, eating up an hour of DevOps time per hire. Offboarding hurts even more. When an engineer leaves on a Friday afternoon, revoking access across every standalone system risks leaving active session tokens or orphaned accounts wide open.
Predictably, team members hit password fatigue. They start reusing 10-character weak passwords across environments or dumping credentials into shared, unencrypted text files. Running without a unified Identity and Access Management (IAM) layer creates messy audit trails, zero single-click session terminations, and wildly inconsistent security standards across everyday tools.
Core IAM Concepts: Realms, Federation, and Single Sign-On
Before launching containers, let’s nail down four foundational concepts to save hours of troubleshooting later:
- Keycloak Realm: An isolated security domain containing users, credentials, roles, and connected apps. The default
masterrealm serves strictly as an admin control plane. Always create a separate realm (such asinternal-corp) for your staff and day-to-day services. - OpenID Connect (OIDC) & SAML: Keycloak bridges modern identity protocols. Most web platforms connect to Keycloak via OIDC (built on OAuth 2.0 using signed RS256 JWT tokens), so apps never touch or store raw user passwords.
- User Federation (LDAP): Instead of juggling duplicate databases, Keycloak binds directly to an external directory service like OpenLDAP or Active Directory. It reads user trees, validates credentials via LDAP bind requests, and caches profile metadata locally.
- Multi-Factor Authentication (MFA / 2FA): Keycloak supports standard RFC 6238 Time-based One-Time Passwords (TOTP). Users scan a QR code into Google Authenticator or FreeOTP, eliminating the need for paid SMS gateways.
Hands-On Practice: Setting Up Keycloak, PostgreSQL, and OpenLDAP
Step 1: Docker Compose Infrastructure Blueprint
Keycloak runs on the Quarkus runtime and pairs cleanly with PostgreSQL for metadata storage. Alongside Keycloak, we will spin up OpenLDAP to store identity records and a lightweight phpLDAPadmin web client for schema management.
For generating database and admin passwords with at least 32 characters of high-entropy randomness, the client-side generator at toolcraft.app/en/tools/security/password-generator works well because it calculates entropy locally in browser memory without sending keys over the wire.
Save this configuration as docker-compose.yml:
version: '3.8'
networks:
iam-network:
driver: bridge
volumes:
postgres_data:
ldap_data:
ldap_config:
services:
postgres:
image: postgres:15-alpine
container_name: keycloak-db
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak_admin
POSTGRES_PASSWORD: ReplaceWithAStrongSecretDbPass123!
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- iam-network
restart: unless-stopped
openldap:
image: osixia/openldap:1.5.0
container_name: openldap
environment:
LDAP_ORGANISATION: "Example Corp"
LDAP_DOMAIN: "example.com"
LDAP_ADMIN_PASSWORD: ReplaceWithLdapAdminPass123!
volumes:
- ldap_data:/var/lib/ldap
- ldap_config:/etc/ldap/slapd.d
networks:
- iam-network
restart: unless-stopped
phpldapadmin:
image: osixia/phpldapadmin:0.9.0
container_name: phpldapadmin
environment:
PHPLDAPADMIN_LDAP_HOSTS: openldap
PHPLDAPADMIN_HTTPS: "false"
ports:
- "8080:80"
networks:
- iam-network
depends_on:
- openldap
restart: unless-stopped
keycloak:
image: quay.io/keycloak/keycloak:24.0.1
container_name: keycloak-server
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL_HOST: postgres
KC_DB_URL_PORT: 5432
KC_DB_URL_DATABASE: keycloak
KC_DB_USERNAME: keycloak_admin
KC_DB_PASSWORD: ReplaceWithAStrongSecretDbPass123!
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: ReplaceWithAdminConsolePass123!
ports:
- "8081:8080"
networks:
- iam-network
depends_on:
- postgres
restart: unless-stopped
Boot the environment in the background:
docker compose up -d
docker compose logs -f keycloak
Watch the logs. In roughly 15 to 20 seconds, Keycloak will print Running the server in development mode. Started.... You can now reach Keycloak at http://localhost:8081 and phpLDAPadmin at http://localhost:8080.
Step 2: Seed Directory Users in OpenLDAP
Open http://localhost:8080 in your browser. Sign in using the admin DN cn=admin,dc=example,dc=com and your defined LDAP_ADMIN_PASSWORD. Create a structural Organizational Unit (OU) called users, then add a test account inside ou=users,dc=example,dc=com:
- First name (givenName): Alex
- Last name (sn): Mercer
- Username (uid): amercer
- Email (mail): [email protected]
- Password (userPassword): TemporaryPass987!
Step 3: Connect Keycloak to OpenLDAP via User Federation
- Log in to the Keycloak admin console at
http://localhost:8081with yourKEYCLOAK_ADMINcredentials. - Click the realm selector at the top left, choose Create Realm, and name it
internal-corp. - In the left sidebar, navigate to User federation and select Add LDAP providers.
- Configure the connection parameters:
- UI display name:
Company-OpenLDAP - Vendor:
Other - Connection URL:
ldap://openldap:389 - Users DN:
ou=users,dc=example,dc=com - Authentication type:
simple - Bind DN:
cn=admin,dc=example,dc=com - Bind credential:
ReplaceWithLdapAdminPass123! - Username LDAP attribute:
uid - RDN LDAP attribute:
uid - UUID LDAP attribute:
entryUUID - User object classes:
inetOrgPerson, organizationalPerson, person - Edit mode:
READ_ONLY(keep this read-only if LDAP remains your single source of truth, or switch toWRITABLEto let users sync password updates back to the directory)
- UI display name:
- Click Test connection, followed by Test authentication. Once both return green success badges, hit Save.
- Scroll down to the Sync settings pane and click Sync all users. Check the Users tab in Keycloak:
amercerappears instantly with their directory email and profile fields intact.
Step 4: Enforce Two-Factor Authentication (TOTP) Policies
Once identities stream in from LDAP, rolling out mandatory 2FA across every connected tool takes under two minutes:
- Inside the
internal-corprealm, click Authentication > Required actions. - Find Configure OTP and enable Set as default action. This flags every account lacking an authenticator registration to enroll on their very next login.
- Navigate to Authentication > Policies > OTP Policy. We recommend setting the hashing algorithm to SHA-256 with standard 6-digit codes and a 30-second token window.
Test the flow right away. Head to http://localhost:8081/realms/internal-corp/account/ and sign in as amercer. Keycloak validates the password against OpenLDAP, immediately halts the session, and presents an enrollment QR code. The user cannot touch downstream tools until they verify their first six-digit code.
Practical Experience & Architecture Insights
After running containerized Keycloak deployments across high-traffic production environments, three operational rules stand out:
- Keep start-dev strictly on local laptops: The
start-devflag turns off critical TLS validations and binds directly to plain HTTP. For staging and production, create a two-stage Dockerfile that builds assets usingkc.sh buildwith your PostgreSQL drivers pre-cached. Then boot containers viakc.sh start --optimizedbehind a reverse proxy (like Traefik or NGINX) handling TLS termination on port 443. - Keep access tokens brief: A 5-minute access token lifespan hits the sweet spot. Don’t stretch access tokens to 8 hours just to avoid refresh handshakes; that turns leaked bearer tokens into an administrative nightmare. Pair short 5-minute access tokens with longer 12-hour refresh tokens, and turn on Revoke Refresh Token to rotate refresh credentials on each exchange.
- Automate background sync jobs: Under a
READ_ONLYLDAP setup, newly added team members won’t show up in Keycloak search lists until they log in or a manual sync triggers. Prevent this by turning on Periodic Full Sync (every 86,400 seconds, or 24 hours) and Periodic Changed Users Sync (every 300 seconds, or 5 minutes). This ensures newly added LDAP groups and team changes reflect in Keycloak role mappings with zero manual overhead.
Combining Keycloak and OpenLDAP in Docker gives you a resilient, battle-tested IAM architecture. Applications delegate auth via OIDC, SysAdmins maintain a clean centralized directory, and security baselines like mandatory TOTP apply across every internal dashboard you run.
