DNSSEC-validatie met de PowerDNS Recursor

PowerDNS is een Nederlands bedrijf (tegenwoordig onderdeel van Open-Exchange) dat over de afgelopen 20 jaar drie softwarepakketten voor DNS ontwikkelde: * PowerDNS Authoritative Server * PowerDNS Recursor * dnsdist (een load balancer)

De software is geschreven in C++, en is schaalbaar en snel. De code draait op alle Unix-achtigen en de laatste versies zijn in ieder geval als kant-en-klaar package beschikbaar voor de meeste Linux- en BSD-distributies. Alle drie software-pakketten worden gepubliceerd als open-source software onder de GPLv2-licentie. Het bedrijf verdient zijn geld via advies, ondersteuning en maatwerk. Daarmee heb je als gebruiker alle voordelen van het klassieke business model voor open source: open software die je 'gratis' kunt gebruiken als je daar zelf de tijd en expertise voor hebt, een actieve community van gebruikers en ontwikkelaars, met een commercieel bedrijf als fallback. Alternatief is het PowerDNS Platform, een software suite gebaseerd op deze drie software-producten.

DNSSEC

De implementatie van DNSSEC betekende de grote doorbraak voor PowerDNS: vrijwel alle grote Internet Service Providers die hun domeinen in bulk ondertekenden, deden dat op basis van de PowerDNS Authoritative Server. Validatie van DNSSEC is pas vanaf versie 4.0 onderdeel van de Recursor. De ontwikkeling ervan is destijds door SIDN (financieel) ondersteund.

Interessante feature is de Lua engine ingebouwd in zowel de Authoritative Server als de Recursor. Lua is een snel te leren script-taal waarmee de interne datastructuren gemakkelijk toegankelijk worden gemaakt voor beheerders. Verderop meer over het gebruik hiervan.

In dit artikel beschrijven we de configuratie van de PowerDNS Recursor als validerende resolver op CentOS/RHEL. De PowerDNS Authoritative Server beschrijven we in een ander artikel.

Kant-en-klare packages

De laatste versie van de PowerDNS Recursor is 4.1.8. De versie van de PowerDNS Authoritative Server staat nog op 4.1.5, maar versie 4.2.0 is onderweg (op dit moment in alpha).

De PowerDNS software is als kant-en-klaar pakket beschikbaar voor download vanaf de repo site. Daar vind je packages voor de meest gebruikte Linux-distributies (Debian, Raspbian, Ubuntu, CentOS/RHEL en SLES).

Let op dat DNSSEC pas vanaf versie 4.0 door de PowerDNS Recursor ondersteund wordt. Bovendien was de eerste implementatie niet goed geslaagd — in een poging om een tolerante validator te schrijven — wat betekent dat je alleen versies vanaf 4.1 moet gebruiken.

Voor deze beschrijving hebben we gebruik gemaakt van PowerDNS Recursor versie 4.1.8 op CentOS 7.6. De documentatie voor de Recursor vind je hier.

Installatie

De installatie van de PowerDNS Recursor begint met de configuratie van de EPEL en PDNS 4.1 repositories en de installatie van het yum-plugin-priorities package:

  yum install epel-release yum-plugin-priorities &&
  curl -o /etc/yum.repos.d/powerdns-rec-41.repo https://repo.powerdns.com/repo-files/centos-rec-41.repo

Gevolgd door het pdns-recursor package zelf:

  yum install pdns-recursor

Hoewel de laatste versie (4.1.8) ook direct vanaf de EPEL repository voor CentOS/RHEL beschikbaar is, wordt hier de versie afkomstig van de powerdns-rec-41 repository gebruikt. Voor de laatste versies van Fedora (28, 29, 30, waarvan die laatste nog in ontwikkeling) wordt Recursor versie 4.1.8 (via de updates) met de distributie meegeleverd.

Configuratie

De makers van de PowerDNS software hebben als uitgangspunt om zo veel mogelijk van de complexiteit voor hun gebruikers (beheerders) te verbergen en te automatiseren. Het is dan ook geen verrassing dat de configuratie in het bestand '/etc/pdns-recursor/recursor.conf' aanzienlijk beperkter en daardoor "makkelijker" is dan die van Unbound. Bovendien beperken de instellingen in deze file zich tot wat we maar even typische server-aangelegenheden noemen: daemon/process, access, logging, stats, caching en het netwerk. DNSSEC/protocol-specifieke instellingen zien we in deze file maar nauwelijks. Dat maakt dat de configuratie voor een recht-toe-recht-aan resolver ook door een systeem/netwerkbeheerder zonder bijzondere kennis van DNSSEC gelijk gedaan kan worden.

