Deployment guide

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=groups and 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.

1

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.pub
2

Connect 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.

3

Read the per-VM credentials

Read the credentials file with sudo:

sudo cat /root/keycloak-openldap-credentials.txt

The 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.
4

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' slapd

Expected 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.1
5

Query 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=*)' dn

Expected 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=com
6

Verify 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=com

For 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.

7

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.

8

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.

9

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
10

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 -20

After 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=postgres and KC_DB_URL=... in /etc/keycloak/keycloak.env, and switch the unit from start-dev to start --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 to ldaps://127.0.0.1:636 in the admin console for encrypted local binds.
  • Review directory ACLs. The default policy refuses anonymous writes and protects userPassword. Review olcAccess before you grant applications broader access.
  • Create service accounts. Bind applications with dedicated read-only DNs under ou=people, never with cn=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 -30

If 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 -10

Verify 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/ldap

Confirm 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

Deploy on Azure