Learn LDAP - Adding & Managing Entries
Series/Learn LDAP/Episode 7
Episode 7 of 31

Learn LDAP - Adding & Managing Entries

Populating the directory from scratch: planning the domain and organizational unit structure, adding users with inetOrgPerson and posixAccount, creating groups with groupOfNames, and batch operations with ldapadd.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 6 you mastered the client tools and the LDIF format. Now it's time to use them: episode 7 covers real directory population, from planning the directory tree structure, creating the domain entry and organizational units, adding users with ldapadd, creating groups, to importing many entries at once via batch operations.

Planning the Directory Structure

Before adding your first entry, design the shape of the tree first. A tidy directory structure (DIT) determines how easy ACLs and searches will be in the following episodes. The basic principles:

  • One root entry as a domain component, e.g. dc=example,dc=com.
  • Split entities by function, not per person, using ou= (organizational unit).
  • Keep users in their own OU and groups in their own OU so ACLs and filters are sharper.
  • Plan for growth: adding a department means adding an OU branch, not restructuring.

A commonly used layout: dc=example,dc=com at the top, then ou=People for all users and ou=Groups for all groups. If the organization grows, you can add branches like ou=Contractors or ou=Departments without moving existing entries.

Creating the Base Structure with ldapadd

The base structure consists of a domain entry and two OUs. Save them in a single LDIF file:

struktur-dasar.ldif
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
o: Example Inc
 
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People
 
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups

Import with ldapadd:

Adding the base structure
ldapadd -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f struktur-dasar.ldif

The -f option reads the whole file at once; entries are separated by blank lines. After running it, check the result with ldapsearch -x -b dc=example,dc=com -s sub "(objectClass=*)" and make sure all three entries appear.

Note

The dc=example,dc=com entry must be created first because LDAP is hierarchical — a child entry cannot exist before its parent. The dpkg-reconfigure slapd configuration in episode 5 usually creates this domain entry during installation, so just make sure it's there.

Adding Users

A user entry in LDIF

A user is represented with a combination of object classes. The standard for enterprise directories:

  • inetOrgPerson — personal attributes like cn, sn, givenName, and mail.
  • posixAccount — Unix attributes like uidNumber, gidNumber, homeDirectory, and loginShell.
budi.ldif
dn: uid=budi,ou=People,dc=example,dc=com
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
uid: budi
cn: Budi Santoso
sn: Santoso
givenName: Budi
mail: budi@example.com
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/budi
loginShell: /bin/bash
userPassword: {SSHA}1K0vX...

Required rules: inetOrgPerson requires cn and sn; posixAccount requires uid, uidNumber, gidNumber, and homeDirectory. The uidNumber and gidNumber values must be unique so they don't collide when used by the system.

Hash passwords, don't store plaintext

Never fill the userPassword attribute with a raw password. Create a hash first with slappasswd:

Creating a password hash
slappasswd
New password:
Re-enter new password:
{SSHA}1K0vX...

OpenLDAP 2.5 supports the salted hashes SSHA, SSHA256, SSHA512, as well as CRYPT and ARGON2 (if the module is built). The generated hash is then copied into userPassword in the LDIF. Full details on hashing are covered in episode 12.

Add the user with ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f budi.ldif.

Important

Always write userPassword as a hash from slappasswd, never as plain text. In real environments, plain text can easily be read by anyone with read access to this attribute.

Adding Groups

Groups are split into two needs: groups for directory management and groups for Unix mapping.

  • groupOfNames — requires cn and at least one member, suitable for application groups.
  • posixGroup — requires cn and gidNumber, uses memberUid for a Unix-style member list.

The two object classes are often combined in one entry:

group-devel.ldif
dn: cn=devel,ou=Groups,dc=example,dc=com
objectClass: groupOfNames
objectClass: posixGroup
cn: devel
gidNumber: 1001
member: uid=budi,ou=People,dc=example,dc=com
member: uid=sari,ou=People,dc=example,dc=com
memberUid: budi
memberUid: sari

Members are filled as full DNs in the member attribute. The memberOf attribute on the user side doesn't need to be filled manually — it's maintained automatically by the memberOf overlay you'll enable in episode 11.

Add it with ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f group-devel.ldif.

Batch Operations

Many entries in one file

An LDIF file can hold many entries at once — separate them with blank lines, and each entry still starts with dn::

semua-user.ldif
dn: uid=sari,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: sari
cn: Sari Wulandari
sn: Wulandari
uidNumber: 1002
gidNumber: 1001
homeDirectory: /home/sari
 
dn: uid=aji,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
uid: aji
cn: Aji Pratama
sn: Pratama
uidNumber: 1003
gidNumber: 1001
homeDirectory: /home/aji

Import scripts and error handling

For large volumes, the import can be called repeatedly from a script. Note two default behaviors: ldapadd stops on the first error, and its return code reflects success. Add -c to continue even when some entries fail:

Import in continue mode
ldapadd -c -x -D "cn=admin,dc=example,dc=com" -W -f semua-user.ldif

About transactions

LDAP doesn't guarantee full atomicity like a relational database: each entry is processed as a separate operation. If one file holds a hundred entries and entry 50 fails, entries 1 through 49 are still stored. That's why you should test files on a development server, and for changes that must be all-or-nothing, split them into small files verified in stages.

Closing

Episode 7 takes the directory from empty to populated: planning the domain and OU structure, creating user entries with inetOrgPerson plus posixAccount, groups with groupOfNames plus posixGroup, password hashing via slappasswd, and batch operations with -c mode.

Key takeaways:

  • Design the DIT before populating data — structure determines how easy ACLs will be later.
  • inetOrgPerson needs cn and sn; posixAccount needs uid, uidNumber, gidNumber, homeDirectory.
  • Never write a plaintext password in userPassword — always hash with slappasswd.
  • LDAP operations aren't fully transactional; test in a development environment first.

In the next episode, episode 8, you'll modify and delete what you've built: adding, replacing, and removing attributes, renaming RDNs, moving entries, and safely deleting entries.