DNSSEC and E-Mail Security workshop @ SWITCH

1 Agenda and Slides

1.2 Slides

1.2.1 DNSSEC

1.2.2 SPF, DKIM and DMARC

1.3 DNSSEC workshop agenda

  • 12:30 Welcome
  • 12:45 DNSSEC in a nutshell
  • 14:30 Operating a DNSSEC resolver
  • 15:30 Break
  • 15:45 DNSSEC signing best practices
  • 16:30 DNSSEC Risk mitigation
  • 17:30 End of the workshop

2 General Information

  • This instructions and the slides can be found online at https://switch.dane.onl
  • Please replace the placeholder characters NN in the instructions with your participant number. You can find your participant number in the table on this page
  • We have prepared two Linux virtual machines in the Internet (one primary authoritative DNS server and one DNS resolver). These machines have a Debian 11 OS installed. You can reach these machines via secure shell (SSH) or via Web-Browser (Cockpit Terminal).

3 Mail and DNS-Server VMs

  • Your authoritative DNS-Server: dns.zNN.dane.onl
  • Text editors evailanble preinstalled on the server: emacs, vim, nano, mg (MicroEmacs). Feel free to install other editors or software that can help you with the workshop
  • Preinstalled tools tmux, dvtm
  • The Bash-Shell can be started with the command bash

4 DNSSEC

4.1 Hands-On: Install DNS resolver

  • Install the DNS query tools (nslookup, dig)
    % apt install dnsutils
    
  • Install the Unbound DNS resolver. DNSSEC validation is enabled by default, there is no need to adjust the configuration
    % apt install unbound
    
  • Test the DNSSEC validation (the AD-Flag must be shown)
    % dig switch.ch a @localhost
    
    ; <<>> DiG 9.16.22-Debian <<>> @localhost  switch.ch a
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50512
    ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ;; QUESTION SECTION:
    ;switch.ch.			IN	A
    
    ;; ANSWER SECTION:
    switch.ch.		300	IN	A	130.59.31.80
    
    ;; Query time: 20 msec
    ;; SERVER: 127.0.0.1#53(127.0.0.1)
    ;; WHEN: Wed Mar 09 09:57:10 UTC 2022
    ;; MSG SIZE  rcvd: 52
    
    

4.2 Hands-On: DNSSEC signatures

  • Work on the DNS resolver VM
  • Request the DNSSEC signature for dnssec.works NS:
    $ dig @localhost dnssec.works NS +dnssec +multi
    
  • Try to answert the following questions

4.3 Hands-On: Negative Trust Anchor (Unbound)

  • The domain fail01.dnssec.works has DNSSEC validation issues
% dig fail01.dnssec.works @localhost

; <<>> DiG 9.16.27-Debian <<>> fail01.dnssec.works @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 32784
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;fail01.dnssec.works.           IN      A

;; Query time: 172 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Aug 29 05:35:52 UTC 2022
;; MSG SIZE  rcvd: 48
  • Create a new text file in /etc/unbound/unbound.conf.d/NTA-fail01-dnssec-works.conf with this content:
server:
  domain-insecure: fail01.dnssec.works
  • Check the Unbound configuration for syntax errors
% unbound-checkconf 
unbound-checkconf: no errors in /etc/unbound/unbound.conf
  • Reload the Unbound configuration
% unbound-control reload
OK
  • Test the Name resolution of the failing domain again, it should now resolve (but without DNSSEC validation - no AD-Flag!)
# dig fail01.dnssec.works @localhost                                                                                                                                        
                                                                                                                                                                                                  
; <<>> DiG 9.16.27-Debian <<>> fail01.dnssec.works @localhost                                                                                                                                     
;; global options: +cmd                                                                                                                                                                           
;; Got answer:                                                                                                                                                                                    
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31681                                                                                                                                         
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;fail01.dnssec.works.           IN      A

;; ANSWER SECTION:
fail01.dnssec.works.    3600    IN      A       5.45.109.212

;; Query time: 364 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Aug 29 05:35:17 UTC 2022
;; MSG SIZE  rcvd: 64
  • Negative Trust Anchors in Unbound are not automatically removed
    • In production environments, implement a system that will remove the NTA automatically after some time or once the DNSSEC issue is solved on the domain owners side

4.4 Hands-On: Configuring a BIND 9 authoritative DNS server and DNS zone

  • Use the virtual lab machine (authoritative DNS Server dns.zNN.dane.onl)
  • Work as user root
    $ sudo -s
    
  • Verify that the BIND 9 DNS server process is started
    % systemctl status bind9
    
  • Edit the BIND 9 configuration file /etc/bind/named.conf with a text editor of your choice. There is a primary authoritative zone for the domain zNN.dane.onl preconfigured
    % chmod +w /etc/bind/named.conf
    % nano /etc/bind/named.conf
    
  • Make the zonefile /etc/bind/zonefile.db writeable (chmod +w /etc/bind/zonefile.db) and open the zone file in an editor. Add the IPv6 Address record (AAAA-Record) of the server at the APEX of the zone (at the base domain name), You can get the IPv6 address of the server with the command hostname -I. Increment the SOA serial number and save the changes.
    • Example AAAA-Record:
      zNN.dane.onl.    IN AAAA 2001:db8::1
      
  • Check both the BIND 9 configuration file and the zone file for syntax errors
    % named-checkconf -z
    
  • If no errors are reported, load the configuration and the new zone file into the BIND 9 server (using rndc)
    % rndc reload zNN.dane.onl
    
  • Verify that the DNS server responds to DNS queries and contains the new SOA serial number
    $ dig @::1 zNN.dane.onl SOA
    
  • Use an external DNS-Resolver (in this example we use Quad9) or your own recursive resolver at dnsr.zNN.dane.onl to resolve the IPv6 address of the server:
    $ dig @9.9.9.9 zNN.dane.onl AAAA
    

