Samba AD DC with Bind as DNS backend

How to set up a Samba AD DC to use Bind as its DNS backend in 2020 on Ubuntu 18.04. I’m writing this down as I go, because I feel a lot of chaos incoming and I kindof want that documented for some reason. TL;DR skip to “Configuration”.

Update: In practice, this configuration has proven somewhat unstable, so I reverted to SAMBA_INTERNAL DNS with a Bind instance as forwarder. This is finally working.

Preparation

Let’s disect those docs a bit and find out what goes where, and what it is we’re actually going to do.

Module selection

Existing backend modules are BIND9_FLATFILE and BIND9_DLZ.

docs say:

Do not use the BIND9_FLATFILE DNS back end. It is not supported and will be formally
deprecated when 4.11.0 is released and removed at 4.12.0.

So I’ll use BIND9_DLZ then.

My bind9 version is 9.11:

# dpkg -l | grep bind9
ii  bind9       1:9.11.3+dfsg-1ubuntu1.11        amd64    Internet Domain Name Server

/usr/share/samba/setup/named.conf.dlz says:

dlz "AD DNS Zone" {
    ${BIND9_11} database "dlopen ${MODULESDIR}/bind9/dlz_bind9_11.so";
};

That seems to be this one: /usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so

Kerberos, chroot

/usr/share/samba/setup/named.txt says:

# If you are running a capable version of BIND and you wish to support
# secure GSS-TSIG updates, you must make the following configuration
# changes:

This probably makes most sense when your bind and your samba are on separate hosts. That’s not the case for me, so I’ll skip this. If I decide to use it later, the keytab is probably /var/lib/samba/private/secrets.keytab.

There’s this interesting tidbit though:

# Steps for BIND 9.x.x using BIND9_DLZ ------------------------------
#

# 3. Disable chroot support in BIND.  
#    BIND is often configured to run in a chroot, but this is not
#    compatible with access to the dns/sam.ldb files that database
#    access and updates require.  Additionally, the DLZ plugin is
#    linked to a large number of Samba shared libraries and loads
#    additonal plugins.

Not sure if this applies to my setup, but I guess it probably does. So if Bind refuses to start once I load the DLZ library, I’ll give this a shot. Also:

# ldd /usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so | wc -l
85

There’s a good chance that one of those dependencies is not going to be included in the chroot, but we’ll see.

dlopen support

docs say that this should not be empty:

# named -V  | grep dlopen
#

But:

Later versions of Bind9.9.x have the --with-dlopen option builtin and is not
shown by the following command. This happened around Bind 9.9.4

So we’re probably safe on this one.

named.conf

There’s a file named /usr/share/samba/setup/named.conf. This file also exists under /var/lib/samba/private/named.conf, so I guess Samba pre-fills it for our Domain:

# [snip commentary]

zone "local.lan." IN {
        type master;
        file "/var/lib/samba/private/dns/local.lan.zone";
        include "/var/lib/samba/private/named.conf.update";
        check-names ignore;
};

That zone-file exists and looks valid, but I wonder if we need it? Doesn’t the DLZ module cause bind to read things from Samba’s LDAP anyway? Hm.

Oddly enough, in my production setup the whole config file doesn’t exist. So perhaps this is a remnant of the past. In that case, the whole /usr/share/samba/setup/named.conf thing is probably obsolete.

named.conf.update

There’s also a file /usr/share/samba/setup/named.conf.update that says:

/*
        this file will be automatically replaced with the correct
        'grant' rules by samba at runtime
*/

That’s probably somewhat untrue because it won’t do that under /usr. But there’s also a guy called /var/lib/samba/private/named.conf.update:

/* this file is auto-generated - do not edit */
update-policy {
        grant LOCAL.LAN ms-self * A AAAA;
        grant Administrator@LOCAL.LAN wildcard * A AAAA SRV CNAME;
        grant DC$@local.lan wildcard * A AAAA SRV CNAME;
};

That looks utterly correct. And Bind won’t be able to access these files while it runs chrooted (unless I hardlink them into the chroot or something, which will probably break as soon as Samba decides to re-generate those files which I have no idea when that may happen. Probably when I scrap and re-join that box.) So I’m inclined to disable chroot at this point.

Configuration

Allright, so here we go. I assume you have the samba and bind9 packages installed. I’m doing this on a RODC that I set up a while ago, using the SAMBA_INTERNAL DNS backend at the time. Turns out that this backend has a few drawbacks (like, it doesn’t support caching).

Disable Samba’s DNS server

I’ll start with updating smb.conf. Remove these lines:

[global]
        recursive queries = yes
        dns forwarder = 8.8.8.8

And add this one:

[global]
        server services = -dns

After restarting Samba, it does not bind to the DNS port anymore:

