Skip to content

Portal | Level: L2: Operations | Topics: LDAP & Identity Management, Linux Hardening, Least Privilege | Domain: Security

LDAP & Identity Management - Primer

Why This Matters

Every organization with more than a handful of servers needs centralized identity management. Without it, you are managing local user accounts on every box, which means inconsistent access, orphaned accounts, and audit nightmares. LDAP is the protocol that glues it all together — it backs Active Directory, FreeIPA, OpenLDAP, and virtually every enterprise identity system.

Understanding LDAP is not about becoming a directory admin. It is about knowing how Linux authentication works end-to-end: from a user typing their password to PAM checking SSSD to SSSD querying LDAP (or Kerberos). When login fails at 2 AM, you need to know where in that chain the problem lives.


The LDAP Data Model

LDAP is a hierarchical directory — think of it as a tree (technically a DAG) of entries.

Name origin: LDAP stands for Lightweight Directory Access Protocol. The "lightweight" is relative to its predecessor, the X.500 Directory Access Protocol (DAP), which required the full OSI stack. LDAP stripped it down to run over TCP/IP. It was created by Tim Howes, Steve Kille, and Wengyik Yeong at the University of Michigan in 1993 (RFC 1487).

                dc=example,dc=com                    (root / base DN)
               /                  \
    ou=People                     ou=Groups
    /    |    \                   /       \
uid=alice  uid=bob  uid=carol  cn=devops  cn=dba

Key Terminology

