Active Directory Domain Join

Overview

This procedure joins a Linux workstation to the inside.domusdigitalis.dev Active Directory domain using manual configuration of Kerberos, Samba, and SSSD.

This is the enterprise-grade method.

We do NOT use realmd or adcli from AUR. Manual configuration provides:

  • Full security control and transparency

  • No untrusted AUR dependencies

  • Auditable configuration at every step

  • Enterprise standard for production deployments

Domain join is REQUIRED for enterprise deployments.

AD membership provides:

  • Centralized user authentication with Kerberos

  • AD group-based ISE authorization policies

  • Automatic certificate enrollment (future with GPO)

  • Single sign-on capabilities

  • Centralized audit trail

See Deployment Models for comparison.

Prerequisites

  • Network connectivity to domain controller (home-dc01.inside.domusdigitalis.dev / 10.50.1.50)

  • DNS resolution working for the domain

  • Domain Admin privileges (your evanusmodestus@inside.domusdigitalis.dev account)

  • Time synchronized with domain (NTP - Kerberos requirement)

  • Required packages already installed

Required Ports

Port 464 (kpasswd) is REQUIRED for domain join. This is often missed in firewall/dACL configurations.

Field-tested at CHLA (2026-02-06): Domain join failed with "KDC reply did not match expectations" until port 464 was added to the dACL.

Port Protocol Purpose

88

TCP/UDP

Kerberos authentication

389

TCP

LDAP (directory queries)

464

TCP

kpasswd (password operations, REQUIRED for join)

636

TCP

LDAPS (secure LDAP)

Architecture

After domain join:

  • Kerberos - Authentication protocol (MIT krb5)

  • Samba - SMB/CIFS and domain join functionality

  • SSSD - System Security Services Daemon (queries AD for users/groups)

  • NSS - Name Service Switch (integrates SSSD with system)

  • PAM - Pluggable Authentication Modules (AD user login)

Step 1: Install Required Packages

Arch Linux (used for modestus-razer)
# Install from official repos only - NO AUR packages
sudo pacman -S sssd krb5 samba
realmd and adcli are AUR packages - we don’t use them for security reasons.
RHEL/Fedora/CentOS
sudo dnf install -y sssd krb5-workstation samba-common-tools
Ubuntu/Debian
sudo apt install -y sssd krb5-user samba-common-bin

Step 2: Configure Kerberos

Create /etc/krb5.conf with secure settings:

sudo tee /etc/krb5.conf > /dev/null << 'EOF'
[libdefaults]
    default_realm = INSIDE.DOMUSDIGITALIS.DEV
    dns_lookup_realm = false
    dns_lookup_kdc = true
    ticket_lifetime = 24h
    renew_lifetime = 7d
    forwardable = true
    # AES encryption required - RC4 rejected by modern DCs
    default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
    default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
    permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96

[realms]
    INSIDE.DOMUSDIGITALIS.DEV = {
        kdc = dc-01.inside.domusdigitalis.dev
        admin_server = dc-01.inside.domusdigitalis.dev
    }

[domain_realm]
    .inside.domusdigitalis.dev = INSIDE.DOMUSDIGITALIS.DEV
    inside.domusdigitalis.dev = INSIDE.DOMUSDIGITALIS.DEV
EOF

Key Settings:

  • dns_lookup_realm = false - Explicitly defined realms (more secure)

  • dns_lookup_kdc = true - Discover KDCs via DNS SRV records

  • ticket_lifetime = 24h - Balance between security and convenience

  • forwardable = true - Required for SSSD

  • default_tgs_enctypes / default_tkt_enctypes / permitted_enctypes - AES encryption required

AES encryption types are critical. Modern domain controllers reject RC4 (type 23). Without explicit AES configuration, SSSD will fail with "KDC has no support for encryption type."

Field-tested at CHLA (2026-02-06): Keytab regeneration with AES fixed SSSD authentication failures.

Test Kerberos Authentication

# Authenticate with YOUR Domain Admin account
kinit evanusmodestus@INSIDE.DOMUSDIGITALIS.DEV

# Enter password when prompted

# Verify ticket
klist
Expected output:
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: evanusmodestus@INSIDE.DOMUSDIGITALIS.DEV

Valid starting       Expires              Service principal
01/27/2026 21:35:24  01/28/2026 07:35:24  krbtgt/INSIDE.DOMUSDIGITALIS.DEV@INSIDE.DOMUSDIGITALIS.DEV
    renew until 02/03/2026 21:35:16

