Many of the long-time readers of this blog are going to probably have a panic attack when they read this article because they are going to be asking themselves the question, “Why in the heck does he want to install Active Directory in his life?” The reason, like so many answers to so many of these questions I ask myself is “Because I can!” LOL!!
So I have a small home network that is my playground for learning new technologies and practicing and growing my security skills. I try to keep it segregated from my true home network that my family uses because I don’t want my latest experiment to get in the way of any of them connecting to the Internet successfully.
Just for fun, however, I’m going to start on a path to try a new experiment – I’d like to have the ability to add a new machine to my network and not have to spend half a day setting it up. Furthermore, I’d like to put everything I can either on a local file server that backs up to the cloud or in the cloud that backs up to a local file server in such a way that I can totally destroy any of my machines and be able to reproduce it at the push of a button. The ultimate in home disaster recovery.
What does this buy me? Well, for one, it lets me be even more aggressive in my experimentation. If I lay waste to a machine because of a failed experiment, no big deal – I just nuke and automatically repave it. For another, it makes it way easier to recover a family member’s setup when something goes wrong. I can just rebuild the machine and know they won’t lose anything. That alone will save me lots of time troubleshooting the latest problems with stuff.
So, why Active Directory? I choose this technology because pretty much everything (OpenBSD is going to be interesting) will authenticate centrally with it and yes, I do have to run some Windows and Mac machines on my network, I can’t do it all on OpenBSD and Linux so it’s a good common ground.
Now, I will die before installing a Windows Server in my infrastructure (LOL) so I have been very careful saying “Active Directory” and not “Windows Server”, or “Azure AD”. I’m going to see how far Samba 4 has come since the last time I played with it. If I can do the full meal deal of authentication, authorization, roaming user profiles and network home directories on a Windows machine, then I can fill in around the edges on my non Windows machines using NFS and other techniques.
Setting up Ubuntu
First things first, I want to start with a clean install of my domain controller. To this end, I’ll nuke and repave my 32-core Threadripper box in my basement with the latest Ubuntu 21.10 build on it and install samba on bare metal. I had originally thought about doing this on a VM or on a Docker container, but I want the reliability and control-ability of a bare metal install with a static IP address, etc. Therefore, after carefully backing up the local files that I wanted to save off of this machine (ha – that’s a lie, I just booted from a USB thumb drive and Gparted the drives with new partition tables), I installed a fresh copy of Ubuntu 21.10 with 3rd party drivers for my graphics card.
Once I had the base OS laid down, I used the canonical documentation from wiki.samba.org (not documentation from Canonical, the owner of Ubuntu <g>), along with some blog posts (1), (2), and (3) to determine my full course of action. I’ll outline the various steps below.
Active Directory Domain Controller
First things first, we need to get the network set up the way Samba wants it on this machine. That consists of setting up a static IP address on the two NICs in my server (one for my “secure” home network and one for my insecure “family” network) and setting the hostname and /etc/hosts file changes. Specifically, I used NetworkManager from the Ubuntu desktop to set the static IPs, the gateway and the netmasks and then modified /etc/hosts as follows:
127.0.0.1 localhost
192.168.1.2 DC1.ad.example.com DC1
It is important to note that Ubuntu will put in an additional 127.0.0.1 line for your host and you need to (apparently, per the documentation) remove that. I then modified my /etc/hostname file as follows:
DC1.ad.example.com
Now for a fun one. We need to permanently change /etc/resolv.conf and not have Ubuntu overwrite it on the next boot. To do that, we have to:
# systemctl stop systemd-resolved
# systemctl disable systemd-resolved
# unlink /etc/resolv.conf
# vim /etc/resolv.conf
nameserver 192.168.1.1
search ad.example.com
At this point, you should have the networking changes in place you need for now. You’ll have to later loop back around and change /etc/resolv.conf to use this machine’s IP address as the nameserver once you have Samba running with it’s built-in DNS server up and running but we don’t want to lose name resolution in the meanwhile so I’ve hard coded it to point to my local DNS server on OpenBSD.
Now it’s time to install the necessary packages to make this machine an active directory domain controller:
# apt update
# apt install acl attr samba samba-dsdb-modules samba-vfs-modules winbind libpam-winbind libnss-winbind libpam-krb5 krb5-config krb5-user dnsutils net-tools smbclient
Specify the FQDN of your server when prompted on the ugly purple screens for things like your Kerberos server and your Administrative server.
Now, it’s time to create the configuration files for Kerberos and Samba. To do this, I ran the following commands:
# mv /etc/krb5.conf /etc/krb5.conf.orig
# mv /etc/samba/smb.conf /etc/samba/smb.conf.orig
# samba-tool domain provision --use-rfc2307 --interactive
I take the defaults, being careful to double-check the DNS forwarder IP address (that’s where the DNS server that will be serving your AD network will forward requests it cannot resolve) and then entered my Administrator password. Keep in mind that be default, the password complexity requirements are set pretty high (which I like) so pick a good one.
Now use the following command to move the Kerberos configuration file that was generated by the Samba provisioning process to its correct location:
# cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
Next, we need to set things up so that the right services are started when you reboot the machine. To do that, issue the following commands:
# systemctl mask smbd nmbd winbind
# systemctl disable smbd nmbd winbind
# systemctl stop smbd nmbd winbind
# systemctl unmask samba-ad-dc
# vim /etc/systemd/system/samba-ad-dc.service
[Unit]
Description=Samba Active Directory Domain Controller
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/sbin/samba -D
PIDFILE=/run/samba/samba.pid
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
# systemctl daemon-reload
# systemctl enable samba-ad-dc
# systemctl start samba-ad-dc
Now go back and update the /etc/resolv.conf file to use the new Samba-supplied DNS service:
# vim /etc/resolv.conf
nameserver 192.168.1.2
search ad.example.com
This is probably a good time to reboot your machine. When you do so, don’t forget to check that /etc/resolv.conf hasn’t been messed with by Ubuntu. If it has, double-check the work you did above and keep trying reboots until it sticks.
Now we need to create the reverse zone for DNS:
# samba-tool dns zonecreate 192.168.1.2 168.192.in-addr.arpa -U Administrator
# samba-tool dns add 192.168.1.2 168.192.in-addr.arpa 2.1 PTR DC1.ad.example.com -U Administrator
If you have multiple NICs in your AD server, you will need to repeat this process for their networks. At this point, double-check that the DNS responder is coming back with what it needs to in order to serve the black magic of the Active Directory clients:
# nslookup DC1.ad.example.com
Server: 192.168.1.2
Address: 192.168.1.2#53
Name: DC1.ad.example.com
Address: 192.168.1.2
# nslookup 192.168.1.2
2.1.168.192.in-addr.arpa name = DC1.ad.exmple.com
# host -t SRV _ldap._tcp.ad.example.com
_ldap._tcp.ad.example.com has SRV record 0 100 389 dc1.ad.example.com
# host -t SRV _kerberos._udp.ad.example.com
_kerberos._udp.ad.example.com has SRV record 0 100 88 dc1.ad.example.com
# host -t A dc1.ad.example.com
dc1.ad.example.com has address 192.168.1.2
If you have multiple NICs in your AD server, you might want to double-check the DNS A records that are returned are reachable from the networks your clients typically use. Since I have a “home” network and a “secure” network, I can manage DNS and DHCP on my secure network so I tend to make sure that my domain controller hostname resolves to an IP address on the secure network. The Windows DHCP admin tools are pretty handy for checking on this and making changes.
Verify that the Samba service has file serving running correctly by listing all of the shares from this server as an anonymous user:
# smbclient -L localhost -N
You should see sysvol, netlogon and IPC$ listed. Any error about SMB1 being disabled is actually a good thing. Validate that a user can successfully log in:
# smbclient //localhost/netlogon -UAdministrator -c 'ls'
You should see a listing of the netlogon share directory which should be empty. Now check that you can successfully authenticate against Kerberos:
# kinit administrator
# klist
You should see a message about when your administrator password will expire if you are successfully authenticated by Kerberos. The klist command should show the ticket that was generated by you logging in as Administrator.
If you look at the documentation in the Samba Wiki, you’ll see that ntp seems to be a better service to use over chrony or optnntpd. If you look at the documentation for chrony (which everyone seems to use), you’ll get a different story. However, when I used chrony, I kept getting NTP errors on my Windows clients so I’m configuring in this post with ntp.
# apt install ntp
# samba -b | grep 'NTP'
NTP_SIGND_SOCKET_DIR: /var/lib/samba/ntp_signd
# chown root:ntp /var/lib/samba/ntp_signd/
# chmod 750 /var/lib/samba/ntp_signd/
# vim /etc/ntp.conf
restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
broadcast 192.168.1.255
disable auth
broadcastclient
# systemctl restart ntp
To be clear, the lines I’m showing after editing the ntp.conf file are lines that you ADD to the file. Also, if you have more than one NIC in the server, you’ll need to add them in on the restrict and broadcast lines as a second line for each.
Now, let’s test that everything is working by enrolling a Windows 10 machine into the domain. Ensure first that you are on the right network and just for safety’s sake, do a reboot so you pick up the DNS server, etc. I have modified the DHCP server on my network to pass the correct information that a client needs as follows (from /etc/dhcpd.conf in OpenBSD):
option domain-name "ad.example.com";
option domain-name-servers 192.168.1.2;
option ntp-servers 192.168.1.2;
Microsoft has done a bang-up job of hiding this in the UI compared to where it has been for literally decades (“get off my lawn!!”). I prefer the old-fashioned way so I ran the following using Windows key + R to get the old UI I’m most comfortable with:
sysdm.cpl
Press the “Change” button and then select “Domain” and enter “ad.example.com” as the name of your domain. That should prompt you for your admin credentials. I typically use AD\administrator as my userid just to be safe. In a matter of seconds, you should be welcomed to the domain.
For safety’s sake, I recommend clearing out your application and system event logs on that machine, rebooting and logging in as your domain admin. Once that’s done, examine the event viewer to ensure that you aren’t seeing any errors that might indicate something isn’t configured correctly on the server. Remember to click the “other user” button on the Windows 10 login screen and use the AD\Administrator to tell Windows which domain you want to log into.
There is a warning (DNS Client Events, Event ID: 8020) that I see in the System event log. This appears to be a problem where the Windows machine tries to re-register with dynamic DNS in Samba with exactly the same info that is already registered for it and Samba returns an error. You can still resolve the client machine from the server so it worked the first time, I think it can be safely ignored for now.
For ease of maintenance you might want to install the “Windows RSAT Tools” on your Windows machine that give you a good UI for managing all of the fun stuff that Active Directory brings to the table. They are a free download.
I really do NOT recommend using your domain controller as a file server. To set that up on another machine, please see the next section.
Samba File Server in a Domain
Thankfully, the wonderful documentation on the Samba WIKI has an entire entry dedicated to setting up Samba as a domain member. First things first, we need to configure the network settings on our file server to use the Active Directory server as the DNS server.
As I did with the domain controller above, I used NetworkManager from the Ubuntu desktop to set the static IPs, the gateway and the netmasks and then modified /etc/hosts as follows:
127.0.0.1 localhost
192.168.1.3 NAS.ad.example.com NAS
It is important to note that Ubuntu will put in an additional 127.0.0.1 line for your host and you need to (apparently, per the documentation) remove that. I then modified my /etc/hostname file as follows:
NAS.ad.example.com
We need to permanently change /etc/resolv.conf and not have Ubuntu overwrite it on the next boot. To do that, we have to:
# systemctl stop systemd-resolved
# systemctl disable systemd-resolved
# unlink /etc/resolv.conf
# vim /etc/resolv.conf
nameserver 192.168.1.2
search ad.example.com
After a quick reboot and verification that the resolv.conf changes survived, we need to install some packages:
# apt install acl attr samba samba-dsdb-modules samba-vfs-modules winbind libpam-winbind libnss-winbind libpam-krb5 krb5-config krb5-user smbclient
Now we need to now configure Kerberos and Samba. First, if there are files currently at /etc/krb5.conf and/or /etc/samba/smb.conf, remove them. Create a new /etc/krb5.conf file with the following contents:
[libdefaults]
default_realm = AD.EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = true
Next, it will be necessary to synchronize time to the domain controller. Since this server won’t be broadcasting network time to client machines (i.e. it isn’t a domain controller), I’ll be setting it up with chrony which is built into Ubuntu.
# apt install chrony ntpdate
# ntpdate 192.168.1.2
# vim /etc/chrony/chrony.conf
server 192.168.1.2 minpoll 0 maxpoll 5 maxdelay .05
# systemctl enable chrony
# systemctl start chrony
That line under the vim command should be the only line in the file. To validate that everything is working, a call to systemctl status chrony should show that it is active and running. First things first, we need to set up the /etc/samba/smb.conf file:
[global]
workgroup = AD
security = ADS
realm = AD.EXAMPLE.COM
netbios name = NAS
domain master = no
local master = no
preferred master = no
idmap config * : backend = tdb
idmap config * : range = 50000-100000
vfs objects = acl_xattr
map acl inherit = Yes
store dos attributes = Yes
winbind use default domain = true
winbind offline logon = false
winbind nss info = rfc2307
winbind refresh tickets = Yes
winbind enum users = Yes
winbind enum groups = Yes
Now we will need to join the domain:
# kinit administrator
# samba-tool domain join AD -U AD\\Administrator
# net ads join -U AD\\Administrator
You’ll probably get a DNS error when you join the domain. Regardless, add an A record and a PTR record for the server into the DNS as follows:
# samba-tool dns add 192.168.1.2 168.192.in-addr.arpa 3.1 PTR NAS.ad.example.com -U Administrator
# samba-tool dns add 192.168.1.2 168.192.in-addr.arpa NAS.ad.example.com A 192.168.1.3
If you have multiple NICs in your file server, make sure you repeat the process for the IP address ranges assigned to them. Now, add the “winbind” parameter as follows to /etc/nsswitch.conf:
# vim /etc/nsswitch.conf
passwd: files winbind systemd
group: files winbind systemd
shadow: files winbind
Next, we will need to enable and start and restart some services:
# systemctl enable smbd nmbd winbind
# systemctl start smbd nmbd winbind
# pam-auth-update
Before proceeding any further, you should probably reboot the machine. Now for some tests to make sure that everything is working ok:
# wbinfo --ping-dc
checking the NETLOGON for domain[AD] dc connection to "dc1.ad.example.com" succeeded.
# wbinfo -g
... list of domain groups ...
# wbinfo -u
... list of domain users ...
# getent group
... list of Linux groups and Windows groups...
# getent passwd
... list of Linux users and Windows users...
Windows Home Directories
A common configuration done by Windows Domain administrators is to create a default “Home” drive (typically mapped to the H: drive letter) for users. To do this, we will want to first set up a file share on the server. The goal will be to set up a mapped “HOME” directory for each domain user. We’ll start off by adding the following to the /etc/samba/smb.conf file:
[users]
comment = Home directories
path = /path/to/folder
read only = no
acl_xattr:ignore system acls = yes
After issuing an “smbcontrol all reload-config” on the file server to reload the changes to the config file, you should now be able to see a share called \\nas\users. When you create the directory on the filesystem, issue the following commands:
# chown "Administrator":"Domain Users" /path/to/folder/
# chmod 0770 /path/to/folder/
It is important to grant the “SeDiskOperatorPrivilege” to the “Domain Admins” group as follows. This has to be done on the file server itself.
# net rpc rights grant "AD\\Domain Admins" SeDiskOperatorPrivilege -U "AD\administrator"
Finally, from the “Active Directory Users and Groups”, select the user in the “Users” folder, right click and select “Properties”. After changing to the “Profile” tab, select the “Connect” radio button under the “Home folder”, choose H: as the drive letter and put in \\nas\users\{user name} for the “To:” entry field. This should automatically create the directory and set the correct permissions on it.
Now log out of the domain and back in as the user account you modified above and you should automatically get an H: drive that maps to that folder on the file server.
User Profiles
OK, so the cool kids on their Windows networks also have this thing called a “Roaming User Profile” that allows you to put their user profile on a file server and then they can move from one machine to another and simply access their stuff as if it was all the same machine. I wanted to see how Samba handled this and sure enough, I got a hit in the Samba wiki that indicated it was possible.
First things first, we need to create a share on our file server to hold the profiles, so I added this to my /etc/samba/smb.conf file:
[profiles]
comment = Users profiles
path = /path/to/profile/directory
browseable = No
read only = No
csc policy = disable
vfs objects = acl_xattr
acl_xattr:ignore system acls = yes
After making that change, I need to create the directory to hold the profiles and set the UNIX ownership and permissions like I did with the home directories above:
# mkdir /path/to/profile/directory
# chown "AD\Administrator":"AD\Domain Users" /path/to/profile/directory
# chmod 0700 /path/to/profile/directory
After a quick “smbcontrol all reload-config” to pull the new changes in, we now have a share on the file server called “profiles” that will hold the resulting Windows user profiles. I used the “Active Directory Users & Computers” tool on my Windows machine (logged in as Administrator), opened the property dialog for my users, navigated to the “Profile” tab and entered the UNC name for the profile directory \\NAS\profiles\{user-name}. The key is to know that, depending on the version of Windows, the system will add a suffix (in my case “.v6”) to that directory name and it will initially be created empty. When you log out, it will actually copy the stuff into the directory and you should see the directories and files show up on your file server. It seems this is the consistent behavior. For example, saving a file into the “Documents” directory on the Windows machine isn’t propagated to the server’s file system until that user logs out.
It really was that easy!
Group Policy
Given the fact that I had, at this point a fully functional Active Directory infrastructure with network home directories, roaming user profiles and all of it was running on Open Source platforms, I thought I’d really try to push it over the edge and dip my toe in the water around Group Policy. Group Policy is some magic stuff based on LDAP that, in the Windows world, allows you to automatically configure an end-user’s workstation. I found documentation in the Samba wiki that indicated it was possible to make this work so I thought I’d give it a try and see what I needed to do.
It looked like the first thing I needed to do was load the Samba “ADMX” templates into the AD domain controller. To do that, I used the following command:
# samba-tool gpo admxload -H dc1.ad.example.com -U Administrator
Sure enough, logging into my Windows machine as a domain admin, I was able to see that the command had indeed injected the Samba files into the Sysvol:
H:\> dir \\DC1\SysVol\ad.example.com\Policies\PolicyDefinitions
That command aove should show you the en-US directory and the samba.admx file. Now we need to download the Microsoft ADMX templates and install them:
# apt install msitools
# cd /tmp
# wget 'https://download.microsoft.com/download/3/0/6/30680643-987a-450c-b906-a455fff4aee8/Administrative%20Templates%20(.admx)%20for%20Windows%2010%20October%202020%20Update.msi'
# msiextract Administrative\ Templates\ \(.admx\)\ for\ Windows\ 10\ October\ 2020\ Update.msi
# samba-tool gpo admxload -U Administrator --admx-dir=Program\ Files/Microsoft\ Group\ Policy/Windows\ 10\ October\ 2020\ Update\ \(20H2\)/PolicyDefinitions/
The last line will take a few seconds as it processes the files and loads them into the SysVol. You can again confirm the presence of the new policies using the “dir” command above from your Windows machine. At this point, you have the group policies set up and installed into your environment and should be able to manipulate them using the “Group Policy Management Console” on your Windows workstation.
Conclusion
While this is probably one of my stranger, and more technical posts, I think this is a cool example of how you can totally eliminate paid software from your server infrastructure and yet still have the full functionality of something like Active Directory in your tool belt.