389 Directory Server Roles vs Groups: Differences and Use Cases

Compare groups with managed, filtered, and nested roles in 389 Directory Server. Learn how nsRole, memberOf, and dynamic membership differ.

Published

Updated

Read time 14 min read

Reviewed byDeepak Prasad

389 Directory Server comparison of LDAP groups with member attributes versus roles with computed nsRole membership

Groups and roles both represent membership in 389 Directory Server, but they store and evaluate that membership differently.

  • Groups: Static groups store member DNs on the group entry. Dynamic groups define membership through memberURL and can optionally return server-computed member values when dynamic lists are enabled.
  • Roles identify which roles an individual entry possesses through the computed nsRole attribute.
  • Both can represent static or dynamically determined membership.
  • The correct choice depends on client compatibility, lookup direction, performance, and administration requirements.

Before you start:

IMPORTANT
This comparison chapter uses one existing reference group and creates three role types. It does not repeat the full group lifecycle from users and groups, configure the MemberOf plug-in, or document Class of Service entries. See Class of Service for virtual attributes across a subtree.

Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.


Roles vs groups at a glance

Area Groups Roles
Membership direction Static groups reference member DNs on the group entry; dynamic groups define membership through memberURL Directory Server calculates the roles that apply to each matching entry and exposes those role DNs through nsRole
User-side lookup For static groups, enable the MemberOf plug-in to maintain reverse membership on user entries; dynamic groups are not supported by MemberOf Query the computed nsRole operational attribute
Static membership Static groups (groupOfNames, groupOfUniqueNames) Managed roles
Dynamic membership Dynamic groups (groupOfURLs / memberURL) Filtered roles
Nesting Depends on group and client design Nested roles
Evaluation cost Static groups are generally less expensive; dynamic groups can require search-time filter evaluation More server-side processing
Client compatibility Widely supported Client must understand or query nsRole

Roles move membership evaluation toward the server. Static groups usually require less search-time processing because their member values are stored. Filtered roles and dynamic groups require the server or client to evaluate membership filters.


How groups work in 389 Directory Server

389 Directory Server supports several common group models:

Group model Object class Membership attribute Behavior
Static group groupOfNames member (full DNs) Explicit membership list on the group entry
Unique static group groupOfUniqueNames uniqueMember (full DNs) Same pattern with a different object class
Dynamic group groupOfURLs memberURL Stores an LDAP URL that defines membership. Clients evaluate the URL under traditional behavior; with dynamic lists enabled, Directory Server returns computed member values at search time
Reverse lookup (optional) memberOf on user entries Maintained by the MemberOf plug-in for supported static groups when enabled; existing memberships may require a fixup task
NOTE

389 Directory Server 3.2.0 supports server-side dynamic lists. Enable them with:

bash
dsconf ldap1 backend config set --enable-dynamic-lists on

The change takes effect immediately and does not require a restart. Confirm the configuration with:

bash
dsconf ldap1 backend config get | grep nsslapd-dynamic-lists

Relevant output:

output
nsslapd-dynamic-lists-enabled: on
nsslapd-dynamic-lists-oc: groupOfURLs
nsslapd-dynamic-lists-url-attr: memberUrl
nsslapd-dynamic-lists-attr: member

The server then evaluates memberURL when the dynamic-group entry is searched and returns matching DNs through the computed member attribute. These values are calculated at search time and do not cause the MemberOf plug-in to add memberOf to matching users.

This lab assumes cn=developers already exists from the users and groups chapter. On my lab host that entry is a groupOfNames group with member DNs.

Confirm the group still lists its member with ldapsearch:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "cn=developers,ou=Groups,dc=example,dc=com" -s base member

Sample output:

output
dn: cn=developers,ou=Groups,dc=example,dc=com
member: uid=user1,ou=people,dc=example,dc=com

Membership lives on the group entry. To discover which static groups a user belongs to, search group entries for matching member values, or enable the MemberOf plug-in so the server maintains memberOf on the user entry when static group membership changes. MemberOf does not populate reverse membership for dynamic groupOfURLs groups.