# netstat -tupln | grep samba | grep :53
# 

And I now can start bind:

# service bind9 start
# service bind9 status
● bind9.service - BIND Domain Name Server
   Loaded: loaded (/lib/systemd/system/bind9.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-04-03 09:58:17 UTC; 1s ago

So far, so good.

Enable bind

Now it’s time to dive into the DLZ configuration. I’ll start by defining the zone for my domain in /etc/bind/named.conf.local. I’ll liberally merge this with the config I found on my olden boxen:

dlz "local.lan" {
    type master;
    database "dlopen /usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so";
    include "/var/lib/samba/private/named.conf.update";
    check-names ignore;
};

Turns out that made Bind unhappy and I’ll have to exclude anything that is not the database line, so the config is now:

dlz "local.lan" {
    database "dlopen /usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so";
};

Let’s see what that does then.

# named-checkconf
# service bind9 restart
# dig @127.0.0.1 local.lan

; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @127.0.0.1 local.lan
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

# journalctl -fu bind9
Apr 03 10:15:36 fraitvm006 named[7143]: Loading 'local.lan' using driver dlopen
Apr 03 10:15:36 fraitvm006 named[7143]: dlz_dlopen failed to open library '/usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so' - /usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so: failed to map segment from shared object
Apr 03 10:15:36 fraitvm006 named[7143]: dlz_dlopen of 'local.lan' failed
Apr 03 10:15:36 fraitvm006 named[7143]: SDLZ driver failed to load.
Apr 03 10:15:36 fraitvm006 named[7143]: DLZ driver failed to load.
Apr 03 10:15:36 fraitvm006 named[7143]: loading configuration: failure
Apr 03 10:15:36 fraitvm006 named[7143]: exiting (due to fatal error)
Apr 03 10:15:36 fraitvm006 systemd[1]: bind9.service: Main process exited, code=exited, status=1/FAILURE

So much for that - I forgot the chroot. chroot is disabled though (no -t option in /etc/default/bind9). So - AppArmor?

Add to /etc/apparmor.d/local/usr.sbin.named:

/lib/** rm,
/usr/lib/** rm,
/var/lib/samba/private/** rwk,

Uncomment dizzles in /etc/apparmor.d/usr.sbin.named:

  # Site-specific additions and overrides. See local/README for details.
  include <local/usr.sbin.named>
# service apparmor reload
# service bind9 restart

Convert the database

Now it’ll probably complain that samba_dlz: Failed to connect to /var/lib/samba/private/dns/sam.ldb. This means it’s time to run this guy:

# ls -la /var/lib/samba/private/dns/sam.ldb
ls: cannot access '/var/lib/samba/private/dns/sam.ldb': No such file or directory
# service samba-ad-dc stop
# samba_upgradedns --dns-backend=BIND9_DLZ
Reading domain information
DNS accounts already exist
No zone file /var/lib/samba/private/dns/LOCAL.LAN.zone
DNS records will be automatically created
DNS partitions already exist
Traceback (most recent call last):
  File "/usr/sbin/samba_upgradedns", line 408, in <module>
    ldbs.sam.modify(m)
_ldb.LdbError: (1, 'Invalid LDB reply type 1')

Hooray. Since this is just a RODC anyway, I’ll nuke it and re-join because fuck this noise:

# rm -rf /var/lib/samba
# mkdir /var/lib/samba
# samba-tool domain join local.lan RODC \
    -U"LOCALLAN\Administrator"        \
    --dns-backend=BIND9_DLZ           \
    --site=Moon
[ snip all the things ]
# la /var/lib/samba/private/dns/sam.ldb
-rw-rw---- 1 root bind 9179136 Apr  3 10:54 /var/lib/samba/private/dns/sam.ldb
# service samba-ad-dc start
# service bind9 start
# service bind9 status
● bind9.service - BIND Domain Name Server
   Loaded: loaded (/etc/systemd/system/bind9.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-04-03 10:55:59 UTC; 2s ago

But, doest thou work?

# dig +short @127.0.0.1 google.com
216.58.211.110

That’s a start…

# dig  @127.0.0.1 local.lan

; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @127.0.0.1 local.lan
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2766
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 9a5870868150e003c9c41dc15e871698eca50c9172d60dfc (good)
;; QUESTION SECTION:
;local.lan.              IN      A

;; ANSWER SECTION:
local.lan.       600     IN      A       192.168.0.5

;; AUTHORITY SECTION:
local.lan.       3600    IN      NS      dc.local.lan.

;; ADDITIONAL SECTION:
dc.local.lan.    3600    IN      A       192.168.0.5

;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Apr 03 10:57:28 UTC 2020
;; MSG SIZE  rcvd: 243

OMGWTFBBQ!