If kinit fails:

  • Check DNS resolution: dig _kerberos._tcp.inside.domusdigitalis.dev SRV

  • Check DC connectivity: ping dc-01.inside.domusdigitalis.dev

  • Check time sync: timedatectl (must be within 5 minutes of DC)

Step 3: Configure Samba

Create /etc/samba/smb.conf for AD integration:

sudo tee /etc/samba/smb.conf > /dev/null << 'EOF'
[global]
   workgroup = INSIDE
   realm = INSIDE.DOMUSDIGITALIS.DEV
   security = ads
   kerberos method = secrets and keytab

   # Disable unnecessary services
   disable netbios = yes
   dns proxy = no

   # Security hardening
   client signing = mandatory
   client schannel = yes
EOF

Security Settings:

  • security = ads - Active Directory security mode

  • kerberos method = secrets and keytab - Use keytab for authentication

  • client signing = mandatory - Enforce SMB signing

  • client schannel = yes - Secure channel encryption

Step 4: Join the Domain

Use net ads join with YOUR Domain Admin credentials:

# Join using YOUR account (prompts for password - most secure)
sudo net ads join -U evanusmodestus@INSIDE.DOMUSDIGITALIS.DEV

# Enter password when prompted
Expected output:
Using short domain name -- INSIDE
Joined 'MODESTUS-RAZER' to dns domain 'inside.domusdigitalis.dev'
DNS Update for modestus-razer.inside.domusdigitalis.dev failed: ERROR_DNS_GSS_ERROR
DNS update failed: NT_STATUS_UNSUCCESSFUL

DNS errors are non-critical.

The join succeeded when you see Joined 'HOSTNAME' to dns domain. DNS dynamic update failures are common and can be ignored - we use pfSense DNS Resolver, not Windows DNS.

Verify Domain Join

# Test domain membership
sudo net ads testjoin
Expected output:
Join is OK

Verify Computer Account Created

On your workstation:

ssh home-dc01 'powershell -Command "Get-ADComputer -Filter {Name -eq \"modestus-razer\"} | Select-Object Name, DistinguishedName, Enabled"'
Expected output:
Name           DistinguishedName                                                 Enabled
----           -----------------                                                 -------
MODESTUS-RAZER CN=MODESTUS-RAZER,CN=Computers,DC=inside,DC=domusdigitalis,DC=dev    True

Verify Keytab File

The domain join creates /etc/krb5.keytab with computer account credentials:

# Check keytab exists
ls -la /etc/krb5.keytab

# List keytab entries
sudo klist -kt /etc/krb5.keytab
Expected output:
Keytab name: FILE:/etc/krb5.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   2 01/27/2026 21:37:14 MODESTUS-RAZER$@INSIDE.DOMUSDIGITALIS.DEV
   2 01/27/2026 21:37:14 HOST/MODESTUS-RAZER@INSIDE.DOMUSDIGITALIS.DEV
   2 01/27/2026 21:37:14 host/modestus-razer.inside.domusdigitalis.dev@INSIDE.DOMUSDIGITALIS.DEV
   ...

Step 5: Configure SSSD

SSSD queries Active Directory for user and group information.

Configuration file must have NO leading spaces!

SSSD INI parser is strict - all directives must start at column 0.

# Create SSSD configuration
sudo bash -c 'cat > /etc/sssd/sssd.conf << "EOF"
[sssd]
domains = inside.domusdigitalis.dev
config_file_version = 2
services = nss, pam

[domain/inside.domusdigitalis.dev]
ad_domain = inside.domusdigitalis.dev
krb5_realm = INSIDE.DOMUSDIGITALIS.DEV
id_provider = ad
auth_provider = ad
access_provider = ad
cache_credentials = false
krb5_store_password_if_offline = false
use_fully_qualified_names = false
fallback_homedir = /home/%u
default_shell = /bin/bash
EOF'

# Set strict permissions (required by SSSD)
sudo chmod 600 /etc/sssd/sssd.conf

Security Settings:

  • cache_credentials = false - Never cache passwords locally

  • krb5_store_password_if_offline = false - No offline password storage

  • use_fully_qualified_names = false - Allow short names (evanusmodestus vs evanusmodestus@inside.domusdigitalis.dev)

Convenience Settings:

  • fallback_homedir = /home/%u - Create home directory on first login

  • default_shell = /bin/bash - Default shell for AD users

Start SSSD

# Enable and start SSSD
sudo systemctl enable --now sssd