Uitgaande van de default-configuratie die met RHEL meegeleverd wordt (waarin alleen setuid/setgid ingesteld staan) hoef je de recursor alleen maar open te zetten voor (recursieve) queries van andere adressen dan localhost, bijvoorbeeld als volgt:

  local-address=192.0.2.5, 2001:db8::2:5
  allow-from=192.0.2.0/24, 2001:db8::/64

DNSSEC

Specifiek voor DNSSEC zijn er twee instellingen. De eerste, 'dnssec', zet validatie door de Recursor aan of uit, waarbij vijf opeenvolgende niveau's worden onderscheiden:

dnssec opties
off uitgeschakeld: DO/AD-vlaggen in queries worden genegeerd; de DO-vlag in eigen (recursieve) queries wordt nooit gezet
process-no-validate (default) de DO-vlag wordt gezet in de eigen uitgaande queries, maar er wordt geen validatie gedaan op de binnenkomende DNSSEC records
process alleen validatie als de client daarom vraagt via de DO/AD-vlag
log-fail validatie wordt altijd gedaan (en gelogd!), ook als een client daar niet om vraagt; op die manier kun je inzicht verkrijgen in het aandeel validerende domeinnamen (een gezette AD-vlag) en de SERVFAIL-antwoorden voordat je je clients bij de resolver laat vragen om validatie
validate validatie wordt altijd gedaan, en het resultaat is altijd een SERVFAIL als een domeinnaam niet goed valideert; een client krijgt alleen een AD-vlag terug als hij daar om gevraagd heeft; zo kun je (op server-niveau) clients beschermen die alleen een stub resolver aan boord hebben of DNSSEC op geen enkele manier ondersteunen

Default-instelling

Bij de default-optie 'dnssec=process-no-validate' voert de Recursor geen validatie uit, dus wordt ook de AD-vlag in het antwoord nooit gezet. Wel worden, als de client daarom vraagt middels de DO-vlag, de DNSSEC-specifieke record types (RRSIG, DNSKEY, DS) met het antwoord meegeleverd. De Recursor vraagt in dit geval dus zelf ook steeds (recursief) om de betreffende record types, zodat die informatie in de cache kan worden opgenomen.

Deze instelling is aan te raden als je je eindgebruikers zelf de DNSSEC-validatie laat uitvoeren. Zo ben je voor het transport van de AD-vlag niet afhankelijk van de veiligheid van de Last Mile. In dit hands-on artikel beschrijven we hoe je de validerende Unbound resolver (in combinatie met DNSSEC-Trigger) configureert op de PC van een eindgebruiker.

Clients met alleen een stub resolver doen zelf nooit validatie. Daarvoor is deze optie alleen veilig als het traject tussen resolver en client over een intern/gesloten netwerk loopt.

Bogus domeinnamen

De tweede DNSSEC-specifieke optie in de '/etc/pdns-recursor/recursor.conf' file is 'dnssec-log-bogus'. Deze geeft de mogelijkheid om alle bogus domeinnamen die de Recursor tegenkomt te loggen, ook als de eerste optie 'dnssec' niet op 'process', 'log-fail' of 'validate' ingesteld staat.

Dit was met name van belang jaren geleden toen er veel bogus domeinen waren doordat DNSKEY enerzijds en sleutelmateriaal geregistreerd bij het bovenliggende domein (in het DS record) anderzijds niet overeenkwamen. Inmiddels is dat geen enkel probleem meer.

Opstarten

Het beheer — en dus ook het opstarten — van de PowerDNS Recursor verloopt via systemd:

  [root@localhost ~]# systemctl status pdns-recursor.service
  ● pdns-recursor.service - PowerDNS Recursor
    Loaded: loaded (/usr/lib/systemd/system/pdns-recursor.service; disabled; vendor preset: disabled)
    Active: inactive (dead)
      Docs: man:pdns_recursor(1)
            man:rec_control(1)
            https://doc.powerdns.com
  [root@localhost ~]# systemctl enable pdns-recursor.service 
  Created symlink from /etc/systemd/system/multi-user.target.wants/pdns-recursor.service to /usr/lib/systemd/system/pdns-recursor.service.
  [root@localhost ~]# systemctl start pdns-recursor.service
  [root@localhost ~]# systemctl status pdns-recursor.service 
  ● pdns-recursor.service - PowerDNS Recursor
    Loaded: loaded (/usr/lib/systemd/system/pdns-recursor.service; enabled; vendor preset: disabled)
    Active: active (running) since Wed 2019-01-02 18:17:03 CET; 12s ago
      Docs: man:pdns_recursor(1)
            man:rec_control(1)
            https://doc.powerdns.com
    Main PID: 26998 (pdns_recursor)
      Tasks: 5
      CGroup: /system.slice/pdns-recursor.service
              └─26998 /usr/sbin/pdns_recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no

  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Listening for TCP queries on 127.0.0.1:53
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Set effective group id to 981
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Set effective user id to 987
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Launching 3 threads
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Done priming cache with root hints
  Jan 02 18:17:03 localhost.localdomain systemd[1]: Started PowerDNS Recursor.
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Done priming cache with root hints
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Done priming cache with root hints
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Done priming cache with root hints
  Jan 02 18:17:03 localhost.localdomain pdns_recursor[26998]: Enabled 'epoll' multiplexer