How roles work

Role definitions are LDAP subentries. The server evaluates them and exposes matching role DNs on member entries through the operational nsRole attribute.

Attribute or object Purpose
nsRoleDN Assigns an entry to a managed role
nsRoleFilter Defines membership for a filtered role
nsRole Computed operational attribute showing role membership
Role definition entry Defines the role and its type (nsManagedRoleDefinition, nsFilteredRoleDefinition, or nsNestedRoleDefinition)

nsRole is computed by the Roles plug-in at search time. Directory Server does not store it as an ordinary user attribute you edit directly.

The Roles plug-in is normally enabled by default. It begins returning meaningful nsRole values after you create role-definition subentries within the relevant directory subtree.

Role scope follows the location of the role definition. Role definitions must be placed within the subtree they should govern. Because the lab users are below ou=People,dc=example,dc=com, the following role definitions are created directly below ou=People.


Create and test a managed role

A managed role is similar to a static group because administrators assign each member explicitly. The difference is where that assignment is represented: groups store user DNs on the group entry, while managed roles place the role DN in nsRoleDN on each member entry.

I'll create the managed-role definition as a subentry under ou=People:

ldif
dn: cn=Application Administrators,ou=People,dc=example,dc=com
objectClass: top
objectClass: LDAPsubentry
objectClass: nsRoleDefinition
objectClass: nsSimpleRoleDefinition
objectClass: nsManagedRoleDefinition
cn: Application Administrators
description: Managed role for application administrators

Create the managed role entry with ldapadd:

bash
ldapadd -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f managed-role.ldif

Sample output:

output
adding new entry "cn=Application Administrators,ou=People,dc=example,dc=com"

The adding new entry line means Directory Server accepted the managed-role definition.

I'll assign uid=user1 to the role. Save the modify LDIF as user1-managed-role.ldif, then apply it:

ldif
dn: uid=user1,ou=people,dc=example,dc=com
changetype: modify
add: nsRoleDN
nsRoleDN: cn=Application Administrators,ou=People,dc=example,dc=com

Apply the modify with ldapmodify:

bash
ldapmodify -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f user1-managed-role.ldif

Sample output:

output
modifying entry "uid=user1,ou=people,dc=example,dc=com"

That modify line confirms nsRoleDN was stored on the user entry.

Request nsRole explicitly. Operational attributes are not returned unless you ask for them:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user1,ou=people,dc=example,dc=com" -s base nsRole

Sample output:

output
dn: uid=user1,ou=people,dc=example,dc=com
nsRole: cn=application administrators,ou=people,dc=example,dc=com

The server computed the managed role DN on the user entry. Role DNs in nsRole may appear with normalized casing.

dsidm creates the role below the effective base DN. Use -b to select the subtree explicitly:

bash
dsidm ldap1 -b "ou=People,dc=example,dc=com" role create-managed --cn "Operations Managers"

Sample output:

output
Successfully created Operations Managers

Assign members with nsRoleDN the same way whether you use ldapadd or dsidm.


Create and test a filtered role

A filtered role assigns membership through an LDAP filter, comparable to a dynamic group. Entries that match nsRoleFilter receive the role automatically.

I'll create a second lab user for the filtered-role test. The next step adds departmentNumber on that account:

bash
dsidm ldap1 user create --uid user2 --cn "User Two" --displayName "User Two" --uidNumber 10002 --gidNumber 10002 --homeDirectory /home/user2

Sample output:

output
Successfully created user2

I'll add the filtered-role definition. Save the LDIF as filtered-role.ldif, then load it:

ldif
dn: cn=IT Department Role,ou=People,dc=example,dc=com
objectClass: top
objectClass: LDAPsubentry
objectClass: nsRoleDefinition
objectClass: nsComplexRoleDefinition
objectClass: nsFilteredRoleDefinition
cn: IT Department Role
nsRoleFilter: (departmentNumber=IT)
description: Filtered role for IT department members

