LDAP Account Manager 9.7 on AWS User Guide
Overview
This guide covers launching and using the LDAP Account Manager 9.7 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; you pick it as the software version when you subscribe and launch.
LDAP Account Manager (LAM) is a web interface for managing the users, groups and other entries of an LDAP directory: you create and edit Unix accounts and groups in a browser instead of writing LDIF, with account profiles, PDF export, a tree view, a schema browser and file upload for bulk changes. This image gives you LAM together with its own OpenLDAP directory on one instance, ready to use.
The cloudimg image is a hardened, ready-to-use directory appliance:
- The free LAM edition, unmodified. LAM 9.7 from the upstream release tarball (GPL-3.0-or-later), checked against its published checksum and installed file for file; no LAM Pro file, module or licence key is present. Ubuntu's older
ldap-account-managerpackage is not used. Source, licences and the file list are on the image in/usr/share/doc/cloudimg-ldap-account-manager/. - 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. The address is set from the instance's EC2 public DNS name at first boot and can be changed to your own domain.
- Every password is created on your instance. First boot creates the directory and generates the directory administrator password you sign in with, the
cn=configpassword, LAM's master configuration password and LAM's server profile password. LAM's well-known default passwordlamnever works, and LAM's "set the master password" page has nothing to offer: the password exists before the web server starts. - An empty directory, created on your instance. The base
dc=example,dc=com(you can change it, Step 12) withou=peopleandou=groupsonly: no demo accounts, and no directory from the build ships in the image. - OpenLDAP is not on the network. slapd listens on
127.0.0.1and its local socket only; anonymous bind and search are refused; passwords are stored as Argon2 hashes (the directory hashes any cleartext password it is given), and accounts you create in LAM get Argon2id hashes. - LAM's own files are never served. Only LAM's pages and static assets are reachable over HTTPS; its configuration files, sessions, temporary files and libraries return 404. PHP runs LAM as its own unprivileged user with access limited to LAM's directories and with process execution disabled.
- Real client addresses and rate-limited sign-in. nginx hands LAM the real TCP peer, never a client's own
X-Forwarded-For, so LAM's log shows who signed in or failed, and sign-in attempts are rate limited per client address. - Metadata access blocked. LAM can connect to LDAP servers and other URLs you configure. 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: LDAP Account Manager 9.7, OpenLDAP 2.6 (slapd, ldap-utils), nginx, PHP 8.3 (FPM), 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) and TCP 443 (LAM) from your own networks only, and TCP 80 (redirects to HTTPS) if you want plain
http://links to work. LAM is an administration tool: do not open it to the whole internet. Never open 389 or 636: the directory listens on the loopback address only (Step 13 shows how to offer LDAPS to other systems deliberately). - For production, a DNS name you control (for example
lam.example.com) and a certificate from a certificate authority for it.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick LDAP Account Manager 9.7 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=ldap-account-manager}]'
First boot takes a few seconds after cloud-init has run. To use your own name or your own directory base from the start, put them in /etc/cloudimg/ldap-account-manager-domain.preset and /etc/cloudimg/ldap-account-manager-basedn.preset with user data (for example cloud-init write_files entries); otherwise first boot uses the instance's public DNS name and dc=example,dc=com.
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 ldap-account-manager-firstboot slapd php8.3-fpm nginx
active
active
active
active
Only SSH, HTTP and HTTPS are public. OpenLDAP listens on the loopback address (and on its local socket); nothing listens on 636:
sudo ss -tln | awk '{print $4}' | grep -E ':(22|80|443|389|636)$' | sort -u
0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
127.0.0.1:389
[::]:22
[::]:443
[::]:80
Step 4: Your address, sign-in name and passwords
sudo grep -v PASSWORD /root/ldap-account-manager-credentials.txt
The file (root only, mode 0600) was written by first boot. Without its password lines it reads:
# LDAP Account Manager 9.7 - written on first boot by ldap-account-manager-firstboot.service. Unique to this instance.
LAM_URL=https://ec2-34-238-125-27.compute-1.amazonaws.com/
LAM_LOGIN_USER=admin
LDAP_ADMIN_DN=cn=admin,dc=example,dc=com
LAM_PROFILE=lam
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_GROUPS_DN=ou=groups,dc=example,dc=com
LDAP_CONFIG_DN=cn=admin,cn=config
TLS_SHA256=D7:D0:9F:0E:C9:1F:E1:DB:3D:0B:8C:8F:3E:67:B5:AD:C8:66:36:39:C0:29:B4:2A:F2:C0:F0:5F:5F:3C:C9:73
TLS_SPKI_SHA256=Tl1YyRXzEwUS7picfh9zOtVf7s51q3Z7xq7uGInuXM4=
#
# LAM configuration (top right of the sign-in page, "LAM configuration"):
# OpenLDAP listens on 127.0.0.1 and ldapi:/// only; anonymous bind is disabled. Command line, bound as LDAP_ADMIN_DN
# without a password on the command line: sudo cloudimg-ldap ldapsearch -b dc=example,dc=com uid cn
# 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 ldap-account-manager-set-domain lam.example.com
# Your own base DN (while the directory has no users or groups): sudo ldap-account-manager-set-basedn dc=corp,dc=example,dc=com
# User guide: https://www.cloudimg.co.uk/guides/ldap-account-manager-9-7-on-ubuntu-24-04-aws/
The file also holds four passwords, each unique to your instance; read the one you need when you need it, for example sudo grep '^LDAP_ADMIN_PASSWORD=' /root/ldap-account-manager-credentials.txt:
| Line | What it is for |
|---|---|
LDAP_ADMIN_PASSWORD |
Signing in to LAM as admin (the directory administrator cn=admin,<base DN>). LAM checks it by binding to the directory. |
LAM_MASTER_PASSWORD |
LAM configuration, Edit general settings (security settings, password policy, logging). |
LAM_PROFILE_PASSWORD |
LAM configuration, Edit server profiles, profile lam (LDAP server, account types, modules). |
LDAP_CONFIG_PASSWORD |
The directory's own configuration (cn=admin,cn=config), for ldapmodify on cn=config. Root can also use sudo ldapmodify -Y EXTERNAL -H ldapi:///. |
The certificate is self-signed and unique to your instance. Do not add it to a trust store: compare the fingerprint your browser shows with TLS_SHA256, or replace the certificate with one from a certificate authority (Step 11).
Step 5: Run the self-test
sudo ldap-account-manager-selftest
It signs in to LAM over HTTPS as the directory administrator (pinned to the instance's own certificate), checks that a wrong password is refused and that the Users list is not served before sign-in, adds a throwaway directory user, checks that LAM lists it and that it can bind with its own password, checks that anonymous LDAP is refused, and removes the user again:
round trip OK: LAM sign-in (cn=admin,dc=example,dc=com) over pinned HTTPS; wrong password 403; list hidden before sign-in; directory user shown in LAM and bound; anonymous LDAP refused
LAM_SELFTEST_OK
Step 6: Sign in to LDAP Account Manager
Open https://<your-instance-public-DNS-name>/ (the LAM_URL from Step 4). Your browser warns about the self-signed certificate: check that the fingerprint it shows matches TLS_SHA256, then continue. The sign-in page offers one user, admin (cn=admin,dc=example,dc=com):

Enter LDAP_ADMIN_PASSWORD. A wrong password is refused:

After signing in you land on the Users list, which is empty on a new instance.
Step 7: Create a group and a user
A Unix user needs a primary group, so create the group first. Choose Accounts > Groups, then New group, enter a Group name (for example staff) and click Save:

Then choose Accounts > Users, New user. On the Personal tab enter the first and last name and an e-mail address. On the Unix tab LAM proposes a user name; choose the Primary group you just made:

Click Set password, enter the user's password twice (untick Force password change if the user signs in only with this password), click Ok, then Save. The user appears in the list:

Tools > Tree view shows the whole directory:

Step 8: Check the new account from the command line
cloudimg-ldap runs any of the ldap* tools bound as the directory administrator, reading the password from the credentials file, so it never appears on a command line or in your shell history:
sudo cloudimg-ldap ldapsearch -LLL -b dc=example,dc=com '(|(uid=alice)(cn=staff))' uid cn uidNumber gidNumber homeDirectory loginShell
dn: cn=staff,ou=groups,dc=example,dc=com
gidNumber: 10000
cn: staff
dn: uid=alice,ou=people,dc=example,dc=com
loginShell: /bin/bash
homeDirectory: /home/alice
uid: alice
cn: Alice Example
uidNumber: 10000
gidNumber: 10000
LAM stored the password as an Argon2id hash:
sudo cloudimg-ldap ldapsearch -LLL -o ldif-wrap=no -b uid=alice,ou=people,dc=example,dc=com -s base userPassword | sed -n 's/^userPassword:: //p' | base64 -d | cut -c1-17; echo
{ARGON2}$argon2id
The user can bind with the password you set (you are prompted for it):
ldapwhoami -x -H ldap://127.0.0.1:389 -D uid=alice,ou=people,dc=example,dc=com -W
dn:uid=alice,ou=people,dc=example,dc=com
Anonymous access is refused (the command succeeds only if the anonymous bind fails):
! ldapwhoami -x -H ldap://127.0.0.1:389 && echo "anonymous bind refused"
ldap_bind: Inappropriate authentication (48)
additional info: anonymous bind disallowed
anonymous bind refused
Step 9: LAM configuration
The LAM configuration link on the sign-in page leads to two areas, each with its own password from Step 4: Edit general settings (LAM_MASTER_PASSWORD) and Edit server profiles (profile lam, LAM_PROFILE_PASSWORD). LAM's default password lam is refused:

With the instance's master password the general settings open. cloudimg's defaults: a 30-minute session timeout, Hide LDAP details on failed login on, a 12-character minimum for passwords set through LAM, and logging to the system log:

The server profile lam points LAM at ldap://127.0.0.1:389, lists cn=admin,<base DN> as the user who may sign in, keeps users in ou=people and groups in ou=groups, and hashes new passwords with Argon2id. A summary, without any password:
sudo ldap-account-manager-config show | python3 -m json.tool
{
"profiles": [
"lam"
],
"default": "lam",
"mainHash": "{CRYPT-SHA512}$6$",
"hideLoginErrorDetails": "true",
"externalPwdCheckUrl": "",
"lam": {
"url": "ldap://127.0.0.1:389",
"admins": "cn=admin,dc=example,dc=com",
"user": "ou=people,dc=example,dc=com",
"group": "ou=groups,dc=example,dc=com",
"login": "list",
"hash": "ARGON2ID",
"pwHash": "{CRYPT-SHA512}$6$"
}
}
To change a LAM password, use Edit general settings > Change master password or Edit server profiles > Manage server profiles > Set profile password, then update the credentials file. The directory administrator cn=admin,<base DN> is the directory's root account, so its password lives in the directory configuration, not in an entry: make a hash with sudo slappasswd -o module-load=argon2 -h '{ARGON2}' (it prompts for the new password), replace olcRootPW on olcDatabase={1}mdb,cn=config with it through sudo ldapmodify -Y EXTERNAL -H ldapi:///, then update LDAP_ADMIN_PASSWORD in the credentials file so cloudimg-ldap keeps working.
Step 10: What is served over HTTPS
Only LAM's pages (/templates/...) and its static files are served. Its configuration files, sessions, temporary files and libraries are not:
for p in /config/config.cfg /config/lam.conf /sess/ /tmp/ /lib/config.inc /templates/login.php; do printf '%-22s %s\n' "$p" "$(curl -s -o /dev/null -w '%{http_code}' --cacert /etc/ssl/ldap-account-manager/server.crt https://$(cat /etc/cloudimg/ldap-account-manager-domain)$p)"; done
/config/config.cfg 404
/config/lam.conf 404
/sess/ 404
/tmp/ 404
/lib/config.inc 404
/templates/login.php 200
To limit who can reach LAM at all, restrict port 443 in the security group, or list your networks in /etc/nginx/cloudimg/lam-access.conf (allow 203.0.113.0/24; lines followed by deny all;), then run sudo nginx -t && sudo systemctl reload nginx.
Step 11: Use your own domain and certificate
Point a DNS name at the instance, then:
sudo ldap-account-manager-set-domain lam.example.com
It sets nginx's server name (requests for any other name are dropped), the name LAM is given, and a new self-signed certificate for that name. To use a certificate from a certificate authority instead, put the certificate chain and key in /etc/ssl/ldap-account-manager/server.crt and server.key (key mode 0600), then sudo nginx -t && sudo systemctl reload nginx. With Let's Encrypt, for example: open port 80 to the internet, sudo apt-get install -y certbot, sudo systemctl stop nginx, sudo certbot certonly --standalone -d lam.example.com, sudo systemctl start nginx, then copy fullchain.pem and privkey.pem from /etc/letsencrypt/live/lam.example.com/ into place. The current certificate:
openssl x509 -in /etc/ssl/ldap-account-manager/server.crt -noout -subject -ext basicConstraints,keyUsage,extendedKeyUsage,subjectAltName
subject=CN = ec2-34-238-125-27.compute-1.amazonaws.com, O = cloudimg
X509v3 Subject Alternative Name:
DNS:ec2-34-238-125-27.compute-1.amazonaws.com, DNS:ip-172-31-92-244.ec2.internal, IP Address:34.238.125.27, IP Address:172.31.92.244, IP Address:127.0.0.1
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
Step 12: Use your own directory base
While the directory holds no users or groups, you can move it to your own base, for example dc=corp,dc=example,dc=com:
sudo ldap-account-manager-set-basedn dc=corp,dc=example,dc=com
It re-creates the empty directory under the new base with the same instance passwords, points LAM's server profile at it (you then sign in as cn=admin,dc=corp,dc=example,dc=com) and updates the credentials file. It refuses once ou=people or ou=groups holds an entry, and rolls back if anything fails. To start with your own base, use the preset file from Step 1 instead.
Step 13: Offer LDAPS to other systems (optional)
By design the directory is reachable only on the instance. If other systems (for example Linux hosts with SSSD) must use it, expose LDAPS on 636 deliberately and only to their networks:
- Mint a certificate for the name those systems use (or use one from your certificate authority), readable by
openldap, for example in/etc/ldap/tls/. - Set
olcTLSCertificateFileandolcTLSCertificateKeyFileoncn=configwithsudo ldapmodify -Y EXTERNAL -H ldapi:///. - Add
ldaps:///to theExecStart=line of/etc/systemd/system/slapd.service(-h "ldapi:/// ldap://127.0.0.1:389/ ldaps:///"), runsudo systemctl daemon-reload && sudo systemctl restart slapd. - Open TCP 636 in the security group to those networks only. Give each system its own read-only bind account rather than
cn=admin; anonymous bind stays disabled.
Step 14: Check the security posture
Every service is blocked from the instance metadata service (the AMI also requires IMDSv2):
systemctl show -p IPAddressDeny slapd php8.3-fpm nginx ldap-account-manager-firstboot
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 169.254.169.254/32 168.63.129.16/32
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 169.254.169.254/32 168.63.129.16/32
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 169.254.169.254/32 168.63.129.16/32
IPAddressDeny=fd00:ec2::254/128 ::ffff:169.254.169.254/128 169.254.169.254/32 168.63.129.16/32
LAM itself makes outbound connections only to what you configure: the LDAP server of a server profile, the optional external password-check service and the "Import from server" button for LDAPS certificates in the general settings. All of them run inside PHP-FPM, which cannot reach the metadata service.
The versions on your instance:
cat /usr/share/ldap-account-manager/VERSION; dpkg-query -W -f='${Package} ${Version}\n' slapd nginx php8.3-fpm
9.7
nginx 1.24.0-2ubuntu7.19
php8.3-fpm 8.3.6-0ubuntu0.24.04.13
slapd 2.6.10+dfsg-0ubuntu0.24.04.1
Your security group should allow 22 and 443 (and 80 for the redirect) from your own networks only.
Step 15: Your data and backups
The directory lives in /var/lib/ldap and LAM's configuration (server profile, account profiles, PDF layouts) in /var/lib/ldap-account-manager/config. A directory export and a configuration copy:
sudo slapcat -n 1 | grep '^dn:'
dn: dc=example,dc=com
dn: ou=people,dc=example,dc=com
dn: ou=groups,dc=example,dc=com
dn: cn=staff,ou=groups,dc=example,dc=com
dn: uid=alice,ou=people,dc=example,dc=com
For a full backup run sudo slapcat -n 0 -l config.ldif, sudo slapcat -n 1 -l data.ldif and sudo tar -C /var/lib/ldap-account-manager -czf lam-config.tgz config, and keep them with /root/ldap-account-manager-credentials.txt somewhere safe: the exports contain password hashes. EBS snapshots of the root volume are the simplest whole-instance backup; for a larger directory, move /var/lib/ldap to its own EBS volume.
Step 16: Licences and source
LDAP Account Manager is licensed under the GNU General Public License, version 3 or later; its bundled libraries carry their own open source licences, listed in the upstream copyright file and the CycloneDX SBOM:
ls /usr/share/doc/cloudimg-ldap-account-manager/
LICENSE-ldap-account-manager-GPL-3.0.txt
SOURCE.txt
copyright-ldap-account-manager.txt
lam-tree.sha256
sbom-ldap-account-manager-9.7.cdx.json
SOURCE.txt names the upstream release tarball and its checksum; the tarball is the complete source, and lam-tree.sha256 lists every installed file with its checksum. OpenLDAP, nginx and PHP are Ubuntu packages (/usr/share/doc/<package>/copyright).
Step 17: Security notes
- Advisories. No published advisory affects LAM 9.7 (the most recent, CVE-2026-55167, was fixed in 9.6). The bundled PHP and JavaScript libraries had no known advisory at build time.
- PHP from Ubuntu universe.
php8.3-fpmandphp8.3-zipare built from Ubuntu's mainphp8.3source but published in the universe component, as islibzip4t64; LAM needs zip support. They receive the same security updates as the rest of PHP 8.3, and the image was checked for fixes available only through Ubuntu Pro (none). - The administrator is the directory root. LAM signs in as
cn=admin, the directory's root account, which is not subject to access rules. Keep its password safe; for day-to-day work you can add more LAM users later (each must be able to bind to the directory and write the entries they manage). - Session cookies are
Secure,HttpOnlyandSameSite=Strict; LAM's own changes are submitted with its form token.
Support
cloudimg provides support for this image by e-mail at support@cloudimg.co.uk. LDAP Account Manager is documented at https://www.ldap-account-manager.org/lamcms/documentation. LDAP Account Manager is developed by Roland Gruber; OpenLDAP is a registered trademark of the OpenLDAP Foundation. Both names are used only to identify the software; cloudimg is not affiliated with or endorsed by the LDAP Account Manager project, Roland Gruber or the OpenLDAP Foundation.