Production-grade make-ldif templates and shell scripts for generating realistic LDAP test data in ForgeRock Directory Services (DS).
Stop writing LDAP test data by hand. This repo gives you runnable templates that generate thousands of realistic users, nested groups, service accounts, and org hierarchies — ready to import into ForgeRock DS.
➡ Advanced Techniques for Generating Test Data Using make-ldif in ForgeRock DS
Related articles:
- Initializing ForgeRock DS from LDIF Files: A Step-by-Step Guide
- Extracting and Mapping Attributes from LDIF for ForgeRock IDM
- Validating IDM Mappings with Simulated LDIF Data
- IAMDevBox.com — Identity & Access Management Blog
- Production-grade make-ldif templates — users, groups, service accounts, org hierarchy
- Nested group generation — multi-level group trees with configurable depth
- Realistic fake data — names, emails, departments, phone numbers
- Shell scripts — generate + import in one command
- Docker Compose — spin up ForgeRock DS with test data pre-loaded
- Scalable — tested with 10K, 100K, and 1M entries
git clone https://github.com/IAMDevBox/forgerock-ds-test-data.git
cd forgerock-ds-test-data
# Option 1: Generate LDIF only
./scripts/generate.sh --count 1000 --output output/test-data.ldif
# Option 2: Generate + import into running DS instance
./scripts/generate-and-import.sh \
--count 5000 \
--host localhost \
--port 1636 \
--bind-dn "cn=Directory Manager" \
--bind-password "password"
# Option 3: Docker Compose (DS + pre-loaded test data)
docker compose up -dforgerock-ds-test-data/
├── templates/
│ ├── users-basic.template # Simple user entries (100-10K scale)
│ ├── users-realistic.template # Users with full attributes + departments
│ ├── groups-nested.template # Multi-level nested group hierarchy
│ ├── service-accounts.template # Service accounts with restricted attributes
│ ├── org-hierarchy.template # Organization units + users + groups
│ └── combined.template # Full enterprise directory scenario
├── scripts/
│ ├── generate.sh # Run make-ldif with a template
│ ├── generate-and-import.sh # Generate + ldapmodify in one step
│ ├── validate-ldif.sh # Validate generated LDIF before import
│ └── cleanup.sh # Remove test data by base DN
├── docker/
│ ├── docker-compose.yml # ForgeRock DS 7.x with test data
│ ├── Dockerfile # DS image with make-ldif pre-configured
│ └── setup.sh # Bootstraps DS + imports test data
├── examples/
│ ├── 1000-users.ldif # Pre-generated sample (1K users)
│ └── enterprise-scenario.ldif # Pre-generated enterprise scenario
├── tests/
│ └── validate_ldif.py # Python script to validate LDIF structure
└── README.md
Generates minimal inetOrgPerson entries. Fastest for bulk testing.
./scripts/generate.sh --template templates/users-basic.template --count 10000Generated entry example:
dn: uid=user-0001,ou=people,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: user-0001
cn: User 0001
sn: Last0001
givenName: User
mail: user-0001@example.com
userPassword: {SSHA}changeit
Generates users with departments, job titles, managers, phone numbers, and employee IDs. Best for IDM mapping tests.
./scripts/generate.sh --template templates/users-realistic.template --count 5000Generated entry example:
dn: uid=jsmith-0042,ou=people,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: extensibleObject
uid: jsmith-0042
cn: Jane Smith
sn: Smith
givenName: Jane
mail: jsmith-0042@corp.example.com
telephoneNumber: +1-555-0042
departmentNumber: ENG-200
employeeNumber: EMP-0042
title: Senior Engineer
manager: uid=mgr-0008,ou=people,dc=example,dc=com
userPassword: {SSHA}changeit
Generates a 3-level group tree: Division → Department → Team. Each team contains 5-15 users.
./scripts/generate.sh --template templates/groups-nested.template --count 500Structure:
cn=Engineering,ou=groups,dc=example,dc=com
└── cn=Platform-Team,ou=groups,dc=example,dc=com
└── cn=Backend-Squad,ou=groups,dc=example,dc=com
├── uid=dev-001,ou=people,dc=example,dc=com
└── uid=dev-002,ou=people,dc=example,dc=com
Generates service accounts with constrained attributes (no personal info, explicit purpose tags).
./scripts/generate.sh --template templates/service-accounts.template --count 50Generates a complete enterprise directory: 5K users, 200 groups (nested 3 levels), 50 service accounts, 10 OUs.
./scripts/generate.sh --template templates/combined.template./scripts/generate.sh [OPTIONS]
Options:
--template FILE Template file (default: templates/users-basic.template)
--count N Number of primary records (default: 1000)
--suffix DN Base DN suffix (default: dc=example,dc=com)
--output FILE Output LDIF file (default: output/generated.ldif)
--ds-home PATH ForgeRock DS home dir (default: /opt/opendj)
--help Show this help./scripts/generate-and-import.sh [OPTIONS]
Options:
--count N Number of entries (default: 1000)
--host HOST DS hostname (default: localhost)
--port PORT DS LDAPS port (default: 1636)
--bind-dn DN Bind DN (default: cn=Directory Manager)
--bind-password PW Bind password (default: password)
--suffix DN Base DN (default: dc=example,dc=com)
--no-ssl Use plain LDAP instead of LDAPSSpin up a ForgeRock DS 7.x instance with 1000 test users pre-loaded:
docker compose up -d
# Wait for DS to be ready
docker compose logs -f ds | grep "The server has started"
# Verify test data
ldapsearch -H ldap://localhost:1389 \
-D "cn=Directory Manager" -w password \
-b "dc=example,dc=com" "(objectClass=inetOrgPerson)" uid cn mail | head -30The Docker setup:
- Starts ForgeRock DS 7.x
- Creates the
dc=example,dc=comsuffix - Generates 1000 users via
make-ldif - Imports the LDIF on first boot
| Entry Count | Template | Generation Time | Import Time |
|---|---|---|---|
| 1,000 | users-basic | ~1s | ~5s |
| 10,000 | users-realistic | ~8s | ~45s |
| 100,000 | users-realistic | ~75s | ~8min |
| 1,000,000 | users-basic | ~12min | ~90min |
For 100K+ entries, use offline import via import-ldif instead of ldapmodify:
# Offline bulk import (much faster for large datasets)
/opt/opendj/bin/import-ldif \
--backendID userRoot \
--ldifFile output/generated.ldif \
--isCompressed falseBefore using in staging/prod pipelines:
- Verify no real employee data in templates
- All passwords are
{SSHA}changeitor test-only hashes - Domain is
example.com, not a real company domain - No real certificate data embedded
- Email addresses use
@example.comor@corp.example.com
- ForgeRock DS 6.5+ / OpenDJ 3.5+ (for
make-ldifbinary) - Bash 4.x+
- For Docker: Docker 20.10+, Docker Compose 2.x
- For Python validator: Python 3.8+
MIT — free to use, fork, and adapt for your own IAM projects.
- 🌐 IAMDevBox.com — IAM engineering blog
- 📖 make-ldif Tutorial
- 🔧 ForgeRock DS LDIF Import Guide
- 🗺 IAM Tools Comparison