This blog uses apt commands in its examples (for Debian-based distros like Ubuntu, Kali, Mint, etc.), however, examples have also been tested with yum/dnf commands (for RPM-based distros like CentOS, Red Hat, Fedora, openSUSE, etc.).
A Very Brief Summary of Linux With Active Directory
When joining a Linux host to Active Directory (AD), two components are required. The first component handles the central identity and authentication source. In this case, that’s Active Directory. The second component handles available domain discovery and acts as a middleman between the first component and the discovered identity source.
Over the years there have been a few different ways to achieve this, however, most were cumbersome to configure. With realmd that’s no longer the case, which is how we’ll be discovering and joining Active Directory. It’s not too much of a lift either, as realmd handles configuration of complex Linux services (for example, SSSD or Winbind).
Joining Active Directory Using realmd
First, make sure your Linux host can communicate with the domain controller(s) over the network. Proper DNS and hostname resolution are important to this process.
Now, let’s install realmd and check to see if we’re already a member of a domain. If realmd wasn’t previously installed, then we shouldn’t have any domain membership.
sudo apt install realmd
The output should be empty, indicating the host isn’t joined to AD or another domain service. If the output lists a domain you’d like to leave, run the following as the domain admin user originally used to join the domain:
sudo realm leave example.com -U email@example.com
Next, we’ll want to discover our domain:
realm discover <domain_controller_hostname_or_ip>
The output should look like the following and provides a list of packages that must be installed in order to join the domain:
When specifying a domain admin, we can just use the username instead of example.com\user format, since we’re already specifying a domain controller in the command.
In one of my labs, I ran into an invalid hostname error while joining a domain, which can occur if a hostname isn’t set with a proper format (on a VM for example, with a hostname of “localhost.localdomain”). To resolve this, simply set the hostname with hostnamectl:
sudo hostnamectl set-hostname '<new_hostname>'
After joining the domain, we can once again run realm list to view our work, confirm success, and review domain info:
In my case, the login-formats property (highlighted above) indicates domain users will be specified in firstname.lastname@example.org format on this host, rather than domain\user format.
Finally, restart the SSSD service and use id to verify Active Directory user information. The id output should show a domain user’s UID, groups, and more:
sudo service sssd restart
That’s all there is to it! This is by no means a comprehensive guide for all the options you can manually configure along the way, however, this is the quickest route to get Linux hosts joined to Active Directory using a modern approach.
Mapping Linux UIDs/GIDs to SIDs in Active Directory
One more thing we should touch on is how POSIX UIDs and GIDs are mapped to SIDs in Active Directory since Linux doesn’t have a concept of SIDs like Windows does.
realmd uses SSSD by default, rather than Winbind. One big benefit of this approach is that SSSD automatically handles POSIX UID/GID generation using the SID of each Active Directory user/group. If you keep the default SSSD settings on each Linux host you join to the domain, then these UID/GID values should be mapped consistently across Linux hosts.
For example, in my lab this result is consistent no matter which Linux host I run it on that’s joined to the same domain:
user@my-linux-host:~$ id email@example.com
uid=778006423(firstname.lastname@example.org) gid=778001234(domain email@example.com) groups=778001234 (domain firstname.lastname@example.org)
It’s possible to take a deeper dive into UID/GID generation and mapping, however, that’s out of the scope of this blog. However, with our setup, we’ll have consistent AD user and group UIDs/GIDs throughout the domain.
Another benefit of this approach is that UIDs and GIDs generated by SSSD can also be applied to the uidNumber and gidNumber attributes in Active Directory for users and groups. This allows applications that may query these attributes to perform UID/GID to SID mapping, ultimately resulting in the same AD users or groups being referenced regardless if a user/group is in use on a Linux or Windows host.
To view uidNumber and gidNumber attributes in Active Directory Users and Computers, make sure you have Advanced Features enabled under the View dropdown.
You’ll then be able to view and edit those fields in a user or group’s Properties menu, on the Attribute Editor tab.
Depending on the number of users and groups in your domain, it may take a long time to manually assign uidNumber and gidNumber values. Although methods to programmatically populate these fields will be environment-specific, we can at least list all AD users and groups, with UIDs and GIDs, using the getent command from a Linux host joined to the domain.
By default, getent will only list local users and groups. However, this can be modified by adding a line to your /etc/sssd/sssd.conf file and restarting SSSD.
It should be noted that enabling this enumeration is an expensive option and can cause undue stress on the Active Directory server. Typically, I like to step through this process outside of production hours, save the results, and then disable the full user/group enumeration. First, we can add enumerate = True to sssd.conf, and then restart the SSSD service:
echo "enumerate = True" | sudo tee -a /etc/sssd/sssd.conf &> /dev/null
sudo service sssd restart
Depending on the size of your Active Directory, it can take up to ten minutes to complete the initial enumeration into the local cache. During this period, you’ll notice domain users and groups populating in the respective outputs from getent passwd and getent group. Once enumeration to the local cache is complete, we can use the following commands to format getent output. The first outputs each domain user, their UID, and their GID in comma-separated format, while the second outputs each domain group with its GID in comma-separated format.
A couple notes on these commands and output. First, <domain> needs to be replaced with your domain name. Second, you can redirect outputs to text or CSV files, for parsing into Active Directory’s uidNumber and gidNumber attributes. Once you’ve saved the output from the getent commands, you can remove the enumerate value from sssd.conf and restart the SSSD service to prevent the expensive LDAP enumeration from continuously occurring:
sudo sed -i '/enumerate = True/d' /etc/sssd/sssd.conf
sudo service sssd restart
With this UID and GID information in CSV format, you could create a script that imports each CSV and automatically updates uidNumber and gidNumber for Active Directory users and groups. For example, the following Windows PowerShell command adds the specified UID and GID to those attributes in AD:
With this command (and Set-ADGroup, respectively), it wouldn’t be too difficult to generate a script that fits your environment and speeds up the process of mapping UIDs/GIDs to uidNumber and gidNumber in AD, which ultimately map to Windows SIDs.
Stealthbits, Active Directory, & Linux
Linux hosts are often used for some of the most critical functions in an organization’s infrastructure. As a byproduct, it’s important for admins to monitor these hosts, understand how they’re used, observe who accesses them, and verify how they’re secured. This is even more critical when Linux hosts are joined to Active Directory.
Dan Piazza is a Technical Product Manager at Stealthbits, now part of Netwrix, responsible for PAM, file systems auditing and sensitive data auditing solutions. He has worked in technical roles since 2013, with a passion for cybersecurity, data protection, automation, and code. Prior to his current role he worked as a Product Manager and Systems Engineer for a data storage software company, managing and implementing both software and hardware B2B solutions.
Hey Dan, Roger here from Microsoft. Great blog post, thanks you saved me hours. At the beginning you say “First, make sure your Linux host can communicate with the domain controller(s) over the network. Proper DNS and hostname resolution are important to this process.”. I did this just using etc/hosts as well as referencing IP address of domain controller and your stuff worked. My linux host is showing up in AD, but not in AD integrated DNS. I was hoping that domain joining the VM would also make the necessary changes to AD Integrated DNS, but I guess I was hoping for too much. Anway thanks again!
For Linux clients joined to Active Directory via SSSD, there’s additional configuration options that can be added to the client’s sssd.conf file to cause dynamic DNS updates (followed by a restart of SSSD after making edits to that file).