Keycloak OpenLDAP
Overview
This image pairs OpenLDAP and Keycloak on one VM. OpenLDAP (slapd) is the authoritative user and group directory. Keycloak is the identity provider in front of it, adding single sign-on, OpenID Connect, OAuth 2.0 and SAML to accounts that live in LDAP.
On first boot, the image wires a Keycloak LDAP user federation provider to the local directory in a dedicated realm named SecureAnyCloud, runs a full user sync, and confirms that a directory-stored user can obtain a token through Keycloak before the machine is handed to you.
What you get:
- Keycloak 26.7.1 (Quarkus distribution) from the official GitHub release tarball at
/opt/keycloak, with OpenJDK 21 - OpenLDAP 2.6 (slapd) from the Ubuntu 24.04 repository, mdb backend, base DN
dc=example,dc=com - Keycloak realm SecureAnyCloud with an LDAP user federation provider (WRITABLE edit mode, registrations sync back to LDAP) pointing at ldap://127.0.0.1:389, with users from ou=people,dc=example,dc=com
- A seeded directory:
ou=people,ou=groupsand a demo user (uid=demo) that is synced into Keycloak and can sign in through it - LDAP on TCP 389 (with StartTLS), LDAPS on TCP 636 (per-VM self-signed certificate), and Keycloak HTTP on TCP 8080
- The directory database on a dedicated 20 GB data disk at
/var/lib/ldap, independently resizable - Unique per-VM passwords for the Keycloak admin (SecureAnyCloud), the directory admin (cn=admin,dc=example,dc=com) and the demo user, generated at first boot, with no default logins
- Verbatim licence texts in the image under
/usr/share/sac/licenses/(Keycloak Apache 2.0, OpenLDAP Public License) - 24/7 SecureAnyCloud support
Prerequisites
You need:
- An active Azure subscription
- An SSH key pair for the VM login user
- A virtual network and subnet (or let the portal create one)
Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) suits evaluation and small deployments. For production SSO with larger user populations, move Keycloak to a PostgreSQL backend and a D-series size.
Network ports
The image listens on these ports:
TCP 22: SSH access
TCP 8080: Keycloak HTTP (admin console, OIDC and SAML endpoints)
TCP 389: LDAP (bind, search, StartTLS)
TCP 636: LDAPS (LDAP over TLS)
An LDAP endpoint reachable from the internet is a serious exposure. Restrict 389 and 636 to your own VNet CIDR. For production, keep 8080 behind a TLS reverse proxy or restrict it to your management network.
Deploy the virtual machine
Option A - Azure Portal. Search the Azure Marketplace for "Keycloak with OpenLDAP Directory SecureAnyCloud" and select the offer. Choose Standard_B2s, your SSH key and your network, then create the VM. Open inbound ports 22 and 8080, and open 389 and 636 only to your VNet.
Option B - Azure CLI. Run:
az vm image terms accept --urn sac1647283583153:keycloak-openldap:default:latest
az vm create \
--resource-group my-rg \
--name keycloak-ldap-vm \
--image sac1647283583153:keycloak-openldap:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pubConnect over SSH
Connect to the VM as azureuser:
ssh azureuser@<vm-ip>First boot takes a couple of minutes. The image rotates every credential, regenerates the LDAP TLS certificate, bootstraps the Keycloak admin, wires the LDAP federation and verifies a federated login. It then writes the credentials file.
Read the per-VM credentials
Read the credentials file with sudo:
sudo cat /root/keycloak-openldap-credentials.txtThe file (mode 0600, root only) holds the three per-VM secrets generated on first boot:
- KEYCLOAK_ADMIN_PASSWORD: the password for the console user SecureAnyCloud.
- OPENLDAP_ADMIN_PASSWORD: the password for the bind DN cn=admin,dc=example,dc=com.
- DEMO_USER_PASSWORD: the password for the LDAP demo user that signs in through Keycloak.
Check service status and versions
Confirm that slapd and Keycloak are running and check their versions:
sudo systemctl status slapd --no-pager | head -5 sudo systemctl status keycloak --no-pager | head -5 sudo /opt/keycloak/bin/kc.sh --version 2>&1 | head -1 dpkg-query -W -f='slapd ${Version}\n' slapdExpected output:
● slapd.service - LSB: OpenLDAP standalone server (Lightweight Directory Access Protocol) Active: active (running) ● keycloak.service - Keycloak 26 Identity & Access Management (sac, OpenLDAP-federated) Active: active (running) Keycloak 26.7.1 slapd 2.6.10+dfsg-0ubuntu0.24.04.1Query the directory
Bind as the directory administrator and list the seeded entries:
LDAP_PW=$(sudo grep -m1 '^OPENLDAP_ADMIN_PASSWORD=' /root/keycloak-openldap-credentials.txt | cut -d= -f2-) ldapwhoami -x -H ldap://127.0.0.1 -D 'cn=admin,dc=example,dc=com' -w "$LDAP_PW" ldapsearch -x -LLL -H ldap://127.0.0.1 -D 'cn=admin,dc=example,dc=com' -w "$LDAP_PW" \
-b 'dc=example,dc=com' '(objectclass=*)' dnExpected output:
dn:cn=admin,dc=example,dc=com dn: dc=example,dc=com dn: ou=people,dc=example,dc=com dn: ou=groups,dc=example,dc=com dn: uid=demo,ou=people,dc=example,dc=comVerify LDAPS
The image serves LDAP over TLS on port 636 with a certificate regenerated for this VM at first boot. Bind over LDAPS:
LDAP_PW=$(sudo grep -m1 '^OPENLDAP_ADMIN_PASSWORD=' /root/keycloak-openldap-credentials.txt | cut -d= -f2-) LDAPTLS_REQCERT=never ldapwhoami -x -H ldaps://127.0.0.1:636 -D 'cn=admin,dc=example,dc=com' -w "$LDAP_PW"Expected output:
dn:cn=admin,dc=example,dc=comFor production, replace the self-signed pair at /etc/ldap/certs/ldap.crt and /etc/ldap/certs/ldap.key with a CA-signed certificate, then restart slapd.
Sign in LDAP users through Keycloak
Realm SecureAnyCloud federates its users from the local directory. Confirm the realm is live, then verify the end-to-end path by obtaining an OpenID Connect token for the LDAP-stored demo user:
curl -sf http://127.0.0.1:8080/realms/sac/.well-known/openid-configuration | head -c 200; echo
DEMO_PW=$(sudo grep -m1 '^DEMO_USER_PASSWORD=' /root/keycloak-openldap-credentials.txt | cut -d= -f2-)
curl -sf -X POST http://127.0.0.1:8080/realms/sac/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=password&client_id=admin-cli&username=demo&password=${DEMO_PW}" \
| grep -o '"token_type":"Bearer"'Expected output:
{"issuer":"http://127.0.0.1:8080/realms/sac","authorization_endpoint":"http://127.0.0.1:8080/realms/sac/protocol/openid-connect/auth", ... "token_type":"Bearer"The password you used is stored only in OpenLDAP. Keycloak validated it by binding to the directory. The directory stays the single source of truth, and Keycloak issues the tokens.
Sign in to the admin console
Browse to http://<vm-ip>:8080/. Keycloak 26 opens the admin console sign-in form directly, with no separate welcome page. Sign in as SecureAnyCloud with KEYCLOAK_ADMIN_PASSWORD from Step 3.
After you sign in, you land on the master realm console. Keycloak flags the first-boot admin as a temporary account. As a hardening step, create your own permanent administrator and delete SecureAnyCloud.
Review the pre-wired LDAP federation provider
Open Manage realms, switch to the SecureAnyCloud realm, then open User federation. The openldap provider is already configured and enabled against the local directory:
- Connection: ldap://127.0.0.1:389
- Users DN: ou=people,dc=example,dc=com
- Bind DN: cn=admin,dc=example,dc=com
- Edit mode: WRITABLE, with registration sync, so users created in Keycloak are written back to LDAP
View directory users in Keycloak
Open Users in realm SecureAnyCloud. Because the realm has a federated provider, the list starts empty. Search for * (or a username), as the console suggests.
The demo user is returned with its name and email attributes mapped from LDAP. It lives in OpenLDAP and was imported by the first-boot full sync. Any user you add under ou=people appears here after a sync, and any user you create here is written into the directory.
Server components
Versions and paths of the installed components:
Keycloak 26.7.1: /opt/keycloak/
OpenJDK 21: /usr/lib/jvm/
OpenLDAP slapd 2.6.10: /usr/sbin/slapd
ldap-utils 2.6.10: /usr/bin/ldapsearch and related tools
Keycloak systemd unit: /etc/systemd/system/keycloak.service
Keycloak runtime environment: /etc/keycloak/keycloak.env
Keycloak H2 database: /opt/keycloak/data/h2/
LDAP database (mdb): /var/lib/ldap/ (dedicated data disk)
LDAP TLS certificate: /etc/ldap/certs/ldap.crt and ldap.key
First-boot script: /usr/local/sbin/keycloak-openldap-firstboot.sh
Credentials: /root/keycloak-openldap-credentials.txt (0600 root:root)
Licences: /usr/share/sac/licenses/
Filesystem layout
Mount points and sizes:
/ (30 GB): root filesystem (Keycloak, OS, Keycloak H2 database)
/boot/efi (100 MB): UEFI boot partition (Gen2 Hyper-V)
/var/lib/ldap (20 GB): dedicated data disk for the OpenLDAP mdb database
/mnt (size varies): Azure temporary resource disk
The directory database is separate from the OS disk, so you can resize it independently. It is preserved on every VM created from this image.
Manage the services
Restart the services and read their logs with systemd:
sudo systemctl restart slapd
sudo systemctl restart keycloak
sudo journalctl -u keycloak --no-pager | tail -20 sudo journalctl -u slapd --no-pager | tail -20After a restart, Keycloak takes 30 to 60 seconds to serve requests.
Production hardening
- Restrict the NSG. Allow 389 and 636 from your VNet CIDR only. Put 8080 behind a TLS reverse proxy (or enable Keycloak HTTPS) and restrict it to trusted networks.
- Move the Keycloak database. For production populations, move from H2 to PostgreSQL: set
KC_DB=postgresandKC_DB_URL=...in/etc/keycloak/keycloak.env, and switch the unit fromstart-devtostart --hostname=<your-fqdn>. - Secure LDAP TLS. Install a CA-signed certificate at
/etc/ldap/certs/and restart slapd. Then set the federation provider's connection toldaps://127.0.0.1:636in the admin console for encrypted local binds. - Review directory ACLs. The default policy refuses anonymous writes and protects
userPassword. ReviewolcAccessbefore you grant applications broader access. - Create service accounts. Bind applications with dedicated read-only DNs under
ou=people, never withcn=admin. - Patch regularly. Unattended upgrades are enabled. Still plan a monthly
apt-get update && apt-get upgrade && reboot.
Troubleshooting
Keycloak is not reachable on 8080
sudo systemctl status keycloak --no-pager | head -5 sudo journalctl -u keycloak --no-pager | tail -30If the unit reports a failed condition on first boot, the first-boot service has not finished yet. Check sudo journalctl -u keycloak-openldap-firstboot --no-pager | tail -30.
A directory user cannot sign in through Keycloak
sudo journalctl -u keycloak --no-pager | grep -i ldap | tail -10Verify that the user exists in LDAP (Step 5). Then open User federation in realm SecureAnyCloud and select Sync all users. Keycloak validates passwords by binding to LDAP, so the user's userPassword must be set in the directory.
slapd will not start
sudo journalctl -u slapd --no-pager | tail -20 df -h /var/lib/ldapConfirm that the data disk is mounted at /var/lib/ldap. The image provisions it automatically.
Licensing
Keycloak is licensed under the Apache License 2.0. OpenLDAP is distributed under the OpenLDAP Public License (BSD-style, OSI approved). Both verbatim licence texts ship in the image under /usr/share/sac/licenses/. SecureAnyCloud provides commercial support separately.
Support
- Email: sales@secureanycloud.com
- Response time: 24/7 with guaranteed response SLA
- Website: https://secureanycloud.com
Deploy on Azure
Launch Keycloak with OpenLDAP Directory on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com