Set up centralized user authentication using OpenLDAP server with SSSD client integration. Configure PAM and NSS for seamless login across multiple Linux systems with directory-based user management.
Prerequisites
- Root or sudo access
- Basic understanding of Linux user management
- Network connectivity between LDAP server and clients
What this solves
LDAP authentication centralizes user management across multiple Linux systems, eliminating the need to maintain local user accounts on each server. When you have multiple servers and users need access to different systems, managing accounts individually becomes unwieldy. This tutorial configures OpenLDAP as the directory server and SSSD as the client to handle authentication, authorization, and user information lookups.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of all components.
sudo apt update && sudo apt upgrade -y
Install OpenLDAP server
Install the OpenLDAP server packages and utilities. This sets up the directory server that will store user accounts and authentication information.
sudo apt install -y slapd ldap-utils
Configure OpenLDAP domain and admin password
Run the initial configuration to set your domain and administrator password. Replace example.com with your actual domain.
sudo dpkg-reconfigure slapd
Create base LDAP structure
Create the organizational units for users and groups. This establishes the directory structure where user accounts will be stored.
dn: ou=users,dc=example,dc=com
objectClass: organizationalUnit
ou: users
dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups
ldapadd -x -D cn=admin,dc=example,dc=com -W -f /tmp/base.ldif
Create test user account
Add a test user to verify the LDAP directory is working. This user will authenticate through LDAP on client systems.
dn: uid=testuser,ou=users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser
cn: Test User
sn: User
givenName: Test
mail: testuser@example.com
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/testuser
loginShell: /bin/bash
userPassword: {SSHA}generatedpasswordhash
slappasswd -h {SSHA}
Copy the generated hash and replace {SSHA}generatedpasswordhash in the LDIF file
ldapadd -x -D cn=admin,dc=example,dc=com -W -f /tmp/testuser.ldif
Install SSSD on client systems
Install SSSD and related packages on systems that need to authenticate against LDAP. SSSD handles the communication with the LDAP server and caches credentials.
sudo apt install -y sssd sssd-ldap ldap-utils
Configure SSSD for LDAP authentication
Create the SSSD configuration file to connect to your LDAP server. This tells SSSD where to find user accounts and how to authenticate them.
[sssd]
config_file_version = 2
domains = example.com
services = nss, pam
[domain/example.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://192.168.1.10
ldap_search_base = dc=example,dc=com
ldap_user_search_base = ou=users,dc=example,dc=com
ldap_group_search_base = ou=groups,dc=example,dc=com
ldap_default_bind_dn = cn=admin,dc=example,dc=com
ldap_default_authtok = your_admin_password
cache_credentials = true
enumerate = false
sudo chmod 600 /etc/sssd/sssd.conf
sudo systemctl enable --now sssd
Configure PAM for LDAP authentication
Update PAM configuration to use SSSD for authentication. This enables LDAP users to log in using their directory credentials.
sudo pam-auth-update --enable mkhomedir
Configure NSS to use SSSD
Update the Name Service Switch configuration to query SSSD for user and group information. This allows the system to resolve LDAP users and groups.
# Edit these lines in /etc/nsswitch.conf
passwd: files systemd sss
group: files systemd sss
shadow: files sss
sudo systemctl restart sssd
Configure automatic home directory creation
Enable automatic creation of home directories when LDAP users log in for the first time. This ensures users have a proper home directory structure.
# Add this line to /etc/pam.d/common-session
session required pam_mkhomedir.so skel=/etc/skel umask=0022
Configure TLS encryption
Generate SSL certificates for LDAP
Create SSL certificates to encrypt LDAP communication. This protects user credentials in transit between clients and the LDAP server.
sudo mkdir -p /etc/ssl/ldap
sudo openssl req -new -x509 -nodes -out /etc/ssl/ldap/ldap-server.pem -keyout /etc/ssl/ldap/ldap-server.key -days 365 -subj "/C=US/ST=State/L=City/O=Organization/CN=ldap.example.com"
sudo chown openldap:openldap /etc/ssl/ldap/*
sudo chmod 600 /etc/ssl/ldap/ldap-server.key
Configure OpenLDAP for TLS
Enable TLS in the OpenLDAP configuration using the certificates you just created.
dn: cn=config
changetype: modify
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/ldap/ldap-server.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/ldap/ldap-server.key
-
add: olcTLSCipherSuite
olcTLSCipherSuite: HIGH:!aNULL:!MD5
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/tls.ldif
sudo systemctl restart slapd
Update SSSD for TLS connection
Modify the SSSD configuration to use encrypted LDAP connections.
[domain/example.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldaps://192.168.1.10:636
ldap_search_base = dc=example,dc=com
ldap_user_search_base = ou=users,dc=example,dc=com
ldap_group_search_base = ou=groups,dc=example,dc=com
ldap_default_bind_dn = cn=admin,dc=example,dc=com
ldap_default_authtok = your_admin_password
ldap_tls_reqcert = allow
cache_credentials = true
enumerate = false
sudo systemctl restart sssd
Verify your setup
Test that LDAP authentication is working correctly on both server and client systems.
# Test LDAP server connectivity
ldapsearch -x -H ldap://192.168.1.10 -D cn=admin,dc=example,dc=com -W -b dc=example,dc=com
Test SSSD user resolution
getent passwd testuser
id testuser
Check SSSD status
sudo systemctl status sssd
sudo sss_cache -E
Test authentication (if configured for SSH)
ssh testuser@localhost
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| getent passwd shows no LDAP users | SSSD not connecting to LDAP | Check /var/log/sssd/sssd_example.com.log and verify LDAP URI and credentials |
| Authentication failed for LDAP user | Wrong bind DN or password | Test with ldapwhoami -x -D uid=testuser,ou=users,dc=example,dc=com -W |
| Home directory not created on login | pam_mkhomedir not configured | Add mkhomedir to PAM configuration and restart SSSD |
| LDAP server not starting | Database permission issues | sudo chown -R openldap:openldap /var/lib/ldap |
| TLS connection failing | Certificate issues | Check certificate paths and permissions, use ldap_tls_reqcert = allow for testing |
| Users can't sudo | No sudo privileges configured | Add LDAP users to sudo group or configure LDAP-based sudo rules |
Next steps
- Configure SSH certificate authentication with CA signing for enhanced SSH security with LDAP users
- Configure NGINX LDAP authentication and authorization for web application SSO
- Setup LDAP replication for high availability to prevent single points of failure
- Integrate LDAP with Kubernetes RBAC for container orchestration authentication
- Configure LDAP sudo rules for privilege escalation to manage admin access centrally
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Default values
DOMAIN="${1:-example.com}"
LDAP_SERVER_IP="${2:-127.0.0.1}"
ADMIN_PASSWORD="${3:-}"
MODE="${4:-server}" # server or client
usage() {
echo "Usage: $0 [domain] [ldap_server_ip] [admin_password] [server|client]"
echo " domain: LDAP domain (default: example.com)"
echo " ldap_server_ip: LDAP server IP (default: 127.0.0.1)"
echo " admin_password: LDAP admin password (required for server mode)"
echo " mode: 'server' to install LDAP server, 'client' for SSSD client (default: server)"
exit 1
}
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
cleanup() {
log_error "Script failed. Cleaning up..."
if [ "$MODE" = "server" ]; then
systemctl stop slapd 2>/dev/null || true
systemctl disable slapd 2>/dev/null || true
else
systemctl stop sssd 2>/dev/null || true
systemctl disable sssd 2>/dev/null || true
fi
}
trap cleanup ERR
# Check if running as root or with sudo
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
# Validate arguments
if [ "$MODE" = "server" ] && [ -z "$ADMIN_PASSWORD" ]; then
log_error "Admin password required for server mode"
usage
fi
if [ "$MODE" != "server" ] && [ "$MODE" != "client" ]; then
log_error "Mode must be 'server' or 'client'"
usage
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
;;
fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
log_info "Detected distribution: $ID"
log_info "Mode: $MODE"
log_info "Domain: $DOMAIN"
# Parse domain components
IFS='.' read -ra DOMAIN_PARTS <<< "$DOMAIN"
LDAP_BASE_DN=""
for part in "${DOMAIN_PARTS[@]}"; do
if [ -n "$LDAP_BASE_DN" ]; then
LDAP_BASE_DN="$LDAP_BASE_DN,dc=$part"
else
LDAP_BASE_DN="dc=$part"
fi
done
if [ "$MODE" = "server" ]; then
echo "[1/8] Updating system packages..."
$PKG_UPDATE
echo "[2/8] Installing OpenLDAP server..."
if [ "$PKG_MGR" = "apt" ]; then
export DEBIAN_FRONTEND=noninteractive
echo "slapd slapd/root_password password $ADMIN_PASSWORD" | debconf-set-selections
echo "slapd slapd/root_password_again password $ADMIN_PASSWORD" | debconf-set-selections
echo "slapd slapd/internal/adminpw password $ADMIN_PASSWORD" | debconf-set-selections
echo "slapd slapd/internal/generated_adminpw password $ADMIN_PASSWORD" | debconf-set-selections
echo "slapd slapd/password2 password $ADMIN_PASSWORD" | debconf-set-selections
echo "slapd slapd/password1 password $ADMIN_PASSWORD" | debconf-set-selections
echo "slapd slapd/domain string $DOMAIN" | debconf-set-selections
echo "slapd shared/organization string $DOMAIN" | debconf-set-selections
echo "slapd slapd/backend string MDB" | debconf-set-selections
echo "slapd slapd/purge_database boolean true" | debconf-set-selections
echo "slapd slapd/move_old_database boolean true" | debconf-set-selections
echo "slapd slapd/allow_ldap_v2 boolean false" | debconf-set-selections
echo "slapd slapd/no_configuration boolean false" | debconf-set-selections
$PKG_INSTALL slapd ldap-utils
else
$PKG_INSTALL openldap-servers openldap-clients
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
chown ldap:ldap /var/lib/ldap/DB_CONFIG
chmod 640 /var/lib/ldap/DB_CONFIG
fi
echo "[3/8] Configuring OpenLDAP..."
systemctl enable slapd
systemctl start slapd
if [ "$PKG_MGR" != "apt" ]; then
# Configure RHEL-based systems
HASH_PASS=$(slappasswd -s "$ADMIN_PASSWORD")
cat > /tmp/chrootpw.ldif << EOF
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: $HASH_PASS
EOF
ldapadd -Y EXTERNAL -H ldapi:/// -f /tmp/chrootpw.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
cat > /tmp/chdomain.ldif << EOF
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=admin,$LDAP_BASE_DN" read by * none
dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: $LDAP_BASE_DN
dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=admin,$LDAP_BASE_DN
dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcRootPW
olcRootPW: $HASH_PASS
dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,$LDAP_BASE_DN" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by anonymous auth
olcAccess: {2}to * by dn="cn=admin,$LDAP_BASE_DN" write by * read
EOF
ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/chdomain.ldif
fi
echo "[4/8] Creating base LDAP structure..."
cat > /tmp/base.ldif << EOF
dn: $LDAP_BASE_DN
objectClass: top
objectClass: dcObject
objectClass: organization
o: $DOMAIN
dc: ${DOMAIN_PARTS[0]}
dn: cn=admin,$LDAP_BASE_DN
objectClass: organizationalRole
cn: admin
dn: ou=users,$LDAP_BASE_DN
objectClass: organizationalUnit
ou: users
dn: ou=groups,$LDAP_BASE_DN
objectClass: organizationalUnit
ou: groups
EOF
if [ "$PKG_MGR" = "apt" ]; then
ldapadd -x -D cn=admin,$LDAP_BASE_DN -w "$ADMIN_PASSWORD" -f /tmp/base.ldif 2>/dev/null || true
else
ldapadd -x -D cn=admin,$LDAP_BASE_DN -w "$ADMIN_PASSWORD" -f /tmp/base.ldif
fi
echo "[5/8] Creating test user..."
USER_HASH=$(slappasswd -s testpass123)
cat > /tmp/testuser.ldif << EOF
dn: uid=testuser,ou=users,$LDAP_BASE_DN
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser
cn: Test User
sn: User
givenName: Test
mail: testuser@$DOMAIN
uidNumber: 10001
gidNumber: 10001
homeDirectory: /home/testuser
loginShell: /bin/bash
userPassword: $USER_HASH
EOF
ldapadd -x -D cn=admin,$LDAP_BASE_DN -w "$ADMIN_PASSWORD" -f /tmp/testuser.ldif
echo "[6/8] Configuring firewall..."
if command -v ufw >/dev/null 2>&1; then
ufw allow 389/tcp
elif command -v firewall-cmd >/dev/null 2>&1; then
firewall-cmd --permanent --add-port=389/tcp
firewall-cmd --reload
fi
echo "[7/8] Cleaning up temporary files..."
rm -f /tmp/*.ldif
echo "[8/8] Verifying LDAP server..."
if ldapsearch -x -H ldap://localhost -b "$LDAP_BASE_DN" >/dev/null 2>&1; then
log_info "LDAP server installation completed successfully"
else
log_error "LDAP server verification failed"
exit 1
fi
else
echo "[1/5] Updating system packages..."
$PKG_UPDATE
echo "[2/5] Installing SSSD..."
if [ "$PKG_MGR" = "apt" ]; then
$PKG_INSTALL sssd sssd-ldap ldap-utils libpam-sss libnss-sss
else
$PKG_INSTALL sssd sssd-ldap openldap-clients
fi
echo "[3/5] Configuring SSSD..."
cat > /etc/sssd/sssd.conf << EOF
[sssd]
config_file_version = 2
domains = $DOMAIN
services = nss, pam
[domain/$DOMAIN]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://$LDAP_SERVER_IP
ldap_search_base = $LDAP_BASE_DN
ldap_user_search_base = ou=users,$LDAP_BASE_DN
ldap_group_search_base = ou=groups,$LDAP_BASE_DN
cache_credentials = true
enumerate = false
ldap_tls_reqcert = never
EOF
chmod 600 /etc/sssd/sssd.conf
chown root:root /etc/sssd/sssd.conf
echo "[4/5] Configuring PAM and NSS..."
if [ "$PKG_MGR" = "apt" ]; then
pam-auth-update --package --enable mkhomedir
else
if command -v authselect >/dev/null 2>&1; then
authselect select sssd --force
authselect enable-feature with-mkhomedir
else
# Fallback for older systems
authconfig --enablesssd --enablesssdauth --enablemkhomedir --update
fi
fi
systemctl enable sssd
systemctl start sssd
echo "[5/5] Verifying SSSD configuration..."
sleep 5
if systemctl is-active --quiet sssd; then
log_info "SSSD client installation completed successfully"
log_info "Test with: getent passwd testuser@$DOMAIN"
else
log_error "SSSD service failed to start"
exit 1
fi
fi
log_info "Installation completed successfully!"
Review the script before running. Execute with: bash install.sh