Trust anchors

De PowerDNS Recursor heeft niet de mogelijkheid om zelf (dynamische) trust anchors op te slaan. De software heeft in eerste instantie alleen de hard ingecodeerde trust anchors ter beschikking. De Recursor ondersteunt dus ook niet RFC 5011, een protocol om nieuwe trust anchors automatisch van de root servers binnen te halen en te installeren.

Dat betekent dat nieuwe trust anchors met de hand moeten worden toegevoegd, als de maintainer van de distributie dat nog niet voor je heeft gedaan. Omdat de DNSSEC-implementatie van PowerDNS Recursor voor versies ouder dan 4.1.0 sowieso niet meer gebruikt moet worden, geven we hier alleen de informatie voor de meest recente releases.

Vanaf versie 4.0.5 is het nieuwe trust anchor voor KSK-2017 aan de software toegevoegd. Je kunt dat verifiëren met behulp van deze opdracht:

  [root@localhost ~]# rec_control get-tas
  Configured Trust Anchors:
  .
      19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5
      20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d

We zien hier dat er inderdaad twee trust anchors zijn geïnstalleerd: met respectievelijk keyid 19036 (KSK-2010) en 20326 (KSK-2017). Dat komt omdat het proces voor de root KSK roll-over strikt genomen nog niet helemaal is afgerond. In de volgende stap (gepland voor het eerste kwartaal van 2019) zal het oude trust anchor voor KSK-2010 nog van de resolvers verwijderd moeten worden. Pas daarna is de roll-over voor systeembeheerders helemaal achter de rug.

Meer trust anchors

Moet je om een of andere reden toch nog (andere) trust anchors toevoegen, dan kan dat on-the-fly met behulp van dit commando:

  rec_control add-ta . 20326 8 2 \
      E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D

