Automated User Provisioning: Implementing On-Demand Local Account Creation for LDAP-Authenticated SSH Users


2 views

When integrating LDAP authentication with SSH via pam_ldap, administrators face a common workflow bottleneck: while authentication works seamlessly, local account creation remains a manual step. After adding a user to LDAP, you still need to run useradd or adduser on each target server.

The solution lies in PAM's capabilities through the pam_mkhomedir.so module. This module can automatically create home directories upon first login, but with some configuration tweaks, we can extend this to full account creation.

# /etc/pam.d/sshd configuration
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022

For full automation, combine these components:

  1. Configure PAM to create home directories
  2. Use SSSD (System Security Services Daemon) for better LDAP integration
  3. Implement name service switches to handle user resolution

Here's a complete configuration example:

# /etc/sssd/sssd.conf
[sssd]
services = nss, pam
domains = yourdomain.com

[domain/yourdomain.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://server1.yourdomain.com
ldap_search_base = dc=yourdomain,dc=com
ldap_user_home_directory = /home/%u
cache_credentials = True

For production environments, consider these enhancements:

# Ensure proper permissions for auto-created homes
session required pam_umask.so umask=0077

# Log creation events for auditing
session optional pam_exec.so /usr/local/bin/log_home_creation.sh

For more control, the pam_script module allows executing custom scripts during authentication:

# /etc/pam.d/sshd addition
session optional pam_script.so onerr=fail

# Sample script (/etc/pam_script)
#!/bin/bash
if [ "$PAM_TYPE" = "open_session" ]; then
  if ! id -u "$PAM_USER" >/dev/null 2>&1; then
    useradd -m -s /bin/bash "$PAM_USER"
  fi
fi

Always ensure:

  • Home directory permissions are restrictive
  • UID/GID numbering doesn't conflict with system accounts
  • Process is logged for audit purposes

When implementing LDAP authentication for SSH access, we often face a chicken-and-egg problem: users exist in LDAP but don't have local accounts on the target server. While pam_ldap handles authentication, we still need local accounts for proper home directories and system permissions.

The simplest approach uses PAM's pam_mkhomedir.so module. Add this line to your /etc/pam.d/sshd file:

session required pam_mkhomedir.so skel=/etc/skel umask=0022

This automatically creates home directories when users first log in. However, it doesn't handle other system account requirements.

For complete account creation, we can use pam_exec to trigger a script:

auth    required pam_exec.so /usr/local/bin/ldap_user_sync.sh

Here's a sample sync script:

#!/bin/bash
# /usr/local/bin/ldap_user_sync.sh

LDAP_USER="$1"

if ! id "$LDAP_USER" >/dev/null 2>&1; then
    # User doesn't exist locally
    USER_ENTRY=$(ldapsearch -x "uid=$LDAP_USER" | grep -A 5 '^dn:')
    UID_NUMBER=$(echo "$USER_ENTRY" | grep 'uidNumber:' | awk '{print $2}')
    GID_NUMBER=$(echo "$USER_ENTRY" | grep 'gidNumber:' | awk '{print $2}')
    
    useradd -m -u "$UID_NUMBER" -g "$GID_NUMBER" "$LDAP_USER"
    mkdir -p "/home/$LDAP_USER/.ssh"
    chmod 700 "/home/$LDAP_USER/.ssh"
fi
exit 0

System Security Services Daemon (SSSD) provides more elegant LDAP integration:

# /etc/sssd/sssd.conf
[sssd]
services = nss, pam
domains = example.com

[domain/example.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://ldap.example.com
ldap_search_base = dc=example,dc=com
ldap_id_use_start_tls = True
ldap_tls_reqcert = allow
cache_credentials = True
entry_cache_timeout = 600
ldap_network_timeout = 3

When implementing automatic account creation:

  • Set proper umask values (022 or 027)
  • Restrict SSH access to specific LDAP groups
  • Implement rate limiting to prevent brute force attacks
  • Consider using SELinux or AppArmor for additional protection

If things don't work as expected:

tail -f /var/log/auth.log
journalctl -f -u sshd
pam_tally2 --user username
getent passwd username