4.5 Hands-On: DNSSEC with BIND 9 inline-signing

  • Use the virtual lab sever dns.zNN.dane.onl (authoritative primary DNS)
  • Configure a directory for the DNSSEC keys in the BIND 9 configuration file /etc/bind/named.conf. Make sure that the directory configured in the key-directory statement exists.
    options {
    	  directory "/etc/bind";
    	  key-directory "keys";
    };
    
  • Create a DNSSEC key pair (ZSK and KSK) for the zone
    • The parameter -K defines the directory where the new key(s) will be stored
    % dnssec-keygen -a RSASHA256 -b 1536 -K /etc/bind/keys -n ZONE zNN.dane.onl
    % dnssec-keygen -a RSASHA256 -b 2048 -K /etc/bind/keys -f KSK -n ZONE zNN.dane.onl
    
  • Make sure that the BIND 9 process bind can read the key files, the zonefiles and the configuration files
    % chown -R bind:bind /etc/bind
    
  • Activate the inline-signing function for the domain zNN.dane.onl, including auto-dnssec for automatic DNSSEC key management:
    zone "zNN.dane.onl" IN {
    	  type master;
    	  file "zonefile.db";
    	  inline-signing yes;
    	  auto-dnssec maintain;
    };
    
  • Text the new configuration, reload the new configuration into the server and have the zone DNSSEC signed:
    % named-checkconf -z
    % rndc reconfig
    % rndc sign zNN.dane.onl
    
  • Check the log files for error messages during the signing (the command rndc sign will never report a signing error!)
    % tail /var/log/daemon.log 
    Sep 20 19:51:08 auth05 named[12822]: received control channel command 'sign zNN.dane.onl'
    Sep 20 19:51:08 auth05 named[12822]: zone zNN.dane.onl/IN (signed): reconfiguring zone keys
    Sep 20 19:51:08 auth05 named[12822]: zone zNN.dane.onl/IN (signed): next key event: 20-Sep-2021 20:51:08.845
    
  • The new zonefile containing the DNSSEC signed zone will be written in binary RAW format.
    • The new file will have the file extension .signed
    • In addition to the new signed zone file, BIND 9 will also create a journal file with the extension .jnl. This file will contain the journal of all changes over time (required for incremental zone transfers of the zone). There will also be a backup of the journal file with the extension .jbk
  • The original zone file will not be changed!
  • All changes to the zone file created through the inline-signing process will be written to storage after approx. 15 minutes
    • This can be forced with the command rndc sync
  • All changes to the zone file will be done in the usual way inside the original zone file
    • The SOA-Serial-number must be incremented after each change
    • The SOA-Serial-number does not need to be higher than the number seen on the live server, it must just be higher than the last loaded SOA serial number.
  • Add a new TXT-Record to the zone file and increment the SOA serial number: erhöhen
    % nano zonefile.db
    
  • Example of a TXT-Record
    zNN.dane.onl.    IN TXT "Hello, this is a TXT record"
    
  • Reload the zone and inspect the log-files. Query the SOA record of the zone and inspect the new SOA serial number value. It should be higher than the number written in the zone file (Why?)
    % rndc reload zNN.dane.onl
    $ dig @::1 zNN.dane.onl SOA +multi +dnssec
    $ dig @::1 zNN.dane.onl TXT +multi +dnssec
    

4.6 Hands-On: DNSSEC Chain of Trust

  • To close the chain of trust, the hash of the Key-Signing-Keys (KSK) of our zone zNN.dane.onl must be published as the DS-Record in the parent zone dane.onl
  • Create the DS-Record from the KSK file (Caution: be sure to use the correct key file from the KSK, not the ZSK!!)
    % dnssec-dsfromkey -2 /etc/bind/keys/KzNN.dane.onl.+008+NNNNN.key
    
  • Copy the output of the command into a file and copy the file to the trainers machine, so that the trainer can copy the data and publish the DS record in the parent zone (use the password dnssec-2022 for the destination machine)
    % dnssec-dsfromkey -2 /etc/bind/keys/KzNN.dane.onl.+008+NNNNN.key > ds-NN
    % scp ds-NN user@dnsr.z01.dane.onl:.
    
  • Once the DS record is published, test the zone from your DNS resolver machine (or using a public DNS resolver) and verify that the AD-Flag (Authentic Data) is signaling successful DNSSEC validation
    resolver% dig @::1 zNN.dane.onl soa +dnssec +multi
    resolver% dig @1.1.1.1 zNN.dane.onl soa +dnssec +multi
    

