Keycloak with OpenLDAP 26.8.1 on AWS User Guide
Overview
This guide covers launching and using the Keycloak with OpenLDAP 26.8.1 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg identity, secrets and PKI listing on AWS Marketplace.
Keycloak is an open source identity and access management server: single sign-on for your applications over OpenID Connect, OAuth 2.0 and SAML 2.0, with an admin console, an account console for users, and user federation. OpenLDAP is the reference open source LDAP directory server (slapd). In this image Keycloak's realm cloudimg reads its users from the local OpenLDAP directory, so a person you add to the directory can sign in through Keycloak straight away, with their password checked by the directory.
The cloudimg image is a hardened, ready-to-use pairing:
- The upstream Keycloak 26.8.1 release. The community distribution from the Keycloak project, checked against pinned SHA-256 and SHA-512 hashes and the Keycloak release signing key at build time, running in production mode (
kc.sh start --optimized) with PostgreSQL 16. It is not a vendor build and no file is changed. - HTTPS from the first boot. nginx is the only public listener (ports 80 and 443) and serves a certificate generated on your instance (an end-entity certificate, not a certificate authority); port 80 redirects to HTTPS. Keycloak itself listens on
127.0.0.1only. - No default password anywhere. First boot generates the Keycloak bootstrap administrator, the directory's
cn=adminandcn=configpasswords, the read-only account Keycloak binds with, and the database password, and writes them to a root-only file. Nothing secret is baked into the image. - A locked-down directory. OpenLDAP listens on the loopback address and its local socket only (ports 389 and 636 are not reachable from the network until you choose to expose LDAPS, Step 13). Anonymous binds and searches are refused, passwords are stored as Argon2 hashes, and Keycloak binds with a least-privilege service account that can read users but cannot write anything or read password hashes.
- The proxy cannot be fooled. nginx hands Keycloak the real client address and the configured host name, overwriting any
X-Forwarded-*header a client sends, and Keycloak trusts those headers only from127.0.0.1. Requests with path tricks (;parameters,//, encoded slashes) are refused before routing, so the optional source-address list for the admin console (Step 9) cannot be sidestepped. - Metadata access blocked. Keycloak can fetch URLs you configure (identity-provider discovery, JWKS, LDAP connections). Every service is blocked from the instance metadata service, and the AMI requires IMDSv2.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Keycloak 26.8.1 (/opt/keycloak), OpenLDAP 2.6 (slapd, ldap-utils), PostgreSQL 16, nginx, OpenJDK 21, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 22 (SSH) from your own networks only, and TCP 443 (Keycloak) and TCP 80 (redirects to HTTPS) from the people and applications that sign in. Do not open 389, 636, 5432, 8080 or 9000: nothing listens on them from the network.
- For production, a DNS name you control (for example
id.example.com) and a certificate from a certificate authority for it, so that browsers and applications trust the sign-in pages without a warning.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Keycloak with OpenLDAP 26.8.1 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair, and a security group as above.
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --image-id <ami-id-from-the-listing> --instance-type m5.large \
--key-name <your-key-pair> --security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=keycloak-openldap}]'
First boot takes about a minute and a half after cloud-init has run. If you want your own name or your own directory base DN from the start, put them in /etc/cloudimg/keycloak-openldap-domain.preset and /etc/cloudimg/keycloak-openldap-basedn.preset with user data (for example cloud-init write_files entries); otherwise first boot uses the instance's public DNS name (or its private name) and the base DN dc=example,dc=com, and you can change both later (Steps 10 and 11).
Step 2: Connect to your instance
| Operating system | SSH user |
|---|---|
| Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
systemctl is-active keycloak-openldap-firstboot postgresql@16-main slapd keycloak nginx
active
active
active
active
active
Only SSH, HTTP and HTTPS are public. Keycloak (8080) and its management interface (9000, health checks), OpenLDAP (389) and PostgreSQL (5432) listen on the loopback address only (Java lists its loopback sockets as [::ffff:127.0.0.1]):
sudo ss -tln | awk '{print $4}' | grep -E ':(22|80|389|443|636|5432|8080|9000)$' | sort -u
0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
127.0.0.1:389
127.0.0.1:5432
[::]:22
[::]:443
[::]:80
[::ffff:127.0.0.1]:8080
[::ffff:127.0.0.1]:9000
A health endpoint for monitoring agents on the instance itself:
curl -s http://127.0.0.1:9000/health/ready; echo
{
"status": "UP",
"checks": [
{
"name": "Graceful Shutdown",
"status": "UP"
},
{
"name": "Keycloak Initialized",
"status": "UP"
}
]
}
Step 4: Your addresses and credentials
Everything first boot generated is in a root-only file (mode 0600). Show it without the password lines first:
sudo grep -v PASSWORD /root/keycloak-openldap-credentials.txt
# Keycloak 26.8.1 with OpenLDAP - written on first boot by keycloak-openldap-firstboot.service. Unique to this instance.
KEYCLOAK_URL=https://ec2-3-88-34-254.compute-1.amazonaws.com/
KEYCLOAK_CONSOLE_URL=https://ec2-3-88-34-254.compute-1.amazonaws.com/admin/
KEYCLOAK_ACCOUNT_CONSOLE=https://ec2-3-88-34-254.compute-1.amazonaws.com/realms/cloudimg/account/
KEYCLOAK_BOOTSTRAP_ADMIN_USER=bootstrap-admin
KEYCLOAK_REALM=cloudimg
LDAP_URL=ldap://127.0.0.1:389
LDAP_BASE_DN=dc=example,dc=com
LDAP_PEOPLE_DN=ou=people,dc=example,dc=com
LDAP_ADMIN_DN=cn=admin,dc=example,dc=com
LDAP_CONFIG_DN=cn=admin,cn=config
LDAP_KEYCLOAK_BIND_DN=cn=keycloak,ou=services,dc=example,dc=com
TLS_SHA256=59:5E:FC:03:8E:CD:B3:3A:9D:C3:CB:84:80:FA:52:FD:82:86:A1:51:8B:51:5B:3D:4C:99:B4:04:9C:43:23:A2
TLS_SPKI_SHA256=KCVGumS779UZ4MBUK5iZKpsuCLOkucf4jr71nagPCxY=
#
# Keycloak: sign in to the admin console at KEYCLOAK_CONSOLE_URL as KEYCLOAK_BOOTSTRAP_ADMIN_USER. It is a TEMPORARY bootstrap
# admin: create your own permanent admin in the master realm, then delete bootstrap-admin (see the guide).
# Directory users live under LDAP_PEOPLE_DN and sign in to realm "cloudimg" (KEYCLOAK_ACCOUNT_CONSOLE) through the LDAP
# federation. Add one: sudo cloudimg-ldap ldapadd -f user.ldif (binds as LDAP_ADMIN_DN; no password on the command line)
# OpenLDAP and PostgreSQL listen on 127.0.0.1 only; the Keycloak database password is in /etc/keycloak/keycloak.conf.
# The HTTPS certificate is self-signed and unique to this instance: compare its SHA-256 fingerprint (TLS_SHA256), or
# replace it with a CA-issued certificate for your own name. Your own name: sudo keycloak-openldap-set-domain id.example.com
# Your own base DN (while the directory has no users): sudo keycloak-openldap-set-basedn dc=corp,dc=example,dc=com
# User guide: https://www.cloudimg.co.uk/guides/keycloak-with-openldap-26-8-1-on-ubuntu-24-04-aws/
The file also holds KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD, LDAP_ADMIN_PASSWORD, LDAP_CONFIG_PASSWORD and LDAP_KEYCLOAK_BIND_PASSWORD; read the one you need when you need it, for example sudo grep '^KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD=' /root/keycloak-openldap-credentials.txt. The database password is only in /etc/keycloak/keycloak.conf (readable by root and the keycloak service account).
The certificate is self-signed and unique to your instance. Do not add it to a trust store: compare its fingerprint (TLS_SHA256) with the one your browser shows, or replace it with a CA-issued certificate (Step 10).
Step 5: Run the self-test
sudo keycloak-openldap-selftest
It checks that an anonymous LDAP bind and search are refused, adds a throwaway user to the directory as the directory administrator (the password is stored as an Argon2 hash), signs that user in to realm cloudimg over HTTPS through the LDAP federation, verifies the access token's signature against the realm's published keys (a tampered token fails), checks that a wrong password is refused, and removes the user from the directory and from Keycloak.
round trip OK: anonymous LDAP refused; ldapadd as admin ({ARGON2} stored); LDAP user -> realm cloudimg token, RS256 verified against the JWKS (tampered token refused); wrong password refused; user removed
KEYCLOAK_OPENLDAP_SELFTEST_OK
Step 6: Sign in to the admin console
Open KEYCLOAK_CONSOLE_URL (https://<your-name>/admin/) in a browser, accept the certificate after comparing its fingerprint, and sign in as bootstrap-admin with KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD.

Keycloak marks this account as a temporary admin. Create your own permanent administrator now and then delete bootstrap-admin: in the master realm open Users, Add user, set a username, then on the user's Credentials tab set a password, and on Role mapping assign the realm role admin. Sign out, sign in as your new administrator, and delete bootstrap-admin under Users. (The helper keycloak-openldap-set-basedn and the self-test sign in with the KEYCLOAK_BOOTSTRAP_ADMIN_* lines of the credentials file; put your own administrator there if you want to keep using them.)

Switch to realm cloudimg and open User federation: the provider openldap reads users from ou=people,<base DN> on ldap://127.0.0.1:389, in READ_ONLY edit mode, bound as cn=keycloak,ou=services,<base DN>.


Step 7: Add a directory user and sign in with it
cloudimg-ldap runs any ldap* tool against the local directory bound as the directory administrator (LDAP_ADMIN_DN); the password goes to the tool in a root-only temporary file, never on the command line. Users go under ou=people with the inetOrgPerson object class. A password given in clear text is hashed (Argon2) by the server before it is stored.
B=$(sudo sed -n 's/^LDAP_BASE_DN=//p' /root/keycloak-openldap-credentials.txt)
PW=$(openssl rand -base64 18)
printf 'dn: uid=alice,ou=people,%s\nobjectClass: inetOrgPerson\nuid: alice\ncn: Alice Example\nsn: Example\ngivenName: Alice\nmail: alice@example.com\nuserPassword: %s\n' "$B" "$PW" > /tmp/alice.ldif
sudo cloudimg-ldap ldapadd -f /tmp/alice.ldif
shred -u /tmp/alice.ldif
printf '%s' "$PW" > /tmp/alice.pw && chmod 600 /tmp/alice.pw
echo "alice's password is in /tmp/alice.pw"
adding new entry "uid=alice,ou=people,dc=example,dc=com"
alice's password is in /tmp/alice.pw
Alice can now sign in to realm cloudimg. In a browser, open KEYCLOAK_ACCOUNT_CONSOLE (https://<your-name>/realms/cloudimg/account/) and sign in as alice:


The same sign-in from the command line, with the ID token's signature checked against the realm's public keys (the token itself is never printed):
D=$(head -1 /etc/cloudimg/keycloak-openldap-domain)
curl -s --cacert /etc/ssl/keycloak-openldap/server.crt --resolve "$D:443:127.0.0.1" \
-d grant_type=password -d client_id=admin-cli -d 'scope=openid profile' -d username=alice \
--data-urlencode "password@/tmp/alice.pw" "https://$D/realms/cloudimg/protocol/openid-connect/token" \
| jq -r .id_token > /tmp/alice.jwt
curl -s --cacert /etc/ssl/keycloak-openldap/server.crt --resolve "$D:443:127.0.0.1" \
"https://$D/realms/cloudimg/protocol/openid-connect/certs" > /tmp/realm-jwks.json
V=$(python3 /usr/local/lib/cloudimg/keycloak-openldap/jwt-verify.py /tmp/alice.jwt /tmp/realm-jwks.json "https://$D/realms/cloudimg")
shred -u /tmp/alice.jwt; echo "$V"
[[ "$V" == "JWT_VERIFY OK"* ]]
JWT_VERIFY OK kid=QvhElW9h iss=https://ec2-3-88-34-254.compute-1.amazonaws.com/realms/cloudimg user=alice
The admin-cli client and the password grant are used here only to show the flow from a shell. Your applications should register their own client in realm cloudimg (Clients, Create client) and use the authorization code flow with PKCE; the realm's discovery document is at https://<your-name>/realms/cloudimg/.well-known/openid-configuration.
To remove a user, delete the directory entry and Keycloak's imported copy of it. Keycloak keeps the imported copy (it is linked to the old entry's entryUUID) until it next looks the user up, and a new directory entry with the same username cannot sign in while that copy exists. The block below does both; it signs in to Keycloak's admin API with the credentials file's admin account, passing the password through a root-only file, never the command line:
B=$(sudo sed -n 's/^LDAP_BASE_DN=//p' /root/keycloak-openldap-credentials.txt)
sudo cloudimg-ldap ldapdelete "uid=alice,ou=people,$B"
sudo bash -c 'umask 077; sed -n "s/^KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD=//p" /root/keycloak-openldap-credentials.txt | tr -d "\n" > /run/kc-admin.pw'
TOK=$(sudo curl -s http://127.0.0.1:8080/realms/master/protocol/openid-connect/token -d grant_type=password -d client_id=admin-cli \
-d username=bootstrap-admin --data-urlencode "password@/run/kc-admin.pw" | jq -r .access_token)
sudo shred -u /run/kc-admin.pw
U="http://127.0.0.1:8080/admin/realms/cloudimg/users?username=alice&exact=true"
curl -s -o /dev/null -H "Authorization: Bearer $TOK" "$U" # the lookup itself drops a copy whose entry is gone
ID=$(curl -s -H "Authorization: Bearer $TOK" "$U" | jq -r '.[0].id // empty')
[ -n "$ID" ] && curl -s -o /dev/null -X DELETE -H "Authorization: Bearer $TOK" "http://127.0.0.1:8080/admin/realms/cloudimg/users/$ID"
echo "alice in Keycloak: $(curl -s -H "Authorization: Bearer $TOK" "$U" | jq length)"
unset TOK; shred -u /tmp/alice.pw /tmp/realm-jwks.json 2>/dev/null; rm -f /tmp/realm-jwks.json; true
(If you replaced bootstrap-admin with your own administrator, use that account, or delete the user under Users in realm cloudimg in the admin console.)
Step 8: Working with the directory
Search the people branch as the directory administrator (password hashes are never shown to anyone but root over the local socket):
B=$(sudo sed -n 's/^LDAP_BASE_DN=//p' /root/keycloak-openldap-credentials.txt)
sudo cloudimg-ldap ldapsearch -LLL -b "$B" -s one dn
dn: ou=groups,dc=example,dc=com
dn: ou=people,dc=example,dc=com
dn: ou=services,dc=example,dc=com
Anonymous access is refused:
ldapsearch -x -H ldap://127.0.0.1:389 -b "dc=example,dc=com" -s base dn 2>&1 | head -2 || true
ldap_bind: Inappropriate authentication (48)
additional info: anonymous bind disallowed
root can also manage the directory and its configuration without a password over the local socket, for example sudo ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b cn=config dn. To change a user's password: sudo cloudimg-ldap ldappasswd -S "uid=alice,ou=people,<base DN>" (it prompts). Group entries (groupOfNames) go under ou=groups; to map them to Keycloak groups add a group-ldap-mapper to the openldap provider in the admin console.
Step 9: Restrict the admin console to your own networks
Everyone who can reach port 443 can see the admin sign-in page. To allow the admin console (/admin) and the master realm (/realms/master, where administrators sign in) only from your own addresses, edit the access list and reload nginx:
sudo cat /etc/nginx/cloudimg/keycloak-admin-access.conf
# cloudimg: who may reach the Keycloak admin console (/admin) and the master realm (/realms/master: admin sign-in and
# admin tokens). Default: everyone (the admin password is the control). To restrict, replace "allow all;" with your
# networks, then: sudo nginx -t && sudo systemctl reload nginx
# allow 203.0.113.0/24;
# allow 198.51.100.7;
# deny all;
allow all;
Replace allow all; with lines such as allow 203.0.113.0/24; followed by deny all;, then run sudo nginx -t && sudo systemctl reload nginx. Realm cloudimg (your users' sign-in pages and your applications' endpoints) stays reachable. The list is matched on the decoded, case-insensitive path, and paths with ;, // or encoded slashes are refused before routing, so spellings such as /realms/MASTER/ or /realms/master;x=1/ cannot get round it.
Step 10: Use your own domain and certificate
Point a DNS name at the instance (an Elastic IP is a good idea), then:
sudo keycloak-openldap-set-domain id.example.com
This sets Keycloak's host name (hostname=https://id.example.com in /etc/keycloak/keycloak.conf), nginx's server names (unknown host names are dropped), and makes a new per-instance certificate for the name, then restarts Keycloak and nginx. Update the redirect URIs of any clients you registered under the old name. To use a certificate from a certificate authority, replace /etc/ssl/keycloak-openldap/server.crt and server.key (keep the key mode 0600, owner root) and run sudo nginx -t && sudo systemctl reload nginx.
Step 11: Use your own directory base DN
The directory starts as dc=example,dc=com. While it holds no users or groups, you can move it to your own base DN in one step; every password stays the same and Keycloak's federation follows:
sudo keycloak-openldap-set-basedn dc=corp,dc=example,dc=com
The command refuses when ou=people or ou=groups already holds entries, or when Keycloak holds users imported from the directory. In that case export your entries (sudo slapcat -n 1), rewrite the DNs, and import them into a directory created with the new base DN.
Step 12: Check the security posture
Every service is blocked from the instance metadata service, and core dumps are off:
systemctl show -p IPAddressDeny -p LimitCORE keycloak slapd nginx postgresql@16-main keycloak-openldap-firstboot
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 168.63.129.16/32 169.254.169.254/32
LimitCORE=0
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 168.63.129.16/32 169.254.169.254/32
LimitCORE=0
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 168.63.129.16/32 169.254.169.254/32
LimitCORE=0
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 168.63.129.16/32 169.254.169.254/32
LimitCORE=0
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 168.63.129.16/32 169.254.169.254/32
LimitCORE=0
PostgreSQL listens on 127.0.0.1 only and only the keycloak role has a password; the postgres superuser is reachable only as the local postgres account:
sudo -u postgres psql -X -tA -c "SHOW listen_addresses" -c "SELECT rolname FROM pg_authid WHERE rolpassword IS NOT NULL"
127.0.0.1
keycloak
The directory refuses anonymous binds and stores passwords as Argon2 hashes, and the service account Keycloak uses can read users but not write:
sudo ldapsearch -Q -LLL -o ldif-wrap=no -Y EXTERNAL -H ldapi:/// -b cn=config '(objectClass=olcGlobal)' olcDisallows olcRequires
sudo ldapsearch -Q -LLL -o ldif-wrap=no -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={1}mdb,cn=config' olcAccess
dn: cn=config
olcDisallows: bind_anon
olcRequires: authc
dn: olcDatabase={1}mdb,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
olcAccess: {1}to attrs=userPassword,shadowLastChange by self =wx by anonymous auth by * none
olcAccess: {2}to dn.subtree="dc=example,dc=com" by dn.exact="cn=keycloak,ou=services,dc=example,dc=com" read by self read by * none
dn: olcOverlay={0}ppolicy,olcDatabase={1}mdb,cn=config
Step 13: Expose LDAPS to your own networks (optional)
By default no LDAP port is reachable from the network: applications sign users in through Keycloak. If systems elsewhere must query the directory directly, serve LDAPS (636) with a certificate and open 636 in the security group to those systems only. A sketch, using the instance's own certificate (replace it with a CA-issued one for production):
sudo install -d -o openldap -g openldap -m 0750 /etc/ldap/tls
sudo install -o openldap -g openldap -m 0600 /etc/ssl/keycloak-openldap/server.key /etc/ldap/tls/ldap.key
sudo install -o openldap -g openldap -m 0644 /etc/ssl/keycloak-openldap/server.crt /etc/ldap/tls/ldap.crt
printf 'dn: cn=config\nchangetype: modify\nreplace: olcTLSCertificateFile\nolcTLSCertificateFile: /etc/ldap/tls/ldap.crt\n-\nreplace: olcTLSCertificateKeyFile\nolcTLSCertificateKeyFile: /etc/ldap/tls/ldap.key\n' | sudo ldapmodify -Q -Y EXTERNAL -H ldapi:///
sudo sed -i 's#ldap://127.0.0.1:389/#ldap://127.0.0.1:389/ ldaps:///#' /etc/systemd/system/slapd.service
sudo systemctl daemon-reload && sudo systemctl restart slapd
Clients then use ldaps://<your-name> and must bind as a user (anonymous binds stay refused). Create a separate read-only service account for each consuming system rather than sharing Keycloak's.
Step 14: Your data and backups
- Keycloak keeps realms, clients, users imported from the directory and sessions in PostgreSQL:
sudo -u postgres pg_dump -Fc keycloak > keycloak-$(date +%F).dump. - The directory is in
/var/lib/ldapand its configuration in/etc/ldap/slapd.d:sudo slapcat -n 1 > directory-$(date +%F).ldifandsudo slapcat -n 0 > config-$(date +%F).ldif. The exports contain password hashes; store them like secrets. - Keep
/root/keycloak-openldap-credentials.txtand/etc/keycloak/keycloak.confwith the backups. For a larger directory, move/var/lib/ldapto its own EBS volume.
Step 15: Licences and source
Keycloak is licensed under the Apache License 2.0; the image runs the unmodified upstream distribution:
cat /usr/share/doc/cloudimg-keycloak-openldap/SOURCE.txt
cat /opt/keycloak/version.txt
Keycloak 26.8.1 (Apache License 2.0, https://www.keycloak.org/) - the upstream community distribution:
https://github.com/keycloak/keycloak/releases/download/26.8.1/keycloak-26.8.1.tar.gz
sha256 4e2740b181faa2ea623a1c2ecf00855935311e546046e2f857615a47ed24cbe8
sha512 b891ae56095dd8536547668b839ff2f63971ed402a976b6be4db2f83cb3f9dd709a321c99b2d92030c81588ec8e1842813e219c5ba3a7ea2f059e98176abe7df
signed by the Keycloak release key 861AB50E8CC6611FB6BC01A6B8F12EA26FD6EEBA (verified at build)
No file is changed; "kc.sh build" (db=postgres, health-enabled=true) generated lib/quarkus. keycloak-tree.sha256 lists
every file of /opt/keycloak (except data/) as built. Source: https://github.com/keycloak/keycloak/tree/26.8.1
OpenLDAP 2.6 (slapd, ldap-utils), PostgreSQL 16, nginx and OpenJDK 21 are Ubuntu 24.04 packages (main); their licences
are in /usr/share/doc/<package>/copyright (OpenLDAP: The OpenLDAP Public License 2.8).
Keycloak - Version 26.8.1
OpenLDAP is distributed under The OpenLDAP Public License 2.8 (/usr/share/doc/slapd/copyright); PostgreSQL, nginx and OpenJDK are Ubuntu packages under their own licences (/usr/share/doc/<package>/copyright).
Step 16: Security notes
- Advisories. No published Keycloak advisory affects 26.8.1, and Ubuntu's OpenLDAP 2.6.10 package has no open advisory. A dependency scan of the Keycloak distribution lists four library advisories with no fixed Keycloak release yet; none is reachable in this configuration: Guava CVE-2026-102554 (Java deserialization of untrusted data, which Keycloak does not do), OpenTelemetry CVE-2026-118259 (
tracestateheader parsing; tracing is off and nginx strips the tracing headers), and MariaDB Connector/J CVE-2026-119210/119276/119280/119281 (the server is built for PostgreSQL, so the MariaDB driver is never loaded). - Temporary admin.
bootstrap-adminis meant to be replaced (Step 6). Keycloak's brute-force protection is on in both realms, and nginx rate-limits sign-in and token requests per client address. - Directory passwords. The directory stores what it is given hashed; Keycloak never sees or stores directory passwords, it asks the directory to check them. Keycloak's federation is read-only: password changes happen in the directory (
ldappasswd). - Deprecated features off. The image disables Keycloak's deprecated
identity-brokering-api:v1andtwitter-broker:v1features.
Support
cloudimg provides support for this image by e-mail at support@cloudimg.co.uk. Keycloak is documented at https://www.keycloak.org/documentation and OpenLDAP at https://www.openldap.org/doc/. Keycloak is a Cloud Native Computing Foundation project and OpenLDAP is a registered trademark of the OpenLDAP Foundation; cloudimg is not affiliated with or endorsed by the CNCF, the Keycloak project, Red Hat or the OpenLDAP Foundation.