# Check status
sudo systemctl status sssd
Expected output:
● sssd.service - System Security Services Daemon
     Loaded: loaded (/usr/lib/systemd/system/sssd.service; enabled; preset: disabled)
     Active: active (running) since Tue 2026-01-27 21:49:11 PST

Verify SSSD Domain Status

# List configured domains
sudo sssctl domain-list

# Check domain connectivity
sudo sssctl domain-status inside.domusdigitalis.dev
Expected output:
Online status: Online

Active servers:
AD Global Catalog: not connected
AD Domain Controller: home-dc01.inside.domusdigitalis.dev

Discovered AD Domain Controller servers:
- home-dc01.inside.domusdigitalis.dev

Step 6: Configure NSS (Name Service Switch)

NSS tells Linux where to look up users and groups. We need to add SSSD.

# Backup first
sudo cp /etc/nsswitch.conf /etc/nsswitch.conf.bak

# Add sss to passwd, group, and shadow lines
sudo sed -i 's/^passwd: files/passwd: files sss/' /etc/nsswitch.conf
sudo sed -i 's/^group: files/group: files sss/' /etc/nsswitch.conf
sudo sed -i 's/^shadow: files/shadow: files sss/' /etc/nsswitch.conf

# Verify
grep -E '^(passwd|group|shadow):' /etc/nsswitch.conf
Expected output:
passwd: files sss systemd
group: files sss [SUCCESS=merge] systemd
shadow: files sss systemd

Resolution order:

  1. files - Check local /etc/passwd, /etc/group, /etc/shadow

  2. sss - Query SSSD (which queries AD)

  3. systemd - Systemd dynamic users

Restart SSSD After NSS Changes

sudo systemctl restart sssd

Step 7: Verify AD User Resolution

# Test with fully qualified name
id administrator@inside.domusdigitalis.dev

# Test with short name (requires use_fully_qualified_names = false)
id administrator

# Test YOUR account
id evanusmodestus
Expected output:
uid=1291000500(administrator) gid=1291000513(domain users) groups=1291000513(domain users),1291000512(domain admins),...

uid=1291001107(evanusmodestus) gid=1291000513(domain users) groups=1291000513(domain users),1291000512(domain admins),...

You should see AD groups!

If you see domain admins, domain users, etc., domain join is working correctly.

If you only see local groups, check:

  1. SSSD is running: sudo systemctl status sssd

  2. SSSD is online: sudo sssctl domain-status inside.domusdigitalis.dev

  3. NSS is configured: grep sss /etc/nsswitch.conf

Step 8: Configure PAM (For AD User Login)

If you want AD users to log in locally via SSH or console:

# Check if pam_sss.so is already configured
grep pam_sss /etc/pam.d/system-auth

If not present, add it manually or use authselect (RHEL/Fedora) or pam-auth-update (Ubuntu).

Enable Automatic Home Directory Creation

AD users need home directories. Without this, SSH login fails with "cannot change directory to /home/user@DOMAIN: No such file or directory."

Field-tested at CHLA (2026-02-06): First AD user login failed until mkhomedir was enabled.

Ubuntu/Debian
sudo pam-auth-update --enable mkhomedir
RHEL/Fedora (authselect)
sudo authselect enable-feature with-mkhomedir
sudo systemctl restart oddjobd
Manual (all distros)
echo "session required pam_mkhomedir.so skel=/etc/skel umask=0077" | sudo tee -a /etc/pam.d/common-session

Optional: Shorter Home Directory Paths

By default, home directories use FQDN format: /home/user@DOMAIN.COM

For shorter paths (/home/user), add to /etc/sssd/sssd.conf:

[domain/your.domain]
use_fully_qualified_names = False
fallback_homedir = /home/%u

Then restart SSSD: sudo systemctl restart sssd

For this deployment, we only need AD user/group resolution for ISE authorization.

Local login for AD users is optional and not required for 802.1X.

Step 9: Add Computer to AD Groups

Now that modestus-razer is domain-joined, add it to GRP-Linux-Admin-Workstations:

ssh home-dc01 'powershell -Command "Add-ADGroupMember -Identity \"GRP-Linux-Admin-Workstations\" -Members \"modestus-razer$\"; Get-ADGroupMember -Identity \"GRP-Linux-Admin-Workstations\" | Select-Object Name"'

Computer accounts require the $ suffix!

Correct: modestus-razer$ Wrong: modestus-razer

Verification Commands

Domain Join Status
# Test domain membership
sudo net ads testjoin