5 SPF

5.1 Basic SPF config

  • We work on the authoritative machine dns.zNN.dane.onl
  • Query the IPv4 address of the DNS resolver/Mailserver machine
    $ dig mail.zNN.dane.onl A
    
  • Open the file /etc/bind/zonefile.db and enter an SPF TXT record for the IPv4 address of the lab mail server
    zNN.dane.onl.    60 IN TXT "v=spf1  ip4:<ip-of-mail-server> ~all"
    
  • Increment the SOA serial number (required for BIND 9 to pick up the new zone data for inline signing)
  • Check the configuration and reload the zone, test the TXT record
    % named-checkconf -z
    % rndc reload
    % dig @1.1.1.1 txt zNN.dane.onl
    
  • Login to the mail-server (which is also our DNS resolver)
  • Send an e-mail using the swaks tool from the mail server (mail.zNN.dane.onl)
    $ swaks -t switch-training@sys4.de -s 127.0.0.1 -f user@zNN.dane.onl
    

5.2 Border Filter

  • Add the following IP-Adresses to your SPF policy: 2001:db8::/128 and 192.0.2.1/32
    zNN.dane.onl.    60 IN TXT "v=spf1  ip4:<ip-of-mail-server> ip4:192.0.2.1 ip6:2001:db8:: ~all"
    

5.3 Email Service Provider / Subdomain

  • Include the SPF-Policy from _spf.sys4.de to your border filter policy
    zNN.dane.onl.    60 IN TXT ( "v=spf1 ip4:<ip-of-mail-server> ip4:192.0.2.1"
                                 "ip6:2001:db8:: include:_spf.sys4.de ~all" )
    

5.4 Delegation

  • Example of a SPF policy delegation
    zNN.dane.onl.    60 IN TXT "v=spf1 redirect:_spf.sys4.de ~all"
    

6 DKIM

  • Work on the mail server (mail.zNN.dane.onl)
  • Generate DKIM keys with the RSA-SHA256 algorithm
    rspamadm dkim_keygen -s '223012-rsa' -b 2048 \
             -d zNN.dane.onl \
             -k /etc/rspamd/dkim/zNN.dane.onl-rsa.private \
             > zNN.dane.onl-rsa.txt
    
  • Generate DKIM keys with the ed25519 algorithm
    rspamadm dkim_keygen -s '223012-ed25519' -t ed25519 \
             -d zNN.dane.onl \
             -k /etc/rspamd/dkim/zNN.dane.onl-ed25519.private \
             > zNN.dane.onl-ed25519.txt
    
  • Make sure that the rspamd process is able to read the generated private keys
  • Adjust the Domain-Names used in the file /etc/rspamd/local.d/dkim_signing.conf to use your domain name.
    domain {  
     zNN.dane.onl {  
       selectors [  
         {  
           path: "/etc/rspamd/dkim/zNN.dane.onl-rsa.private";  
           selector: "223012-rsa";  
         },  
         {  
           path: "/etc/rspamd/dkim/zNN.dane.onl-ed25519.private";  
           selector: "223012-ed25519";  
         },  
       ]  
     }  
    } 
    
  • Verify the RSpamd configuration file and restart the RSpamd service
    % rspamadm configtest
    syntax OK
    % systemctl restart rspamd
    
  • The DNS DKIM public key records can now be found in the files zNN.dane.onl-rsa.txt and zNN.dane.onl-ed25519.txt
  • Copy the DKIM TXT records info the zonefile.db file on the authoritative DNS server (dns.zNN.dane.onl)
  • Increment the SOA serial number of the zonefile, save the file, check the configuration and the zonefile with name-checkconf -z and reload the zone. Query the new TXT records from a public DNS resolver to make sure the DKIM public keys are visible from the Internet DNS
    dig @9.9.9.9 223012-rsa._domainkey.zNN.dane.onl. TXT +dnssec +multi
    
  • Send an e-mail using the swaks tool from the mail server (mail.zNN.dane.onl)
    $ swaks -t switch-training@sys4.de -s 127.0.0.1 -f user@zNN.dane.onl \
            --header 'From: Tessi Testinger <user@z29.dane.onl>'
    
  • The trainer will check the DKIM signature authentication results on the sys4 mail server

7 DMARC

  • Work on the authoritative DNS server (dns.zNN.dane.onl)
  • Add a none DMARC policy to your domain, reports should be send dmarc@zNN.dane.onl
    _dmarc.zNN.dane.onl.  60 IN TXT "v=DMARC1\; p=none\; rua=mailto:dmarc@zNN.dane.onl\;"
    
  • Send an e-mail using the swaks tool from the mail server (mail.zNN.dane.onl)
    $ swaks -t switch-training@sys4.de -s 127.0.0.1 -f user@zNN.dane.onl \
            --header 'From: Tessi Testinger <user@z29.dane.onl>'
    
  • The trainer will check the DMARC results on the sys4 mail server