Load the role definition with ldapadd:

bash
ldapadd -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f filtered-role.ldif

Sample output:

output
adding new entry "cn=IT Department Role,ou=People,dc=example,dc=com"

Set departmentNumber on the test user. Save as user2-department.ldif, then apply the modify:

ldif
dn: uid=user2,ou=people,dc=example,dc=com
changetype: modify
add: departmentNumber
departmentNumber: IT

Apply the attribute change with ldapmodify:

bash
ldapmodify -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f user2-department.ldif

Sample output:

output
modifying entry "uid=user2,ou=people,dc=example,dc=com"

Verify the computed role on the matching user:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user2,ou=people,dc=example,dc=com" -s base nsRole departmentNumber

Sample output:

output
dn: uid=user2,ou=people,dc=example,dc=com
departmentNumber: IT
nsRole: cn=it department role,ou=people,dc=example,dc=com

You did not add user2 to the role manually. Directory Server assigned the role because the user entry matched (departmentNumber=IT).

Change the attribute and confirm membership updates automatically. Save as user2-sales.ldif, then apply the modify:

ldif
dn: uid=user2,ou=people,dc=example,dc=com
changetype: modify
replace: departmentNumber
departmentNumber: Sales

Apply the department change with ldapmodify:

bash
ldapmodify -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f user2-sales.ldif

Sample output:

output
modifying entry "uid=user2,ou=people,dc=example,dc=com"

Query nsRole again:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user2,ou=people,dc=example,dc=com" -s base nsRole

Sample output:

output
dn: uid=user2,ou=people,dc=example,dc=com

The IT filtered role no longer applies because the entry no longer matches the filter.

dsidm ldap1 role create-filtered prompts for nsRoleFilter interactively when the filter is omitted. Use ldapadd or ldapmodify when you need a repeatable LDIF file with an explicit filter.


Create a nested role

A nested role combines other role definitions. A user who matches any contained role also receives the nested role.

Add the managed role back to user1, then I'll create the nested role. Reapply user1-managed-role.ldif:

ldif
dn: uid=user1,ou=people,dc=example,dc=com
changetype: modify
add: nsRoleDN
nsRoleDN: cn=Application Administrators,ou=People,dc=example,dc=com

Apply the modify with ldapmodify:

bash
ldapmodify -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f user1-managed-role.ldif

Sample output:

output
modifying entry "uid=user1,ou=people,dc=example,dc=com"

Create the nested role that references the managed and filtered roles. Save as nested-role.ldif, then load it:

ldif
dn: cn=Combined IT and App Admins,ou=People,dc=example,dc=com
objectClass: top
objectClass: LDAPsubentry
objectClass: nsRoleDefinition
objectClass: nsComplexRoleDefinition
objectClass: nsNestedRoleDefinition
cn: Combined IT and App Admins
nsRoleDN: cn=Application Administrators,ou=People,dc=example,dc=com
nsRoleDN: cn=IT Department Role,ou=People,dc=example,dc=com
description: Nested role combining managed and filtered roles

Load the nested role with ldapadd:

bash
ldapadd -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f nested-role.ldif

Sample output:

output
adding new entry "cn=Combined IT and App Admins,ou=People,dc=example,dc=com"

Restore user2 to the IT department for the nested-role demonstration. Reapply user2-department.ldif:

ldif
dn: uid=user2,ou=people,dc=example,dc=com
changetype: modify
replace: departmentNumber
departmentNumber: IT

Apply the attribute change with ldapmodify:

bash
ldapmodify -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -f user2-department.ldif

Sample output:

output
modifying entry "uid=user2,ou=people,dc=example,dc=com"

Query user1 (managed role member):

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user1,ou=people,dc=example,dc=com" -s base nsRole

Sample output:

