Introduction
My preferred platforms are Windows Server (for Windows applications obviously) and Debian (for Linux - which in my case includes Docker). However, I want a single username to be valid and useful in similar ways across the two environments.
I've always preferred joining my Debian servers to AD, and getting authentication to work is pretty easy. Recently, though, DNS dynamic update has not been so cooperative.
Goals
Ideally I want similar basic functionality across the Windows and Debian environments. Note that most of what is here probably applies to Ubuntu without much change, but RHEL and its relatives obviously use slightly different configuration files, commands and tools (especially for package management). Since I haven't installed a RHEL variant for at least a decade, it's probably safe to assume I have zero knowledge there.
So what does that mean to me?
Description | How it works on Windows | How it works on Debian |
---|---|---|
Standard User Authentication | Log on to Windows with a domain account, either username or UPN format. A local profile is created in C:\Users and the user has rights granted by groups, including nested groups. | Log onto Debian with a domain account, local username or UPN format. A local profile is created in /home, and the user has rights granted by groups, including nested groups. |
Administrator Elevation | User uses UAC to transition to an elevated context, and administrative user accounts can perform appropriate tasks. | User uses sudo to transition to an elevated context, and administrative accounts can perform appropriate tasks. |
Network Access | RDP enabled by policy. Administrators can remotely access the machine for administration. | SSH enabled. Administrators can remotely access the machine for administration. |
DNS registration | Windows computers register in DNS with their hostname and update when IP addresses change. | Debian computers register in DNS with their hostname and update when IP addresses change. |
That's really not a huge list, but it does make it simpler to correlate actions by individuals across the estate.
Platform
This is all native Windows functionality; Linux is a different beast. I started with Debian Stretch 9.7 (booting from the 9.6 NetInst ISO image). It's a simple base build:
- 2 vCPUs;
- 2GB RAM;
- 64GB Disk 0;
- 1 x NIC on appropriate network;
- 1 x optical drive for installation.
Running quickly through the installer screens:
Mode | Install | You can also do a graphical install, but this is a server - no GUI needed for the most part. If your application does need X, install as appropriate. |
Language | English | I don't speak Russian, so this is the obvious choice. |
Location | Australia | I also don't live in Upper Volta, so again, choose wisely. |
Keymap | American English | Australia tends to get US keyboards. |
Hostname | dockerimage | I'm building a common image for docker roles - both masters and workers |
Domain Name | ad.domain.net | Match the internal AD domain name. You don't have to do this, but it might make it simpler later. |
Root Password | SomethingSecure | I have a password manager I tend to use, but because this is an image it's a long but memorable password |
Local User | Local Admin (local-admin, password) | I haven't yet found a way to avoid creating a local account, and it's not the worst fallback if something goes wrong. I don't think I've ever used it, though. |
Timezone | New South Wales | I hope I don't have to tell you to select this appropriately |
Partitioning Mode | Guided - use entire disk and set up LVM | Personal preference. You could go any approach, but I like to have the ability to expand with LVM if I need to. |
Force UEFI | Yes | I run Gen 2 VMs on Hyper-V, so I force UEFI installation mode. |
Debian Mirror | Local to me (iiNet, Aarnet etc) | Choose wisely, this takes at least ten seconds to change later |
Popularity-Contest | Disable | Personal preference, again |
Install Components | Deselect everything except SSH and the standard utilities | Again, this is a template for a standard server. You may want Gnome on every machine - but I see no reason for it. |
Install takes me about 5-10 minutes depending on prevailing conditions, including local wind speed, the direction of flight of any observed birds, and the amount of coffee left in the cup. Once install is complete, restart and log in as root.
Edit /etc/network/interfaces if you're not planning to use DHCP - mine looks roughly like this:
iface eth0 inet static
address a.b.c.d/24
gateway a.b.c.1
iface eth0 inet6 static
address 2001:aaaa:bbbb:cccc::ffff:gggg/64
gateway 2001:aaaa:bbbb:cccc::ffff:1
Check /etc/resolv.conf to make sure DNS configuration is correct, perhaps similar to:
domain ad.domain.net
search ad.domain.net
nameserver a.b.c.11
nameserver a.b.c.12
I then added the following components with apt:
- hyperv-daemons - because it's a Hyper-V VM, and I like when things actually work
- curl - I prefer it over wget, but this is preference
- apt-transport-https - some repos use https, and with everything transitioning to https only (bloody Google) I think it's only a matter of time before this is common
- realmd - needed for AD membership
- adcli - needed for AD membership
- sssd - needed for AD membership
- ntp - needed for AD membership (time sync)
- packagekit - needed for AD membership
- sssd-tools - needed for AD membership
- cifs-utils - mapped CIFS paths
- sudo - preferred over plain su for auditing, I think
- dnsutils - needed for AD membership
Join the domain with realm:
# realm join -U Administrator ad.domain.net
Edit /etc/sssd/sssd.conf to tweak the sssd configuration to preference:
Operation | Setting | Value | Notes |
---|---|---|---|
Change | use_fully_qualified_names | False | This setting allows logon with unqualified usernames (like Bob) and also with a UPN (Bob.Ford@ad.domain.net) |
Change | fallback_homedir | /home/%d/%u | Home directories are in /home/ad.domain.net/samAccountName |
Add | chpass_provider | ad | Passwords can be changed in AD |
Add | ad_hostname | hostname.ad.domain.net | DNS name to register |
Add | dyndns_update | true | Perform DNS updates (I believe this is the default, but possibly wasn't when I started joining systems to AD) |
Add | dyndns_refresh_interval | 43200 | Time between refreshes. This needs to be the same as, or longer than the minimum refresh time to be effective (I believe this is the default, but possibly wasn't when I started joining systems to AD) |
Add | dyndns_update_ptr | true | Also update the reverse record (I believe this is the default, but possibly wasn't when I started joining systems to AD) |
Add | dyndns_ttl | 3600 | Recommend 1 hour, which matches the minimum refresh interval possible in AD (I believe this is the default, but possibly wasn't when I started joining systems to AD) |
Add | ad_gpo_access_control | disabled | Enforcing mode (default) prevents logon by default - I haven't had time to diagnose this, but disabling is OK for my environment at the moment |
Create the base folder for home directories:
# mkdir /home/ad.domain.net
# chown root:root /home/ad.domain.net
# chmod 755 /home/ad.domain.net/
Update /etc/pam.d/common-session, adding the second line as shown:
session required pam_unix.so
session required pam_mkhomedir.so umask=077 skel=/etc/skel
Restart sssd to effect the changes
# systemctl restart sssd
Enable sudo for Domain Admins (and/or other groups as desired) - this example is very permissive, but it suits the environment:
# echo %domain\\\ admins ALL=\(ALL\) ALL > /etc/sudoers.d/domain-admins
At this point, you're probably expecting everything to work. I did. I was wrong. The Debian server just will not register with AD DNS.
Diagnosis
On the AD side, I turned on debug logging, for updates only, but all other details:
Then, I set debug_level to 10 in /etc/sssd/sssd.conf, and restarted sssd:
# systemctl restart sssd
/var/log/sssd/sssd_ad.domain.net shows the details of the DNS registration - the error was as shown below:
show_message()
Out of recvgss
update_completed()
; TSIG error with server: tsig verify failure
show_message()
The debug log on the AD side showed a similar failure pattern, with the AD DNS server refusing the update.
Turning off Secure updates permitted the name to register, but that's not a long term solution. A number of other causes were proposed:
- Updates to the forward zone must be configured for Secure Only (this is the default state);
- The correct reverse DNS zone must exist (it does, the lack of it annoys my OCD);
- Updates to the reverse zone must be configured for Secure Only (again, default state).
Research suggested there was a bug in sssd, v1.5.0 - which just so happens to be the version available in Debian Stable. It was in a Reddit post I cannot find at the moment.
The Fix
The naive approach (which obviously was the one I selected first) would be to upgrade just sssd using the testing repository - as at this writing, the testing repository is current at v1.16.3. That doesn't work.
Instead, I had to update the rest of the system from stable to testing - I don't think this is the most terrible scenario in the current "everyone on the bleeding edge all the time" world. It's still software that has two weeks without bugs being logged against it, so it's not generally rushed.
Hypothesis: It's not just sssd that requires updates, it's also nsupdate (dnsutils package) and all the dependencies of those packages.
The suite of changes are all to files that drive apt behaviour. Note that there might be better ways to do this, but it worked for me:
Operation | File Path | Contents | Notes |
---|---|---|---|
Move | /etc/apt/sources.list to /etc/apt/sources.list.d/stable.list |
# deb http://ftp.iinet.net.au/debian/debian/ stretch main deb-src http://ftp.iinet.net.au/debian/debian/ stretch main deb http://security.debian.org/debian-security stretch/updates main deb-src http://security.debian.org/debian-security stretch/updates main # stretch-updates, previously known as 'volatile' deb http://ftp.iinet.net.au/debian/debian/ stretch-updates main deb-src http://ftp.iinet.net.au/debian/debian/ stretch-updates main |
This probably isn't needed, but keeping it can't hurt when you want to revert to stable |
Create | /etc/apt/sources.list.d/testing.list |
# deb http://ftp.iinet.net.au/debian/debian/ testing main deb-src http://ftp.iinet.net.au/debian/debian/ testing main deb http://security.debian.org/debian-security testing/updates main deb-src http://security.debian.org/debian-security testing/updates main # testing-updates, previously known as 'volatile' deb http://ftp.iinet.net.au/debian/debian/ testing-updates main deb-src http://ftp.iinet.net.au/debian/debian/ testing-updates main |
Testing will likely be the source of almost everything after we update. |
Create | /etc/apt/preferences.d/stable.pref |
Package: * Pin: release a=stable Pin-Priority: 500 |
Stable seems to default to priority 500, based on apt-cache policy. |
Create | /etc/apt/preferences.d/testing.pref |
Package: * Pin: release a=testing Pin-Priority: 600 |
I set this to 600, leaving a sizeable gap between stable and testing, and between testing and security patches. I think. Hope. |
Now update and upgrade. There were more than 310 changes for me:
# apt update
# apt upgrade
You're going to want to restart, now, because there are changes to systemd among other things. Restarts are needed.
Remove your debug level from sssd.conf, too, else you'll end up with huge log files in /var/log/sssd.