# Show domain info
sudo net ads info

# List domain controllers
sudo net ads lookup
SSSD Status
# Domain list
sudo sssctl domain-list

# Domain status
sudo sssctl domain-status inside.domusdigitalis.dev

# User cache
sudo sssctl user-show administrator
AD User Lookup
# Test user resolution
id administrator
id evanusmodestus

# Test group membership
groups administrator
Keytab Verification
# List keytab entries
sudo klist -kt /etc/krb5.keytab

# Test keytab authentication
sudo kinit -kt /etc/krb5.keytab 'MODESTUS-RAZER$@INSIDE.DOMUSDIGITALIS.DEV'
sudo klist

Troubleshooting

SSSD Won’t Start

Error: Can’t read config: 'Error while parsing configuration file'

Cause: Leading spaces in /etc/sssd/sssd.conf

Fix:

# Strip leading spaces
sudo sed -i 's/^  //' /etc/sssd/sssd.conf

# Verify NO spaces at start of lines
sudo cat /etc/sssd/sssd.conf | head -5

# Restart SSSD
sudo systemctl restart sssd

SSSD Online But Users Don’t Resolve

Symptom: sudo sssctl domain-status shows "Online" but id administrator returns "no such user"

Cause: NSS not configured to use SSSD

Fix:

# Check NSS configuration
grep sss /etc/nsswitch.conf

# Should show "sss" in passwd, group, shadow lines
# If not, add it:
sudo sed -i 's/^passwd: files/passwd: files sss/' /etc/nsswitch.conf
sudo sed -i 's/^group: files/group: files sss/' /etc/nsswitch.conf
sudo sed -i 's/^shadow: files/shadow: files sss/' /etc/nsswitch.conf

# Restart SSSD
sudo systemctl restart sssd

Kerberos Ticket Expired

Error: kinit fails with "Ticket expired"

Fix:

# Destroy old ticket
kdestroy

# Get new ticket
kinit evanusmodestus@INSIDE.DOMUSDIGITALIS.DEV

Time Sync Issues

Error: Clock skew too great during kinit

Cause: System time differs from DC by more than 5 minutes

Fix:

# Check time
timedatectl

# Sync with NTP
sudo timedatectl set-ntp true

# Or manually sync
sudo ntpdate dc-01.inside.domusdigitalis.dev

DNS Resolution Failures

Error: net ads join fails with "Failed to lookup DC info"

Fix:

# Test DNS resolution
dig inside.domusdigitalis.dev
dig _ldap._tcp.inside.domusdigitalis.dev SRV
dig _kerberos._tcp.inside.domusdigitalis.dev SRV

# Ping DC directly
ping dc-01.inside.domusdigitalis.dev

# Check /etc/resolv.conf
cat /etc/resolv.conf

Complete Verification Checklist

After domain join, verify ALL of these:

  • sudo net ads testjoin returns "Join is OK"

  • Computer account exists in AD: Get-ADComputer modestus-razer

  • Keytab file exists: ls -la /etc/krb5.keytab

  • SSSD is running: sudo systemctl status sssd

  • SSSD is online: sudo sssctl domain-status inside.domusdigitalis.dev

  • NSS configured: grep sss /etc/nsswitch.conf

  • AD users resolve: id administrator

  • AD groups visible: groups administrator shows "domain admins"

  • Computer in AD group: Get-ADGroupMember GRP-Linux-Admin-Workstations

Security Hardening

Restrict AD User Access

To limit which AD users can log in:

# Add to /etc/sssd/sssd.conf under [domain/inside.domusdigitalis.dev]
ad_access_filter = memberOf=CN=Linux-Users,OU=Groups,DC=inside,DC=domusdigitalis,DC=dev
Disable Password Caching

Already configured in our setup:

cache_credentials = false
krb5_store_password_if_offline = false
Configure Sudo for AD Groups
# Create sudoers file for Domain Admins
sudo visudo -f /etc/sudoers.d/domain-admins
Content:
# Domain Admins have full sudo access
%domain\ admins ALL=(ALL) ALL

Production Deployment Notes

For enterprise/research deployments:

  1. Use YOUR Domain Admin account - Don’t create service accounts with static passwords

  2. Document the computer OU - Move computers from default Computers container to proper OU

  3. Test thoroughly - Verify all checks pass before deploying to production

  4. Monitor SSSD logs - Watch /var/log/sssd/*.log for issues

  5. Plan certificate auto-enrollment - Configure GPO for automatic certificate issuance (future)