output
dn: uid=user1,ou=people,dc=example,dc=com
nsRole: cn=application administrators,ou=people,dc=example,dc=com
nsRole: cn=combined it and app admins,ou=people,dc=example,dc=com

Query user2 (filtered role member):

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user2,ou=people,dc=example,dc=com" -s base nsRole

Sample output:

output
dn: uid=user2,ou=people,dc=example,dc=com
nsRole: cn=combined it and app admins,ou=people,dc=example,dc=com
nsRole: cn=it department role,ou=people,dc=example,dc=com

Each user receives the nested role through a different child role. user1 qualifies through the managed role assignment; user2 qualifies through the filtered role match.

List role definition subentries (hidden from ordinary subtree searches):

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "ou=People,dc=example,dc=com" -s sub "(&(objectClass=ldapSubentry)(objectClass=nsRoleDefinition))" dn nsRoleFilter

Sample output:

output
dn: cn=Application Administrators,ou=People,dc=example,dc=com
dn: cn=IT Department Role,ou=People,dc=example,dc=com
nsRoleFilter: (departmentNumber=IT)
dn: cn=Combined IT and App Admins,ou=People,dc=example,dc=com

Query group and role membership

Compare the lookup direction for each model:

Question Approach
Group → members Read stored member or uniqueMember values for static groups. For dynamic groups, read computed member values when dynamic lists are enabled; otherwise evaluate the search represented by memberURL
User → static groups Search group entries for the user DN, or request memberOf when MemberOf is configured
User → dynamic groups Evaluate applicable memberURL filters; MemberOf does not provide this relationship
User → roles Request nsRole from the user entry
Role → users Search user entries with (nsRole=<role-DN>)

Read static group members from the group entry:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "cn=developers,ou=Groups,dc=example,dc=com" -s base member

Sample output:

output
dn: cn=developers,ou=Groups,dc=example,dc=com
member: uid=user1,ou=people,dc=example,dc=com

On this lab host, memberOf is empty until you configure the MemberOf plug-in for static groups:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user1,ou=people,dc=example,dc=com" -s base memberOf

Sample output:

output
dn: uid=user1,ou=people,dc=example,dc=com

The DN is returned, but no memberOf attribute appears until MemberOf is enabled and has processed existing group memberships.

Find every user who possesses the IT filtered role:

bash
ldapsearch -x -H ldap://127.0.0.1:389 -D "cn=Directory Manager" -y /root/dm.pw -b "ou=People,dc=example,dc=com" -s sub "(nsRole=cn=IT Department Role,ou=People,dc=example,dc=com)" dn

Sample output:

output
dn: uid=user2,ou=people,dc=example,dc=com

Only entries that currently possess the role DN in their computed nsRole values appear in this result.

Operational attributes such as nsRole and memberOf must appear in the attribute list. A wildcard * request does not return them. Requesting + returns all operational attributes supported for the entry, but naming nsRole or memberOf explicitly is normally better when an application needs only those attributes. See LDAP basics for DN and search-scope fundamentals; use man ldapsearch on the host or the ldapsearch(1) mirror for attribute selection syntax.


When should you use groups?

Choose groups when:

  • Existing applications expect member, uniqueMember, or POSIX group object classes.
  • Client compatibility with standard LDAP group structures is important.
  • Applications, audit tools, or exports must read membership from conventional LDAP group entries.
  • Lower server-side evaluation cost is preferred.
  • Operating-system or application authorization expects POSIX or groupOfNames semantics.

Static groups remain the default choice for application integration and Linux identity mapping.


When should you use roles?

Choose roles when:

  • Applications primarily ask which memberships a user possesses.
  • Membership should be derived from entry attributes (filtered roles).
  • Managed and filtered membership should share one user-side lookup (nsRole).
  • Nested membership is central to the directory design.
  • Role-based account activation or inactivation is required.

Directory Server can inactivate an entire role, causing members to receive a computed nsAccountLock: true state. That can simplify temporary suspension of a department or administrative role, but ACIs must prevent users from removing the attributes that make them members of the inactive role.

