Joining AlmaLinux 9 to an Active Directory domain with SSSD

Complete guide to joining an AlmaLinux 9 server to an Active Directory domain — LDAP/Kerberos authentication, AD-based sudo, automatic home directories.

Joining AlmaLinux 9 to an Active Directory domain with SSSD Joining AlmaLinux 9 to an Active Directory domain with SSSD
Table of Contents

Joining a Linux server to an Active Directory domain lets domain users log in with their AD credentials and benefit from centralized policies. Here is how to do it cleanly on AlmaLinux 9 with SSSD and realmd.

Prerequisites

  • An up-to-date AlmaLinux 9
  • Network access to the domain controller (ports 88, 389, 636, 3268, 3269)
  • An AD account allowed to join machines to the domain
  • DNS set up to resolve the AD domain

Checking the network

# Check DNS resolution of the AD domain
dig +short domain.local _ldap._tcp.domain.local SRV
# → must return the DC's IP and LDAP port

# Ping the DC
ping dc1.domain.local

# Check the required ports
for port in 88 389 636; do
  nc -zv dc1.domain.local $port && echo "Port $port OK" || echo "Port $port CLOSED"
done
DNS is critical

DNS must resolve the AD domain and its SRV records. Set the DCs as DNS servers in /etc/resolv.conf before you start.

Configuring DNS

# /etc/resolv.conf
search domain.local
nameserver 192.168.x.10   # DC1
nameserver 192.168.x.11   # DC2

# Check
nslookup domain.local
nslookup dc1.domain.local

Installing the packages

dnf install -y \
  realmd \
  sssd \
  sssd-ad \
  sssd-tools \
  oddjob \
  oddjob-mkhomedir \
  adcli \
  samba-common-tools \
  krb5-workstation \
  openldap-clients

Joining the domain

# Discover the domain (without joining)
realm discover domain.local

# Join the domain
realm join -U administrator domain.local
# Enter the AD account password when prompted

# Check the join
realm list

Expected output:

root@alma9:~# realm list
domain.local
  type: kerberos
  realm-name: DOMAIN.LOCAL
  domain-name: domain.local
  configured: kerberos-member
  server-software: active-directory
  client-software: sssd
  required-package: oddjob
  required-package: oddjob-mkhomedir
  required-package: sssd
  required-package: adcli
  required-package: samba-common-tools
  login-formats: %U@domain.local
  login-policy: allow-realm-logins
The server is a Kerberos member of the domain, with SSSD as client

SSSD configuration

/etc/sssd/sssd.conf is generated automatically by realm join, but a few adjustments are recommended:

# /etc/sssd/sssd.conf
[sssd]
domains = domain.local
config_file_version = 2
services = nss, pam

[domain/domain.local]
default_shell = /bin/bash
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = DOMAIN.LOCAL
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u@%d
ad_domain = domain.local
use_fully_qualified_names = False    # ← log in without @domain.local
ldap_id_mapping = True
access_provider = ad

# Performance
ad_gpo_access_control = disabled    # Disable Linux GPO enforcement (optional)
ldap_referrals = false

# Cache
cache_credentials = true
offline_credentials_expiration = 7

# Timeouts
ldap_network_timeout = 3
ldap_opt_timeout = 3
use_fully_qualified_names = False

Without this option, users must log in as user@domain.local. With False, ‘user’ is enough — much more convenient.

# Apply the permissions (mandatory)
chmod 600 /etc/sssd/sssd.conf

# Restart SSSD
systemctl restart sssd
systemctl enable sssd

Automatic home directory creation

# Create the home directory automatically on first login
authselect select sssd with-mkhomedir --force

# Enable the oddjobd service
systemctl enable --now oddjobd

Testing authentication

# Check that an AD user is visible
id user@domain.local
# With use_fully_qualified_names = False:
id user

# Test Kerberos authentication
kinit administrator@DOMAIN.LOCAL
klist   # Shows the Kerberos ticket

# Test an SSH login with an AD account
ssh user@localhost

Allowing only some AD groups

By default, every AD user can log in. Restrict access:

# Allow only the "Linux-Admins" AD group
realm permit -g 'Linux-Admins@domain.local'

# Deny everyone except the allowed groups
realm deny --all
realm permit -g 'Linux-Admins@domain.local'
realm permit -g 'Linux-Users@domain.local'

# Check
realm list

Sudo through Active Directory groups

Create a sudoers file for your AD groups:

# /etc/sudoers.d/ad-admins
# Full sudo for the "Linux-Admins" AD group
%Linux-Admins@domain.local ALL=(ALL) ALL

# Passwordless sudo for infrastructure admins
%Linux-Infra-Admins@domain.local ALL=(ALL) NOPASSWD: ALL
# Check the syntax
visudo -c -f /etc/sudoers.d/ad-admins

# Test
su - admin-user@domain.local
sudo whoami   # → root
admin-user@alma9:~$ sudo whoami
root
An AD user from Linux-Admins gets root through sudo

Common problems

SSSD won’t start

journalctl -u sssd -n 50 --no-pager

# Frequent culprit: sssd.conf permissions
chmod 600 /etc/sssd/sssd.conf
chown root:root /etc/sssd/sssd.conf

# Clear the SSSD cache (for "ghost" users)
sss_cache -E
systemctl restart sssd

AD user not found

# Test the LDAP connection directly
ldapsearch -H ldap://dc1.domain.local \
  -D "CN=svc-linux,OU=Services,DC=domain,DC=local" \
  -w PASS \
  -b "DC=domain,DC=local" \
  "(sAMAccountName=user)"

# Force a refresh
sss_cache -u user
id user

Expired or invalid Kerberos ticket

# Check the ticket
klist

# Renew it manually
kinit user@DOMAIN.LOCAL

# Sync the clock (Kerberos is sensitive to drift)
timedatectl status
chronyc tracking

# If the drift is > 5 min → Kerberos fails
chronyc makestep

Leaving the domain

realm leave domain.local
# The computer account is removed from AD

Final check

# Full test
getent passwd user              # The user is visible
getent group 'Linux-Admins'     # The AD group is visible
su - user                       # Login → home created automatically
sudo -l                         # Correct sudo rights
Result

AD users can now SSH into the Linux server with their domain credentials. Their home directory is created automatically on first login.

Special case — authentication without joining (simple LDAP bind)

If you can’t join the machine to the domain (restricted environments), an alternative is a simple LDAP bind with nslcd:

dnf install -y nss-pam-ldapd nslcd

# /etc/nslcd.conf
uri ldap://dc1.domain.local
base dc=domain,dc=local
binddn CN=svc-linux,OU=Services,DC=domain,DC=local
bindpw YOUR_PASSWORD
ssl start_tls
tls_reqcert never
scope sub
filter passwd (&(objectClass=user)(memberOf=CN=Linux-Users,OU=Groups,DC=domain,DC=local))
map passwd uid sAMAccountName
map passwd homeDirectory unixHomeDirectory
map passwd gecos displayName

This method is less integrated (no Kerberos, no SSO) but works in constrained environments.

Comments