Term Meaning Example
DN Distinguished Name (full path to entry) uid=alice,ou=People,dc=example,dc=com
RDN Relative DN (just this entry's name) uid=alice
Base DN Root of the search tree dc=example,dc=com
OU Organizational Unit (container) ou=People
CN Common Name cn=devops
DC Domain Component dc=example
objectClass Schema type of entry inetOrgPerson, posixAccount
Attribute Key-value property of an entry mail=alice@example.com

Entry Structure

An LDAP entry is a set of attributes:

dn: uid=alice,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: alice
cn: Alice Smith
sn: Smith
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/alice
loginShell: /bin/bash
mail: alice@example.com
userPassword: {SSHA}encrypted_hash_here

LDAP Operations

BIND      authenticate to the directory
SEARCH    query entries (the most common operation)
ADD       create a new entry
MODIFY    change attributes of an entry
DELETE    remove an entry
MODRDN    rename an entry
COMPARE   test if an attribute has a specific value
UNBIND    close the connection

LDAP Search Filters

Filters are how you query LDAP. The syntax is prefix notation:

# Simple equality
(uid=alice)

# Wildcard
(cn=Alice*)

# AND (all conditions must match)
(&(objectClass=posixAccount)(uidNumber>=1000))

# OR (any condition matches)
(|(uid=alice)(uid=bob))

# NOT
(!(loginShell=/bin/false))

# Combined
(&(objectClass=posixAccount)(|(memberOf=cn=devops,ou=Groups,dc=example,dc=com)(uid=admin)))

Search Scope

base      search only the base DN itself
one       search direct children of base DN
sub       search entire subtree (most common)

The Linux Authentication Stack

When a user logs in to a Linux machine, the request flows through:

User types password
┌──────────────┐
│    PAM        │  Pluggable Authentication Modules
│  (pam stack)  │  /etc/pam.d/
└──────┬───────┘
┌──────────────┐
│    NSS        │  Name Service Switch
│ /etc/nsswitch │  maps uid -> username, etc.
└──────┬───────┘
┌──────────────┐
│    SSSD       │  System Security Services Daemon
│   (cache +    │  /etc/sssd/sssd.conf
│    backend)   │
└──────┬───────┘
┌──────────────┐
│  LDAP / AD /  │  Backend identity provider
│  FreeIPA      │
└──────────────┘

PAM (Pluggable Authentication Modules)

PAM is a framework that lets you stack authentication methods. Each service (sshd, sudo, login) has a PAM config:

# /etc/pam.d/sshd
auth       required     pam_sepermit.so
auth       sufficient   pam_sss.so forward_pass
auth       required     pam_unix.so use_first_pass
auth       required     pam_deny.so

account    required     pam_unix.so
account    sufficient   pam_sss.so
account    required     pam_permit.so

password   sufficient   pam_sss.so
password   required     pam_unix.so

session    required     pam_mkhomedir.so skel=/etc/skel/ umask=077
session    required     pam_unix.so
session    optional     pam_sss.so

PAM Control Flags

required     must pass; failure is fatal but continues checking
requisite    must pass; failure stops immediately
sufficient   if passes, skip remaining modules in this stack
optional     result only matters if it's the only module

The order matters enormously. A misplaced sufficient can bypass all subsequent checks.

Remember: PAM control flags mnemonic: Requisite Rejects immediately, Required Records failure but continues, Sufficient Stops on success. Think "RR stops, RR continues, S skips."

Gotcha: If you put pam_sss.so as sufficient before pam_unix.so, and SSSD is down, local users in /etc/passwd can still log in. But if you reverse the order and make pam_unix.so sufficient first, LDAP-only users will never be checked when local auth fails.

NSS (Name Service Switch)

# /etc/nsswitch.conf
passwd:     files sss
group:      files sss
shadow:     files sss
hosts:      files dns

This says: look up users first in /etc/passwd, then ask SSSD. Same for groups.


SSSD — The Glue Daemon

SSSD is the modern way to connect Linux to LDAP/AD/FreeIPA. It handles:

  • Authentication (password check)
  • Identity (user/group lookup)
  • Caching (works offline if cache is warm)
  • Kerberos ticket management

Basic SSSD Config for LDAP

# /etc/sssd/sssd.conf  (must be mode 0600!)
[sssd]
domains = example.com
services = nss, pam

[domain/example.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldaps://ldap.example.com
ldap_search_base = dc=example,dc=com
ldap_tls_reqcert = demand
ldap_tls_cacert = /etc/pki/tls/certs/ca-bundle.crt

# User/group mappings
ldap_user_search_base = ou=People,dc=example,dc=com
ldap_group_search_base = ou=Groups,dc=example,dc=com

# Cache settings
cache_credentials = true
entry_cache_timeout = 300

# Enumeration (set false for large directories)
enumerate = false

Debug clue: When SSSD authentication fails, the first place to look is /var/log/sssd/sssd_<domain>.log. Set debug_level = 6 in the [domain/...] section of sssd.conf for verbose output. After changing debug level, restart SSSD — it does not pick up debug level changes on SIGHUP.

SSSD for Active Directory

[domain/ad.example.com]
id_provider = ad
auth_provider = ad
access_provider = ad
ad_domain = ad.example.com
ad_server = dc1.ad.example.com
krb5_realm = AD.EXAMPLE.COM

# Use POSIX attributes from AD (if configured)
ldap_id_mapping = false

# Or let SSSD auto-map SIDs to UIDs
ldap_id_mapping = true

# Filter allowed groups
ad_access_filter = memberOf=CN=LinuxAdmins,OU=Groups,DC=ad,DC=example,DC=com

Kerberos Basics

Kerberos provides single-sign-on (SSO) by issuing time-limited tickets:

Name origin: Kerberos is named after the three-headed dog (Cerberus) from Greek mythology that guards the gates of the underworld. The three "heads" of the protocol are the client, the server, and the Key Distribution Center (KDC). Developed at MIT as part of Project Athena in the 1980s.

1. User authenticates to KDC (Key Distribution Center)
   → Receives TGT (Ticket Granting Ticket)

2. User requests access to service
   → Presents TGT to KDC
   → Receives Service Ticket

3. User presents Service Ticket to service
   → Service validates ticket
   → Access granted (no password sent!)

┌────────┐         ┌──────────┐         ┌──────────┐
│  User  │──TGT──▶│   KDC    │         │ Service  │
│        │◀───────│(AS + TGS)│         │ (SSH/HTTP)│
│        │──Svc──▶│          │         │          │
│        │ Ticket │          │         │          │
│        │────────┼──────────┼────────▶│          │
└────────┘        └──────────┘         └──────────┘

Kerberos on Linux

# Obtain a TGT
kinit alice@EXAMPLE.COM

# List tickets
klist

# Destroy tickets
kdestroy

# Kerberos config
cat /etc/krb5.conf
# /etc/krb5.conf
[libdefaults]
    default_realm = EXAMPLE.COM
    dns_lookup_kdc = true

[realms]
    EXAMPLE.COM = {
        kdc = kdc.example.com
        admin_server = kdc.example.com
    }

[domain_realm]
    .example.com = EXAMPLE.COM
    example.com = EXAMPLE.COM

FreeIPA

FreeIPA bundles LDAP (389 Directory Server), Kerberos, DNS, and a web UI into a single identity management platform. It is the open-source answer to Active Directory.

Joining a Client to FreeIPA

# Install client packages
yum install ipa-client   # RHEL/CentOS
apt install freeipa-client  # Debian/Ubuntu

# Join the domain (interactive)
ipa-client-install --domain=example.com --realm=EXAMPLE.COM \
    --server=ipa.example.com --mkhomedir

# This configures:
# - SSSD for identity/auth
# - Kerberos (/etc/krb5.conf)
# - PAM and NSS
# - SSH key retrieval from IPA
# - Certificate trust

Common IPA Commands

# Find a user
ipa user-find alice

# Show user details
ipa user-show alice --all

# Add user to group
ipa group-add-member devops --users=alice

# List groups
ipa group-find

# Check host enrollment
ipa host-find $(hostname)

# Manage sudo rules
ipa sudorule-find
ipa sudorule-show admin_rule --all

AD Integration Without FreeIPA

For joining Linux directly to Active Directory:

# Using realmd (recommended)
realm discover ad.example.com
realm join ad.example.com -U admin

# Verify
realm list

# SSSD is auto-configured. Check status:
systemctl status sssd
id aduser@ad.example.com

Login Format After AD Join

# Default format
ssh aduser@ad.example.com@linuxhost

# Configure short names in sssd.conf
[domain/ad.example.com]
use_fully_qualified_names = false
fallback_homedir = /home/%u

Quick Reference: File Locations

/etc/sssd/sssd.conf           SSSD configuration (0600!)
/etc/pam.d/                   PAM configs per service
/etc/nsswitch.conf            Name service switch order
/etc/krb5.conf                Kerberos configuration
/etc/ldap.conf                LDAP client defaults
/var/log/sssd/                SSSD domain and service logs
/var/lib/sss/db/              SSSD cache databases
/etc/openldap/ldap.conf       OpenLDAP client config

Understanding the full chain — PAM, NSS, SSSD, LDAP/Kerberos — is what separates "login does not work" panic from "the SSSD cache is stale, let me clear it." Know the chain, debug the chain.


Wiki Navigation

Prerequisites