Roles fit authorization models that query the user entry rather than enumerate group entries.


Security and performance considerations

  • Restrict who can modify nsRoleDN on managed roles—users who can remove their own assignment bypass role-based lockout unless ACIs prevent it.
  • Protect attributes referenced in nsRoleFilter so users cannot change their department, title, or other filter fields to gain unintended roles.
  • Filtered and nested roles consume more server resources than reading a static member list because Directory Server evaluates filters and role relationships at search time.
  • Test filtered and nested roles against realistic directory sizes before deploying them in production.
  • Index attributes used in nsRoleFilter when the filter runs against large subtrees.
  • Add an equality index on nsRoleDN for managed-role membership searches, and on filter attributes such as departmentNumber for filtered roles. These indexes are not required for a small lab, but they matter when role searches run across large datasets:
bash
dsconf ldap1 backend index add --index-type eq --attr nsRoleDN --reindex userroot

The command creates the equality index and starts reindexing the selected backend.

bash
dsconf ldap1 backend index add --index-type eq --attr departmentNumber --reindex userroot

The second command follows the same pattern for the filtered-role filter attribute.

Replace userroot with your backend name from dsconf ldap1 backend suffix list. Reindexing can take longer on large backends; the lab finishes quickly because the suffix is small.

ACI examples for nsRoleDN and filter attributes belong in ACI examples.


Can roles replace groups completely?

Usually not. Many LDAP applications and authorization systems expect standard group object classes and membership attributes, not nsRole. Linux identity mapping still belongs to POSIX or RFC2307bis-style groups.

Use both models where each fits: groups for application compatibility and POSIX integration; roles for server-computed membership and user-centric authorization queries.


Summary

Requirement Recommended model
Traditional application membership Static group
Attribute-based group membership Dynamic group or filtered role
Query memberships from the user entry Roles through nsRole, or supported static groups through MemberOf
POSIX/Linux group integration POSIX group
Explicit role assignment Managed role
Combine several role definitions Nested role

Groups store membership on the group entry; roles compute nsRole on the member entry. Managed roles provide explicit membership comparable to static groups, while filtered roles provide attribute-based membership comparable to dynamic groups. Choose groups for compatibility and roles when user-side membership evaluation justifies the additional server cost.


What's Next


References


Frequently Asked Questions

1. What is the main difference between groups and roles in 389 Directory Server?

Static groups store member references in member or uniqueMember. Dynamic groups store a memberURL that defines which entries qualify. Roles calculate applicable role DNs and expose them on each matching entry through the operational nsRole attribute. Groups are widely supported by LDAP clients; roles require clients to query nsRole explicitly.

2. When should I use a filtered role instead of a dynamic group?

Use a filtered role when applications primarily ask which roles a user possesses and you want a consistent user-side lookup through nsRole. Use a dynamic group when applications consume groupOfURLs and memberURL, or when server-side dynamic lists are enabled to return computed member values on the group entry. Dynamic membership remains calculated rather than permanently stored, and it does not populate memberOf.

3. Does nsRole replace memberOf?

No. nsRole is a virtual attribute calculated from role definitions. memberOf is maintained by the MemberOf plug-in when membership in supported static groups changes. The MemberOf plug-in does not calculate membership for dynamic groupOfURLs groups. Both attributes can coexist, but they are produced and maintained differently.

4. Can roles replace groups for Linux login mapping?

No. Linux identity clients normally expect a POSIX group schema such as posixGroup with memberUid, or an RFC2307bis-style configuration using DN-valued membership attributes such as member or uniqueMember. Use LDAP/POSIX groups for Linux identity and access mapping unless the client has been explicitly customized to consume nsRole.

5. Why does ldapsearch not list my role definition entries?

Role definitions are LDAP subentries. Normal subtree searches hide them. Search with (&(objectClass=ldapSubentry)(objectClass=nsRoleDefinition)) or request subentries explicitly when you need to list role definition entries.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …