Deployment guide

LDAP Account Manager 9.7

Overview

This guide shows you how to launch and use the LDAP Account Manager 9.7 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud 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. LAM adds 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. It is a hardened, ready-to-use directory appliance.

What you get:

  • 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, and Ubuntu's older ldap-account-manager package is not used. Source, licences and the file list are on the image in /usr/share/doc/sac-ldap-account-manager/.
  • HTTPS from the first boot. nginx is the only public listener (ports 80 and 443). It serves a certificate generated on your instance (an end-entity certificate, not a certificate authority), and port 80 redirects to HTTPS. First boot sets the address from the instance's EC2 public DNS name, and you can change it 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=config password, LAM's master configuration password and LAM's server profile password. LAM's well-known default password lam never works, and LAM's "set the master password" page has nothing to offer, because the password exists before the web server starts.
  • An empty directory, created on your instance. The base is dc=example,dc=com (you can change it in Step 12) with ou=people and ou=groups only. There are 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.1 and its local socket only, and 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. 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. Also allow TCP 80 (redirects to HTTPS) if you want plain http:// links to work. LAM is an administration tool, so do not open it to the whole internet. Never open 389 or 636, because 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.
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 select your Region. Then choose Launch through EC2.

Choose m5.large, your key pair and a security group as described above.

Alternatively, launch 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/sac/ldap-account-manager-domain.preset and /etc/sac/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.

2

Connect to your instance

Connect over SSH as the ubuntu user on Ubuntu 24.04:

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

All four services should report active:

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), and nothing listens on 636. Confirm the listeners:

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
4

Find your address, sign-in name and passwords

First boot writes your address and sign-in details to a credentials file. Print it without the password lines:

sudo grep -v PASSWORD /root/ldap-account-manager-credentials.txt

The file is root only (mode 0600). 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 sac-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://secureanycloud.com/stacks/ldap-account-manager-9-7/

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. Each line is used as follows:

LDAP_ADMIN_PASSWORD: signs you in to LAM as admin (the directory administrator cn=admin,<base DN>). LAM checks it by binding to the directory.

LAM_MASTER_PASSWORD: opens LAM configuration, Edit general settings (security settings, password policy, logging).

LAM_PROFILE_PASSWORD: opens LAM configuration, Edit server profiles, profile lam (LDAP server, account types, modules).

LDAP_CONFIG_PASSWORD: unlocks 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. Instead, compare the fingerprint your browser shows with TLS_SHA256, or replace the certificate with one from a certificate authority (Step 11).

5

Run the self-test

Run the built-in self-test:

sudo ldap-account-manager-selftest

The self-test signs in to LAM over HTTPS as the directory administrator (pinned to the instance's own certificate). It checks that a wrong password is refused and that the Users list is not served before sign-in. It then adds a throwaway directory user, checks that LAM lists it and that it can bind with its own password, and checks that anonymous LDAP is refused. Finally, it 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
6

Sign in to LDAP Account Manager

Open https://<your-instance-public-DNS-name>/, which is 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. LAM refuses a wrong password.

After you sign in, you land on the Users list, which is empty on a new instance.

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

Choose Tools > Tree view to see the whole directory.

8

Check the new account from the command line

sac-ldap runs any of the ldap* tools bound as the directory administrator. It reads the password from the credentials file, so the password never appears on a command line or in your shell history. Look up the new group and user:

sudo sac-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

Confirm that LAM stored the password as an Argon2id hash:

sudo sac-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

Check that the user can bind with the password you set. The command prompts 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

Check that 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
9

Review the LAM configuration

The LAM configuration link on the sign-in page leads to two areas. Each has its own password from Step 4: Edit general settings (LAM_MASTER_PASSWORD) and Edit server profiles (profile lam, LAM_PROFILE_PASSWORD). LAM refuses its default password lam.

Enter the instance's master password to open the general settings. SecureAnyCloud sets these defaults: a 30-minute session timeout, Hide LDAP details on failed login switched 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 and lists cn=admin,<base DN> as the user who may sign in. It keeps users in ou=people and groups in ou=groups, and it hashes new passwords with Argon2id. Print a summary of the configuration, 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. To change it, make a hash with sudo slappasswd -o module-load=argon2 -h '{ARGON2}', which prompts for the new password. Replace olcRootPW on olcDatabase={1}mdb,cn=config with that hash through sudo ldapmodify -Y EXTERNAL -H ldapi:///. Then update LDAP_ADMIN_PASSWORD in the credentials file so sac-ldap keeps working.

10

Check what is served over HTTPS

HTTPS serves only LAM's pages (/templates/...) and its static files. It does not serve LAM's configuration files, sessions, temporary files or libraries. Verify this with a request for each path:

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/sac/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. Alternatively, list your networks in /etc/nginx/sac/lam-access.conf (allow 203.0.113.0/24; lines followed by deny all;), then run sudo nginx -t && sudo systemctl reload nginx.

11

Use your own domain and certificate

Point a DNS name at the instance, then run:

sudo ldap-account-manager-set-domain lam.example.com

The command sets nginx's server name (requests for any other name are dropped), sets the name LAM is given, and creates 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 run sudo nginx -t && sudo systemctl reload nginx.

With Let's Encrypt, for example, follow these steps. Open port 80 to the internet. Run sudo apt-get install -y certbot, sudo systemctl stop nginx, sudo certbot certonly --standalone -d lam.example.com and sudo systemctl start nginx. Then copy fullchain.pem and privkey.pem from /etc/letsencrypt/live/lam.example.com/ into place.

To inspect the current certificate, run:

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 = sac 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
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. Run:

sudo ldap-account-manager-set-basedn dc=corp,dc=example,dc=com

The command re-creates the empty directory under the new base with the same instance passwords. It points LAM's server profile at the new base, so you then sign in as cn=admin,dc=corp,dc=example,dc=com, and it updates the credentials file. It refuses once ou=people or ou=groups holds an entry, and it rolls back if anything fails.

To start with your own base, use the preset file from Step 1 instead.

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). Make it readable by openldap, for example in /etc/ldap/tls/.
  • Set olcTLSCertificateFile and olcTLSCertificateKeyFile on cn=config with sudo ldapmodify -Y EXTERNAL -H ldapi:///.
  • Add ldaps:/// to the ExecStart= line of /etc/systemd/system/slapd.service (-h "ldapi:/// ldap://127.0.0.1:389/ ldaps:///"). Then run sudo 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.
14

Check the security posture

Every service is blocked from the instance metadata service, and the AMI also requires IMDSv2. Confirm the block:

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.

Check 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 ports 22 and 443 (and 80 for the redirect) from your own networks only.

15

Back up your data

The directory lives in /var/lib/ldap. LAM's configuration (server profile, account profiles, PDF layouts) lives in /var/lib/ldap-account-manager/config. To list the entries in a directory export, run:

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. Keep the results with /root/ldap-account-manager-credentials.txt somewhere safe, because 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.

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. List the files on the image:

ls /usr/share/doc/sac-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).

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-fpm and php8.3-zip are built from Ubuntu's main php8.3 source but published in the universe component, as is libzip4t64. LAM needs zip support. These packages 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, HttpOnly and SameSite=Strict. LAM submits its own changes with its form token.

Support

SecureAnyCloud provides support for this image by e-mail at sales@secureanycloud.com. 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. SecureAnyCloud is not affiliated with or endorsed by the LDAP Account Manager project, Roland Gruber or the OpenLDAP Foundation.

Deploy on AWS

Launch LDAP Account Manager 9.7 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS