Samba4 AD and Bind DNS

This is Part 1 of the Great Server Migration of 2023, and I want to apologize in advance for the delayed post. I started it the day I did the work but life happened.

So in preparation for that, I’m working on the DNS structure and moving it out to my cloud server where I can get to it easily while remote across the VPN. I am planning on fixing the Wireguard setup as right now it’s running on the server with a static route being passed from the router, which is not ideal since if my server goes down, so goes the Wireguard link. I’d rather not have that situation occur if I can help it.

As a part of the setup, I need to make sure that DNS records are accessible as well as the servers, and that the records get updated properly without my clients needing to figure out where to get the records from in the event of a server failure. I chose Bind over dnsmasq as dnsmasq did not appear to support dynamic DNS per my Google searching. This could be a situation where my Google-fu was lacking, however learning how Bind handles records and dynamic DNS was not too much of a challenge.

Initial setup (I’m running Debian so adapt accordingly) was to install bind via apt:

apt install bind9

Once installed I followed the basic guides on how to setup a file to cover internal DNS zones, and I made a point of doing dynamic DNS because my original plans included running a secondary server offsite. Since that server would be offsite, the IP range would be different and therefore I would need to guarantee that services would still work. Primarily my AD server, which some external (to the AD server) use for authentication. I managed to figure out all of the necessary bits to get it working with the AD server, and I’m going to drop in the bind DNS bits you would need if you had to change the IP address of a Samba AD server.

$ORIGIN .
$TTL 30	; 30 seconds
domain.local		IN SOA	ns1.domain.example. root.ns1.domain.example. (
				18         ; serial
				604800     ; refresh (1 week)
				86400      ; retry (1 day)
				2419200    ; expire (4 weeks)
				604800     ; minimum (1 week)
				)
			NS	ns1.domain.local.
			NS	localhost.
			A	127.0.0.1
			AAAA	::1
$ORIGIN _tcp.Default-First-Site-Name._sites.dc._msdcs.domain.example.
_kerberos		SRV	0 100 88 AD_SRV1.
_ldap			SRV	0 100 389 AD_SRV1.
$ORIGIN dc._msdcs.domain.example.
_ldap._tcp		SRV	0 100 389 AD_SRV1.
$ORIGIN gc._msdcs.domain.example.
_ldap._tcp.Default-First-Site-Name._sites SRV 0 100 3268 AD_SRV1.
_ldap._tcp		SRV	0 100 3268 AD_SRV1.
$ORIGIN _msdcs.domain.example.
_ldap._tcp.pdc		SRV	0 100 389 AD_SRV1.
$ORIGIN _tcp.Default-First-Site-Name._sites.domain.example.
_gc			SRV	0 100 3268 AD_SRV1.
_kerberos		SRV	0 100 88 AD_SRV1.
_ldap			SRV	0 100 389 AD_SRV1.
$ORIGIN _tcp.domain.example.
_gc			SRV	0 100 3268 AD_SRV1.
_kerberos		SRV	0 100 88 AD_SRV1.
_kpasswd		SRV	0 100 464 AD_SRV1.
_ldap			SRV	0 100 389 AD_SRV1.
$ORIGIN _udp.domain.example.
_kerberos		SRV	0 100 88 AD_SRV1.
_kpasswd		SRV	0 100 464 AD_SRV1.
_ldap			SRV	0 100 389 AD_SRV1.
$ORIGIN domain.example.
andoria			A	192.168.6.31
$ORIGIN DomainDnsZones.domain.example.
_ldap._tcp.Default-First-Site-Name._sites SRV 0 100 389 AD_SRV1.
_ldap._tcp		SRV	0 100 389 AD_SRV1.
$ORIGIN domain.example.
ds9			A	172.25.25.1
$ORIGIN ForestDnsZones.domain.example.
_ldap._tcp.Default-First-Site-Name._sites SRV 0 100 389 AD_SRV1.
_ldap._tcp		SRV	0 100 389 AD_SRV1.

That’s the records needed to make a Samba AD work. I pulled them from the DNS config I had in my Samba server and converted them to bind9 format. I want to make clear that you can have an easier time just connecting Samba to the bind9 instance, and it has been said that you can do it via a Samba share. So I could have just simply made a Samba share that I mounted whenever the VM would be booted, and it wouldn’t matter where the VM was physically/virtually stored as it would update the records accordingly.

That said, I need to mention a caveat: I did notice at one point during testing that the records where being duplicated, as in I would see two results returned when using nslookup or dig, and that is not what I needed. At some point I don’t know if I resolved the issue or if it resolved itself, but here is the updater script I have that pulls the IP from the machine and sends the updated record to bind9. I’m not covering how to get that working as there are plenty of guides out there and that could change by the time you see this, so use your search-fu and look into setting up bind9 and bind9 with dynamic dns records and how to update them securely.

#!/bin/bash
sleep 1
KEY="/root/dns.key" # Example key file
IP=$(hostname -I)
cat <<EOF | nsupdate -k "$KEY"
zone domain.local
server 172.25.25.1
update delete AD_SRV1.domain.example. A
update add AD_SRV1.domain.example. 30 A $IP
show
send
EOF

samba_dnsupdate --verbose

The sleep 1 line is to make sure the network is fully up and running before it tries to pull the IP address. That could be a symptom of the server running across a wireless link, or could be that systemd was so fast that it was beating the script to the punch. This script runs on startup, and I used systemd as it was the default init system.

[Unit]
Description=Update DNS server with local IP address
Before=cockpit.service
[Service]
Type=simple
ExecStart=/bin/bash /srv/scripts/startup/update_dns.sh

[Install]
WantedBy=multi-user.target

I run cockpit on some of the servers so I can have a web interface to them without needing full-blown ssh connectivity (Chromebooks are an example of this) (I’m aware I can use crosh). I don’t like adding components that increase attack surface, and in this instance I recommend using a tool called systemd-analyze.

systemd-analyze critical-chain

Using that allowed me to figure out what I should use as a reference marker during bootup. I happen to have cockpit installed and that seemed like as good a place as any. Adapt to fit your environment. At this point that covers my basic needs for DNS and the Samba AD, and the last script can also be used on other servers to update their records as well. In my case, I’m not sure that’s necessary as I don’t plan on making other systems with any degree of high availability, but if I ever decide to do that I can implement this on those systems as well.

If you have anything you’d like to comment on or add, feel free to do so, and I can update the post as time marches on.