Securing BIND 9 with AppArmor/Firejail/Systemd Workshop
1 BIND 9 Security workshop
The virtual machines have a domain name in the form
apparmorNNN.dnslab.org
.
Please login to the machines with a modern web browser under the URL
https://apparmorNNN.dnslab.org:9090 with the username user
and the
password DNSandBIND
. You can also login with SSH and the same
username and password.
The virtual machines run the cockpit
tool
(https://cockpit-project.org) to provide a terminal in the web
browser.
Then select the terminal (last menue option on the left) and start the tutorial.
1.1 Virtual machines
Every participant has a VM number. Please replace the NNN
in the
instructions with your participant number from the table below:
VM Number | Name |
1.2 Basic Installation
- For the sessions you need to become the user
root
with thesudo
command, for example withsudo -s
- A command line promt starting with
%
indicates a root shell
2 Session 1 - Fixing an AppArmor permission issue
- Login to the Lab VM machine and switch to the root user with
sudo -i
- Check that AppArmor is installed and enabled
% aa-status apparmor module is loaded. 8 profiles are loaded. 8 profiles are in enforce mode. /usr/bin/man /usr/sbin/chronyd lsb_release man_filter man_groff nvidia_modprobe nvidia_modprobe//kmod tcpdump 0 profiles are in complain mode. 2 processes have profiles defined. 2 processes are in enforce mode. /usr/sbin/chronyd (737) /usr/sbin/chronyd (739) 0 processes are in complain mode. 0 processes are unconfined but have a profile defined.
- Install the BIND 9 DNS Server
% apt install bind9
- Check that the BIND 9 process is running under AppArmor control
% ps auxZ | grep named named (enforce) bind 11913 0.8 2.5 221376 25636 ? Ssl 09:20 0:00 /usr/sbin/named -f -u bind unconfined root 12068 0.0 0.0 5204 732 pts/1 S+ 09:20 0:00 grep named
- Create a non-standard directory for storing secondary zone files
(we propose there are technical or organisational reasons that
demand this change)
% mkdir -p /srv/bind/zonefiles/secondary % chown bind: /srv/bind/zonefiles/secondary
- Remove the default BIND 9 configuration
/etc/bind/named.conf
and replace it with the content belowoptions { recursion no; directory "/var/cache/bind"; }; zone "dnssec.works" { type secondary; file "/srv/bind/zonefiles/secondary/dnssec.works"; primaries { 5.45.109.212; 2a03:4000:6:2115::2; }; };
- Save the file and check the configuration for errors
% named-checkconf
- Restart the BIND 9 service and check it's status
% systemctl restart bind9
- There should be a problem reported: AppArmor does not allow BIND 9 to write to the secondary zone file
% systemctl status bind9 ● named.service - BIND Domain Name Server Loaded: loaded (/lib/systemd/system/named.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2021-10-20 09:30:22 UTC; 2s ago Docs: man:named(8) Main PID: 12365 (named) Tasks: 5 (limit: 1132) Memory: 17.0M CPU: 66ms CGroup: /system.slice/named.service └─12365 /usr/sbin/named -f -u bind Oct 20 09:30:22 apparmor001 named[12365]: running Oct 20 09:30:22 apparmor001 named[12365]: managed-keys-zone: Key 20326 for zone . is now trusted (acceptance timer complete) Oct 20 09:30:22 apparmor001 named[12365]: zone dnssec.works/IN: Transfer started. Oct 20 09:30:22 apparmor001 named[12365]: resolver priming query complete Oct 20 09:30:22 apparmor001 named[12365]: transfer of 'dnssec.works/IN' from 5.45.109.212#53: connected using 161.35.104.3#60547 Oct 20 09:30:23 apparmor001 named[12365]: zone dnssec.works/IN: transferred serial 3151 Oct 20 09:30:23 apparmor001 named[12365]: transfer of 'dnssec.works/IN' from 5.45.109.212#53: Transfer status: success Oct 20 09:30:23 apparmor001 named[12365]: transfer of 'dnssec.works/IN' from 5.45.109.212#53: Transfer completed: 2 messages, 259 records, 32087 bytes, 0.272 secs (117966 bytes/sec)> Oct 20 09:30:23 apparmor001 named[12365]: zone dnssec.works/IN: sending notifies (serial 3151) Oct 20 09:30:23 apparmor001 named[12365]: dumping master file: /srv/bind/zonefiles/secondary/tmp-pV7V2CdOuA: open: permission denied
- See the AppArmor "deny" message in the Linux audit logfile
% grep denied /var/log/audit/audit.log type=AVC msg=audit(1634722223.143:20): apparmor="DENIED" operation="mknod" profile="named" name="/srv/bind/zonefiles/secondary/tmp-pV7V2CdOuA" pid=12365 comm="isc-worker0000" requested_mask="c" denied_mask="c" fsuid=112 ouid=112FSUID="bind" OUID="bind"
- Try to change the AppArmor profile for BIND 9 in
/etc/apparmor.d/usr.sbin.named
to fix the permission issue - The Solution will be published after 15 minutes of the lab start
2.1 Solution
- Add the following line to the (local) AppArmor profile
/srv/bind/zonefiles/secondary/** lrw,
- Restart AppArmor and BIND 9
% systemctl restart apparmor % systemctl restart bind9
3 Session 2 - Secure BIND 9 with Firejail
- Login to the lab VM and switch to the
root
user withsudo -i
- Disable AppArmor (until next reboot)
% systemctl stop apparmor % aa-teardown
- Install the BIND 9 DNS Server
% apt install bind9
- Create a non-standard directory for storing secondary zone files
(we propose there are technical or organisational reasons that
demand this change)
% mkdir -p /srv/bind/zonefiles/secondary % chown bind: /srv/bind/zonefiles/secondary
- If you have worked on session 1 above, remove the secondary zone file
% rm /srv/bind/zonefiles/secondary/dnssec.works
- Remove the default BIND 9 configuration
/etc/bind/named.conf
and replace it with the content belowoptions { recursion no; directory "/var/cache/bind"; }; zone "dnssec.works" { type secondary; file "/srv/bind/zonefiles/secondary/dnssec.works"; primaries { 5.45.109.212; 2a03:4000:6:2115::2; }; };
- Save the file and check the configuration for errors
% named-checkconf
- Install Firejail (The Debian 11 package for Firejail pulls in a
large number of dependencies. This is an artifact of the Debian 11
packaging system and not required by Firejail)
% apt install firejail firejail-profiles
- Install the Firejail profile for BIND 9 in
/etc/firejail/named.profile
# Firejail profile for BIND 9 (named) # Description: Authoritative DNS Server and DNS resolver name named # Persistent local customizations include named.local # Persistent global definitions include globals.local noblacklist /sbin noblacklist /usr/sbin blacklist /tmp/.X11-unix blacklist ${RUNUSER}/wayland-* include disable-common.inc include disable-devel.inc include disable-exec.inc include disable-interpreters.inc include disable-passwdmgr.inc include disable-programs.inc include disable-xdg.inc include whitelist-usr-share-common.inc whitelist /etc/bind whitelist /etc/passwd whitelist /var/cache/bind whitelist /var/run caps.keep net_admin,net_bind_service,setgid,setuid,sys_chroot,sys_resource ipc-namespace machine-id netfilter no3d nodvd nonewprivs nosound notv nou2f novideo protocol inet,inet6,unix,netlink seccomp.drop _sysctl,acct,add_key,adjtimex,clock_adjtime,delete_module,fanotify_init,finit_module,get_mempolicy,init_module,io_cancel,io_destroy,io_getevents,io_setup,io_submit,ioperm,iopl,kcmp,kexec_file_load,kexec_load,keyctl,lookup_dcookie,mbind,migrate_pages,modify_ldt,mount,move_pages,open_by_handle_at,perf_event_open,perf_event_open,pivot_root,process_vm_readv,process_vm_writev,ptrace,remap_file_pages,request_key,set_mempolicy,swapoff,swapon,sysfs,syslog,umount2,uselib,vmsplice disable-mnt private private-dev private-tmp writable-var dbus-user none dbus-system none # mdwe can break modules/plugins memory-deny-write-execute
- Install a new systemd-unit for the Firejail protected BIND 9
service
/etc/systemd/system/bind9-hardened.service
[Unit] Description=BIND Domain Name Server Documentation=man:named(8) After=network.target Wants=nss-lookup.target Before=nss-lookup.target [Service] EnvironmentFile=-/etc/default/named ExecStart=/usr/bin/firejail /usr/sbin/named -f $OPTIONS ExecReload=/usr/sbin/rndc reload ExecStop=/usr/sbin/rndc stop Restart=on-failure [Install] WantedBy=multi-user.target Alias=bind9.service
- Load the new service unit into Systemd, stop the non-hardened BIND
9 service and start the new hardened BIND 9
% systemctl daemon-reload % systemctl stop bind9 % systemctl disable bind9 % systemctl enable --now bind9-hardened % systemctl disable bind9 Removed /etc/systemd/system/bind9.service. Removed /etc/systemd/system/multi-user.target.wants/named.service. root@apparmor001:/home/user# systemctl enable --now bind9-hardened Created symlink /etc/systemd/system/bind9.service → /etc/systemd/system/bind9-hardened.service. Created symlink /etc/systemd/system/multi-user.target.wants/bind9-hardened.service → /etc/systemd/system/bind9-hardened.service. root@apparmor001:/home/user# systemctl status bind9-hardened ● bind9-hardened.service - BIND Domain Name Server Loaded: loaded (/etc/systemd/system/bind9-hardened.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2021-10-20 09:52:31 UTC; 7s ago Docs: man:named(8) Main PID: 18946 (firejail) Tasks: 7 (limit: 1132) Memory: 19.2M CPU: 158ms CGroup: /system.slice/bind9-hardened.service ├─18946 /usr/bin/firejail /usr/sbin/named -f -u bind ├─18947 /usr/bin/firejail /usr/sbin/named -f -u bind └─18953 /usr/sbin/named -f -u bind Oct 20 09:52:32 apparmor001 named[18953]: running Oct 20 09:52:32 apparmor001 named[18953]: managed-keys-zone: Key 20326 for zone . is now trusted (acceptance timer complete) Oct 20 09:52:32 apparmor001 named[18953]: resolver priming query complete
- Check that BIND 9
named
is running under Firejail control% firejail --top
4 Session 3 - Harden the BIND 9 Systemd Unit
- Login to the lab VM and switch to the
root
user withsudo -i
- Install the BIND 9 DNS Server
% apt install bind9
- If you have worked on Session 2 (Firejail), disabled the hardened
BIND 9 service unit, enable the default BIND 9 service unit and re-enable AppArmor
% systemctl stop bind9-hardened % systemctl disable bind9-hardened % systemctl enable --now named % systemctl start apparmor
- Analyze the security of the default BIND 9 Systemd unit and note
down the exposure level for
named.service
% systemd-analyze security bind9
- Create a new Systemd service unit in
/etc/systemd/system/named-secure.service
[Unit] Description=BIND Domain Name Server Documentation=man:named(8) After=network.target Wants=nss-lookup.target Before=nss-lookup.target [Service] EnvironmentFile=-/etc/default/named ExecStart=/usr/sbin/named -f $OPTIONS ExecReload=/usr/sbin/rndc reload ExecStop=/usr/sbin/rndc stop Restart=on-failure AppArmorProfile=named Personality=x86-64 LockPersonality=yes UMask=077 MemoryMax=2G TasksMax=20 RestrictNamespaces=Yes RestrictRealtime=True MemoryDenyWriteExecute=True NoNewPrivileges=Yes PrivateDevices=Yes DevicePolicy=closed PrivateTmp=Yes PrivateMounts=Yes ProtectClock=Yes ProtectControlGroups=Yes ProtectHome=Yes ProtectKernelLogs=Yes ProtectKernelModules=Yes ProtectKernelTunables=Yes ProtectProc=invisible ProcSubset=pid ProtectSystem=Yes ProtectHostname=Yes RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK SystemCallFilter=~@clock @debug @module @mount @raw-io @reboot @swap @cpu-emulation @obsolete CapabilityBoundingSet=~CAP_SETPCAP CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_(DAC_OVERWRITE CAP_FOWNER CAP_IPC_OWNER CapabilityBoundingSet=~CAP_SYS_MODULE CAP_SYS_RAWIO CAP_SYS_TIME CAP_AUDIT_CONTROL CAP_KILL CAP_MKNOD CAP_NET_BROADCAST CAP_NET_RAW CapabilityBoundingSet=~CAP_SYS_NICE CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_BPF CAP_SYS_BOOT CAP_LINUX_IMMUTABLE CAP_IPC_LOCK CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_LEASE CAP_SYS_PACCT CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM [Install] WantedBy=multi-user.target Alias=bind9-secure.service
- Load the new Systemd unit, stop the old BIND 9 service and start
BIND 9 with the new secure unit definition
% systemctl daemon-reload % systemctl stop named % systemctl disable named % systemctl enable --now named-secure
- Check the status of the BIND 9 service (the Tasks and Memory
limits indicate that the new service unit is active)
% systemctl status named-secure ● named-secure.service - BIND Domain Name Server Loaded: loaded (/etc/systemd/system/named-secure.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2021-10-20 10:13:32 UTC; 2s ago Docs: man:named(8) Main PID: 19439 (named) Tasks: 5 (limit: 20) Memory: 17.3M (max: 2.0G) CPU: 109ms CGroup: /system.slice/named-secure.service └─19439 /usr/sbin/named -f -u bind Oct 20 10:13:33 apparmor001 named[19439]: managed-keys-zone: loaded serial 16 Oct 20 10:13:33 apparmor001 named[19439]: zone dnssec.works/IN: loaded serial 3151 (DNSSEC signed) Oct 20 10:13:33 apparmor001 named[19439]: all zones loaded Oct 20 10:13:33 apparmor001 named[19439]: running Oct 20 10:13:33 apparmor001 named[19439]: zone dnssec.works/IN: sending notifies (serial 3151) Oct 20 10:13:33 apparmor001 named[19439]: missing expected cookie from 2001:500:1::53#53 Oct 20 10:13:33 apparmor001 named[19439]: missing expected cookie from 2001:500:1::53#53 Oct 20 10:13:33 apparmor001 named[19439]: missing expected cookie from 2001:500:1::53#53 Oct 20 10:13:33 apparmor001 named[19439]: managed-keys-zone: Key 20326 for zone . is now trusted (acceptance timer complete) Oct 20 10:13:33 apparmor001 named[19439]: resolver priming query complete
- Check the security score of the new Systemd unit and compare with the original result
% systemd-analyze security named-secure