Maar om te zorgen dat dit trust anchor ook na een herstart weer beschikbaar is, moet je (ook) een 'addDS'-opdracht aan het Lua startup script van de Recursor toevoegen. Dat ziet er dan als volgt uit:

  addDS('.', "20326 8 2
      E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D")

We zien hier dat er in dit geval twee trust anchors zijn geïnstalleerd: met respectievelijk keyid 19036 (KSK-2010) en 20326 (KSK-2017). Dat komt omdat op moment van schrijven het proces voor de root KSK roll-over strikt genomen nog niet helemaal was afgerond. Inmiddels is de roll-over voor systeembeheerders helemaal achter de rug en moet het oude trust anchor voor KSK-2010 van de resolvers verwijderd zijn.

Negatieve trust anchors

Negatieve trust anchors gebruik je voor domeinen waarvoor je de DNSSEC-validatie (tijdelijk) wilt uitschakelen. Dat doe je bijvoorbeeld als een domein fouten bevat in de DNSSEC-configuratie en je gebruikers klagen dat het domein onbereikbaar is (want terecht geblokkeerd door de validerende resolver).

Om een uitzondering te maken voor het domein example.nl zou je bijvoorbeeld de volgende opdracht geven:

  [root@localhost ~]# rec_control add-nta example.nl 'resolving issues'
  Added Negative Trust Anchor for example.nl with reason 'resolving issues'

Een overzicht van de actieve negatieve trust anchors krijg je als volgt:

  [root@localhost ~]# rec_control get-ntas
  Configured Negative Trust Anchors:
  example.nl    resolving issues

En om deze weer te verwijderen geef je de volgende opdracht:

  [root@localhost ~]# rec_control clear-nta example.nl
  Removed Negative Trust Anchors for example.nl

Om dit negatieve trust anchor permanent aan de configuratie toe te voegen, zou je het volgende Lua-commando gebruiken:

  addNTA('example.nl', "resolving issues")

Lua engine

Lua is een wat ongelukkig ontworpen taal, maar als embedded engine wel enorm handig om gebruikers een run-time scripting-ingang tot je software te geven. Voor ontwikkelaars is het namelijk heel makkelijk om snel nieuwe interfaces naar hun C-code toe te voegen.

De ingebouwde Lua-faciliteit (vanaf versie 4.0) maakt de PowerDNS Recursor in het bijzonder interessant als je dynamisch met je configuratie wilt spelen: je kunt scripts laden, vervangen en ontladen zonder de operatie van de resolver te onderbreken. Belangrijke beperking is wel dat maar 1 script tegelijk actief kan zijn: bij het laden van een nieuw script wordt de configuratie van het vorige, actieve script vervangen.

Laden (wisselen dus) en ontladen van een Lua-script doe je met deze twee commando's:

  rec_control reload-lua-script <script_file>
  rec_control unload-lua-script

Lua startup script

Naast dit Lua-script is er ook nog het helemaal op zichzelf staande Lua startup script dat bij het opstarten door de Recursor wordt geladen. Deze staat gespecificeerd in de configuratie-optie 'lua-config-file'. Een goede locatie voor deze file is '/etc/recursor-conf.lua'. Er is geen default, dus als deze file niet is gedefinieerd, dan wordt helemaal geen Lua-configuratie geladen.

Belangrijk onderscheid is dat het Lua startup script maar eenmalig wordt ingelezen, terwijl het boven beschreven run-time Lua-script voor elke query opnieuw wordt uitgevoerd bij het beantwoorden daarvan.

Voor het opnieuw inlezen van het Lua startup script is dit commando beschikbaar:

  rec_control reload-lua-config

Lua-faciliteiten

In de Lua-interface van de Recursor is het hele DNSQuestion object met al zijn velden beschikbaar gemaakt. Hetzelfde geldt voor de DNSHeader en de EDNSOptionView. Je kunt domeinnamen, IP-adressen en netmasks aanmaken, om die vervolgens te bevragen en te bewerken.

Daarnaast zijn er functies voor het opvragen van statistieken en het wegschrijven van log-berichten. En er is de mogelijkheid om hooks te installeren op diverse plaatsen in het proces van query naar response.

Een paar specifieke functies die we hier nog willen noemen:

  • addSortList: vergelijkbaar met het sortlist statement van BIND named, voor het sorteren van de records in een RRset-antwoord, bijvoorbeeld als 'load balancing'-strategie op A/AAA records

  • uitgebreide logging via Protocol Buffers over een TCP-verbinding

  • ondersteuning voor het RPZ-protocol (Response Policy Zone) om voor specifieke domeinnamen andere antwoorden te retourneren, typisch om domeinen die bekend staan als kwaadaardig geautomatiseerd te omzeilen

Voor wie liever met een JSON/REST API werkt is er de mogelijkheid om een webserver op te starten als onderdeel van de Recursor.

DNSSEC-specifiek

In onderstaande tabel geven we tenslotte nog een overzicht van de 'rec_control'- en Lua-opdrachten specifiek relevant voor DNSSEC.

rec_control Lua
add-ta addTA toevoegen trust anchor
clear-ta clearTA verwijderen trust anchor
get-tas overzicht huidige trust anchors
add-nta addDS/addNTA toevoegen negatief trust anchor
clear-nta clearDS/clearNTA verwijderen negatief trust anchor
get-ntas overzicht huidige negatieve trust anchors
reload-lua-config laad het Lua startup script opnieuw
reload-lua-script laad het Lua run-time script opnieuw
unload-lua-script ontlaad het Lua run-time script

Vanaf versie 4.2 zijn de Lua commando's addDS en clearDS vervangen door respectievelijk addNTA en clearNTA. Met deze versie is bovendien een heel nieuw commando geïntroduceerd: readTrustAnchorsFromFile, waarmee je DNSKEY/DS records uit een bestand (in Bind 'zone file'-formaat) kunt inlezen.

Afsluitend

De PowerDNS Recursor is een toegankelijke resolver die door een systeem/netwerkbeheerder direct geconfigureerd kan worden zonder bijzondere kennis van DNSSEC. Het belangrijkste onderscheid met de Unbound resolver is dan ook dat de instellingen in het configuratiebestand zich beperken tot bekende server-aangelegenheden — waar de configuratie van Unbound bestaat uit één lange lijst van opties voor server- alsook DNSSEC/protocol-specifieke zaken. Wil je meer van de PowerDNS Recursor, dan kan dat door het inladen van aparte startup/run-time programma's voor de ingebouwde Lua engine.

De out-of-the-box configuratie op CentOS die wij voor dit artikel bekeken was — net als de default-configuratie van Unbound overigens — direct te gebruiken na het aanpassen van de listen-poorten.