Hands-on: OpenDNSSEC automatiseert hele DNSSEC -proces

Installatie vraagt wel goed begrip van de onderliggende technologie

Hoewel de ondersteuning van DNSSEC in DNS -server-software steeds beter wordt, is deze nog nergens compleet. De publicatie van een eenmaal ondertekende zone lukt inmiddels prima, maar het up-to-date houden van die informatie vraagt nog steeds om handwerk of het schrijven van scripts. BIND — de meest gebruikte DNS-server — en PowerDNS — met name populair hier in Nederland — doen het wat dat betreft beter dan andere veelgebruikte pakketten, zoals NSD, Knot en Yadifa. De laatste versies van BIND bieden inmiddels configuratie-opties om het hertekenen van de zone te automatiseren als veranderingen in de zone file of de sleutels dat nodig maken.

Waar het echt nog aan schort is sleutelbeheer. Met behulp van scripts kun je met BIND of PowerDNS als basis zonder al te veel knutselwerk een heel eind komen, ook in bedrijfsmatige omgevingen. Maar wie bekend is met RFC 6781 ("DNSSEC Operational Practices, Version 2") weet dat hier nog wel wat haken en ogen aan kunnen zitten.

OpenDNSSEC neemt het complete sleutelbeheer uit handen en automatiseert alles rondom de sleutels en het ondertekenen van de zones. Het open-source pakket kan via de zone files of via zone transfers makkelijk geïntegreerd worden met BIND, PowerDNS en andere DNS-servers. Wel vraagt de installatie een goed begrip van de werking van DNSSEC, public key cryptografie, vertrouwensketens, sleutelbeheer, en alle timing-aspecten en bijbehorende afhankelijkheden rond DNS en DNSSEC. Daarmee wordt gelijk duidelijk dat DNS met DNSSEC niet langer een administratieve aangelegenheid is maar een complexe, cryptografisch beveiligde infrastructuur. Hoewel de configuratie van OpenDNSSEC wel wat tijd en aandacht kost, raden we dit pakket van harte aan als complementaire oplossing naast de DNS-server. De ervaring heeft inmiddels geleerd dat de beste manier om met de complexiteit van DNSSEC om te gaan een zo groot mogelijke automatisering is.

In dit artikel bespreken we de complete installatie van OpenDNSSEC en de integratie met de DNS-servers, zowel via de zone files als via zone transfers. Hoewel de defaults al een goed vertrekpunt bieden en maar weinig aanpassingen vragen, is wel een goed begrip van DNSSEC nodig. Vandaar dat we naast alle hands-on informatie ook veel aandacht besteden aan de uitleg eromheen.

We schreven eerder al een hands-on verhaal over BIND en de ondersteuning voor DNSSEC. Het publiceren van de digitale handtekeningen (de RRSIG records) is niet zo ingewikkeld; voor BIND is dat in de kern immers niet anders dan het publiceren van een niet-ondertekende zone file. Vanaf versie 9.7 is de ondersteuning voor het automatisch ondertekenen en ondertekend houden van de zones bovendien steeds beter geworden.

Waar het echter aan schort is goed geautomatiseerd sleutelbeheer. Voor een handvol domeinen kun je je nog behelpen met een huisgemaakt script. Maar gaat het om een grotere of bedrijfskritieke installatie, dan kom je al gauw uit bij OpenDNSSEC. Voor dergelijke omgevingen is het verstandiger om de beheersopties voor DNSSEC in de named configuratie helemaal uit te schakelen en over te stappen naar een complementaire oplossing voor ondertekening en sleutelbeheer.

OpenDNSSEC

OpenDNSSEC is een open-source tool om de ondertekening van domeinnamen te verzorgen. Kortgezegd neemt het een zone als input en levert het een ondertekende zone als output. Dat wil zeggen dat de handtekeningen voor de record sets (RRSET's) aan de zone zijn toegevoegd — de RRSIG en NSEC3 records — alsook de records met het bijbehorende sleutelmateriaal — de DNSKEY records.

Daarbij neemt OpenDNSSEC ook de key roll-overs voor zijn rekening: het sleutelmateriaal wordt automatisch gegenereerd, gepubliceerd en weer verwijderd. Het enige handwerk dat overblijft is het uploaden van nieuwe DS records voor opname in de zone van het bovenliggende domein.

De cryptografische sleutels zelf worden gegenereerd, ondertekend en bewaard in een HSM (Hardware Security Module) die via een PKCS #11 interface (API) wordt aangesproken.

Bump-in-the-wire

Voor zowel de input als de output zijn twee verschillende adapters beschikbaar. Daarmee kan OpenDNSSEC makkelijk in een bestaande DNS-publicatieketen ingehaakt worden. Hoewel je ook de bestaande zone files kunt inlezen en weer wegschrijven, maakt een typische configuratie gebruik van het AXFR/IXFR overdrachtsprotocol voor DNS zone transfers. Op die manier kun je de onversleutelde zones beheren op een verborgen master server. Deze worden vervolgens ondertekend op een tweede verborgen master die als slave fungeert van die eerste master server. Vanuit de tweede master worden de ondertekende zones vervolgens verspreid naar de publieke DNS-servers die in deze constellatie dus als slave van de tweede master staan ingesteld.

Deze drietraps-opzet wordt bijvoorbeeld gebruikt bij de Rijksuniversiteit Groningen, bij de Universiteit Twente en bij SURFnet.

SURFnet DNS infrastructuur

In dit artikel laten we zien hoe je een dergelijke bump-in-the-wire constellatie configureert. Daarbij maken we gebruik van SoftHSM, zoals de naam al aangeeft een software-matige implementatie van een HSM. Op de site van OpenDNSSEC staat een lijst van geteste HSM-producten en een HSM Buyers' Guide.

Van de op deze site beschreven cases maakt echter alleen SURFnet gebruik van (twee) hardware-matige HSM's, net als SIDN zelf overigens. Deze specifieke systemen kosten al gauw vele tienduizenden euro's. De meeste gebruikers gaan dan ook met SoftHSM aan de slag. Voor grote installaties is het dan wel zaak te zorgen dat er voldoende entropie beschikbaar is voor het generen van de sleutelparen.

Installatie

De installatie van OpenDNSSEC op RHEL/CentOS versie 6 is recht-toe-recht-aan: RPM-pakketten voor OpenDNSSEC en SoftHSM zijn beschikbaar via de EPEL repository. Deze maakt pakketten van Fedora Linux — de community/development distributie van Red Hat — beschikbaar voor RHEL en afgeleide distributies. Om EPEL op RHEL/CentOS 6 te installeren:

wget http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum install ./epel-release-6-8.noarch.rpm

Na het aankoppelen van EPEL kunnen OpenDNSSEC en SoftHSM direct geïnstalleerd worden:

yum install opendnssec softhsm

Voorgebakken RPM packages van OpenDNSSEC en SoftHSM voor RHEL/CentOS versie 7 zijn op moment van schrijven niet beschikbaar. Maintainer Paul Wouters werkt op dit moment aan de pakketten die een dezer dagen in de Core repository van RHEL/CentOS 7 terecht moeten komen. Probleem daarbij is dat SoftHSM versie 1 de botan crypto library (onder BSD-licentie) gebruikt. Eerst zullen de huidige pakketten in EPEL 6 naar SoftHSM versie 2 worden opgewaardeerd. Omdat die versie ook overweg kan met de OpenSSL library, maakt dat ook opname in de reguliere distributie mogelijk.

KLIK HIER voor extra informatie over de inzet van MySQL als back-end database.

Architectuur

Het belangrijkste onderdeel bij de configuratie van OpenDNSSEC is de Key And Signing Policy (KASP). Deze wordt door de Enforcer gebruikt om het sleutelbeheer uit voeren. De software bestaat uit de ods-enforcerd daemon en de bijbehorende tool ods-ksmutil.

De Signer is verantwoordelijk voor de ondertekening van de zones. De ods-signerd daemon neemt de zone files en de data van de Enforcer als input en genereert daaruit ondertekende zone files. De command line tool voor de Signer heet ods-signer.

Tenslotte zijn er de input en output Adapters die zorgen dat OpenDNSSEC naadloos in de keten voor beheer en publicatie van DNS zones kan worden opgenomen. Op dit moment is er ondersteuning voor AXFR, IXFR en zone files.

OpenDNSSEC architectuur

Configuratiebestanden

De configuratie van OpenDNSSEC wordt vastgelegd in een viertal XML-bestanden in de directory /etc/opendnssec/:

  • conf.xml: bevat de algemene configuratie (logging, locaties van directories en files, keystores, database en dergelijke)
  • kasp.xml: bevat de Key And Signing Policy, bestaat uit security en timing informatie:
    • policies voor de ondertekening van zone records en NSEC3
    • cryptografische parameters en sleutelmateriaal
    • additionele informatie voor de ondertekende zone files
  • addns.xml: bevat specifieke informatie voor de Adapters
  • zonelist.xml: bevat alle zones die je wilt laten ondertekenen, met daarbij een specificatie van bijbehorende policies en Adapters

Daarnaast worden er allerlei administratieve en tijdelijke bestanden aangemaakt in de directory /var/opendnssec/. Maar als alles zonder problemen loopt, heb je hier ook als beheerder niets te zoeken. Voor de details verwijzen we naar de documentatie van OpenDNSSEC.

conf.xml: de keystore repositories

We beginnen onze configuratie met het bestand conf.xml. De meeste default instellingen kunnen we gewoon laten staan. Wel moeten we instellen waar de HSM's (keystore repositories) te vinden zijn. Voor gebruik van SoftHSM kunnen we de bestaande configuratie laten zoals die is:

<RepositoryList>
  <Repository name="SoftHSM">
    <Module>/usr/lib64/softhsm/libsofthsm.so</Module>
    <TokenLabel>OpenDNSSEC</TokenLabel>
    <PIN>************</PIN>
  </Repository>
</RepositoryList>

Verander wel de <PIN>. Hoewel de naam anders suggereert, hoeft deze niet alleen cijfers te bevatten, dus maak daar een goed paswoord van.

Als je de toegangscode voor de HSM liever niet in de configuratie zet, dan kun je die ook handmatig opgeven voordat je OpenDNSSEC opstart:

ods-hsmutil login

Dat betekent wel dat OpenDNSSEC niet automatisch aan het werk kan na een reboot.

Uitgecommentarieerd daaronder staat een configuratie voor een hardware-matige HSM. Daar kun je ook de extra opties zien:

  • <Capacity>1000</Capacity>:
    het maximum aantal sleutels dat de HSM kan opslaan
  • <RequireBackup/>:
    deze optie voorkomt dat er sleutelparen in gebruik genomen worden waarvan nog geen backup is gemaakt; de beheerder moet dat dan met deze twee commando's eerst zelf aankondigen en na de feitelijke backup bevestigen:
    ods-ksmutil backup prepare
    ods-ksmutil backup commit
    
  • <SkipPublicKey/>: sla niet de publieke maar alleen de private sleutels op in de HSM, zodat je meer "sleutelparen" kwijt kunt op het device;
    wil je OpenDNSSEC in combinatie met BIND inzetten, dan kun je deze optie niet gebruiken;
    in combinatie met SoftHSM heeft deze optie sowieso geen zin, want die slaat de keystore repositories gewoon op disk op

De <Common> sectie bevat alleen logging-informatie en de locatie van de configuratiebestanden. Eventueel kun je daar ook een <ZoneFetchFile> instellen als alternatief voor de <ZoneListFile>. Deze optie gebruik je om zones automatisch via AXFR binnen te laten komen naar aanleiding van NOTIFY-berichten.

conf.xml: MySQL back-end

Als je een nieuwe versie van OpenDNSSEC hebt gecompileerd voor gebruik met MySQL, dan moet de bijbehorende toegangsinformatie worden gespecificeerd in het <Enforcer> gedeelte:

<!-- <Datastore><SQLite>/var/opendnssec/kasp.db</SQLite></Datastore> -->
<Datastore>
  <MySQL>
    <Host port="3306">localhost</Host>
    <Database>odnskasp</Database>
    <Username>odnskasp</Username>
    <Password>************</Password>
  </MySQL>
</Datastore>

Dit is gelijk een goede gelegenheid om die database in MySQL aan te maken:

[root ~]# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor. Commands end with ; or g.
Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
mysql> CREATE DATABASE odnskasp;
Query OK, 1 row affected (0.00 sec)
mysql> GRANT ALL PRIVILEGES ON odnskasp.* TO "odnskasp"@"localhost" IDENTIFIED BY "************";
Query OK, 0 rows affected (0.03 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.04 sec)
mysql> EXIT;
Bye
[root ~]#

Het laden van een database-definitie is niet nodig; dat gebeurt later als impliciet onderdeel van de 'ods-ksmutil setup' opdracht.

conf.xml: de Enforcer

Het <Interval> bepaalt hoe vaak de Enforcer checkt of sleutelparen al gerold moeten worden. Om te zorgen dat de timing van de roll-overs de geldigheidsduur van de sleutelparen goed volgt, moet deze frequentie minstens een orde grootte hoger liggen dan de geldigheidsduur. Vergelijk het maar met de frequentie van een cron job.

Stel je de geldigheidsduur van je ZSK-sleutelparen op weken of maanden in, dan kun je bijvoorbeeld een keer per dag laten checken of er iets moet gebeuren:

<Interval>P1D</Interval>

Wil je je sleutels vaker rollen, dan doe je deze check bijvoorbeeld elk uur:

<Interval>PT3600S</Interval>

Het interval zelf wordt gespecificeerd volgens de ISO 8601 standaard.

Extra opties:

  • <ManualKeyGeneration/>:
    hiermee geef je aan dat de benodigde sleutelparen niet automatisch maar handmatig gegenereerd moeten worden;
    je gebruikt daarvoor het commando 'ods-ksmutil key generate';
    er zijn vergelijkbare commando's voor het rollen, uit dienst nemen en verwijderen van sleutelparen
  • <RolloverNotification>:
    bij gebruik van <ManualKeyGeneration/> specificeert deze optie hoe lang tevoren je alerts (in de logs) krijgt voordat een actief KSK-sleutelpaar verloopt;
    zorg dat je voor jezelf voldoende ruimte voor sleutelbeheer maakt;
    als de geldigheidsduur van je KSK-sleutelparen een of meerdere jaren is, dan is het helemaal niet gek om een of twee maanden tevoren je roll-over in gang te zetten:
    <RolloverNotification>P30D</RolloverNotification>
    

Hoewel je met <ManualKeyGeneration/> de Enforcer bijvoorbeeld met behulp van cron heel nauwkeurig kunt besturen, raden wij aan om deze en andere handmatige opties niet te gebruiken zonder hele goede redenen. OpenDNSSEC biedt alle faciliteiten om sleutelbeheer zo veel mogelijk te automatiseren; zelf doen is vragen om fouten en vergissingen.

  • <DelegationSignerSubmitCommand>:
    hiermee specificeer je een script dat bij veranderingen in het te publiceren sleutelmateriaal aangeroepen wordt;
    het programma krijgt via stdin de DNSKEY records toegestopt en kan dus gebruikt worden om de publicatie van de DS records bij de registry te automatiseren

De eppclient die met eerdere versies van OpenDNSSEC werd meegeleverd wordt echter niet meer ondersteund. Wel wordt met de source code een handig mail scriptje meegeleverd. Dat stuurt een bericht als de beheerder zijn sleutelmateriaal bij de registry moet aanpassen. Deze set-up wordt bijvoorbeeld door de Rijksuniversiteit Groningen gebruikt.

cp .../opendnssec-1.4.6/plugins/simple-dnskey-mailer/simple-dnskey-mailer.sh /etc/opendnssec/
edit /etc/opendnssec/simple-dnskey-mailer.sh
  RECIPIENT=hostmaster@example.nl
chown root:ods /etc/opendnssec/simple-dnskey-mailer.sh
chmod 750 /etc/opendnssec/simple-dnskey-mailer.sh

Als de DS records inderdaad door de registry in de TLD zone gepubliceerd zijn, moet je Enforcer laten weten dat het volgende fase van het roll-over process ingegaan kan worden:

ods-ksmutil key ds-seen --zone example.nl --keytag 12345

Je kunt ook nog de optie --cka_id aan de opdracht in <DelegationSignerSubmitCommand> toevoegen, een signaal aan de Enforcer om ook de (interne) cka-id aan het script mee te geven. Waar keytags niet noodzakelijk uniek zijn en een (kleine) mogelijkheid op een botsing geven, is die kans voor cka-id's (hashes) verwaarloosbaar.

<DelegationSignerSubmitCommand>/etc/opendnssec/simple-dnskey-mailer.sh --cka_id</DelegationSignerSubmitCommand>

Let op dat deze optie nogal ongelukkig geïmplementeerd is: het lijkt alsof deze wordt meegegeven aan het script, maar dat is niet het geval: de optie is echt alleen bedoeld voor de Enforcer en wordt verwijderd voordat het script wordt aangeroepen.

Nu kun je de cka-id gebruiken om Enforcer een signaal te geven:

ods-ksmutil key ds-seen --zone example.nl --cka_id a6f66e07871469fd81ec6908fb221b68

conf.xml: de Signer

Tenslotte is er nog de <Signer> sectie waarin de privileges, threads, poorten en interfaces voor de listener zijn gedefinieerd. Voor een zelfstandige bump-in-the-wire set-up tussen twee DNS-servers moet de <Listener> geactiveerd worden:

<Listener></Listener>

Zonder verdere specificaties luistert deze naar queries, notificaties en zone transfer requests op port 53 voor zowel IPv4 als IPv6. Daarmee staat er dus een volledige master DNS-server klaar om ondertekende zones op te hoesten.

Om een lokale server een seintje te geven als er een nieuwe (ondertekende) versie van een zone is, kan het <NotifyCommand> een reload voor die zone initiëren. Voor BIND named zou dat er als volgt uitzien:

<NotifyCommand>/usr/sbin/rndc reload %zone</NotifyCommand>

Controleer tevoren of dit commando inderdaad op die locatie aanwezig is:

[root ~]# which rndc
/usr/sbin/rndc
[root ~]#

Let op dat deze rndc-opdracht niet werkt in combinatie met "views". Dan moet namelijk voor elke view afzonderlijk een reload commando worden gegeven. Het makkelijkst is om daarvoor een apart scriptje /etc/opendnssec/notify-rndc aan te maken:

#!/bin/bash
if [[ $# -ne 1 ]]; then
  echo "Usage: $0 zone" >&2
  exit 1;
else
  /usr/sbin/rndc reload $1 IN localhost_resolver
  /usr/sbin/rndc reload $1 IN internal
  /usr/sbin/rndc reload $1 IN external;
fi

te zorgen dat deze door de gebruiker ods uitgevoerd kan worden:

chown root:ods /etc/opendnssec/notify-rndc
chmod 750 /etc/opendnssec/notify-rndc

en deze door de Signer te laten aanroepen voor de reload van een zone:

<NotifyCommand>/etc/opendnssec/notify-rndc %zone</NotifyCommand>

KLIK HIER voor extra informatie over de configuratie van rndc.

Voor andere DNS-servers dan BIND moet het commando aangepast worden. Eventueel is ook nog de parameter %zonefile beschikbaar. Die geeft het volledige pad naar de nieuw ondertekende zone file.

kasp.xml: ondertekening van de record sets

Het configuratiebestand kasp.xml bevat de policies voor het ondertekenen van de zones. Deze bestaat in eerste instantie alleen uit de default Policy. Heb je geen specifieke eisen voor verschillende domeinen, dan is deze Policy in principe genoeg.

De inhoud van een Policy bestaat vooral uit de specificatie van alle timing-instellingen. Om te beginnen die voor de handtekeningen (de RRSIG records):

<Signatures>
  <Resign>PT2H</Resign>
  <Refresh>P3D</Refresh>
  <Validity>
    <Default>P7D</Default>
    <Denial>P7D</Denial>
  </Validity>
  <Jitter>PT12H</Jitter>
  <InceptionOffset>PT7200S</InceptionOffset>
</Signatures>

Hier kunnen we lezen dat de Signer elke twee uur wordt opgestart (vergelijk cron). Drie dagen voor het verlopen van de handtekeningen worden de DNS records opnieuw ondertekend. De geldigheidsduur van die handtekeningen is een week. Hetzelfde geldt voor de tussenliggende NSEC3 records. Zo wordt voorkomen dat oude handtekeningen nog lang na veranderingen in de record set misbruikt zouden kunnen worden voor een DNS-replay-aanval.

Zorg dat de frequentie van de <Resign> minstens een orde grootte sneller is dan die van de <Refresh>, zodat de timing van de policies goed gevolgd wordt.

OpenDNSSEC: Reuse of signatures

<Jitter> zorgt voor een random interval (±random*j) rond de verlooptijd van een handtekening, zodat niet alle zone-informatie steeds tegelijkertijd opnieuw ondertekend wordt. Zorg dus dat deze minstens een orde grootte kleiner is dan de geldigheidsduur van een handtekening. Op deze manier gaat het ondertekenen van de record sets vanzelf steeds meer verlopen.

De impact van het ondertekenen kun je ook verkleinen door de <Resign> periode te verkleinen. Op die manier wordt die werklast verdeeld over kleinere batches die vaker worden uitgevoerd.

<InceptionOffset> haalt de starttijd van de handtekeningen met twee uur naar voren. Op die manier worden tijdsverschillen met de ondertekenende machine en door zomertijd opgevangen.

OpenDNSSEC: Signature lifetime

NSEC3 levert een ondertekend bewijs dat een bepaalde Domeinnaam niet bestaat in een zone:

<Denial>
  <NSEC3>
    <!-- <OptOut/> -->
    <Resalt>P100D</Resalt>
    <Hash>
      <Algorithm>1</Algorithm>
      <Iterations>5</Iterations>
      <Salt length="8"/>
    </Hash>
  </NSEC3>
</Denial>

Deze sectie geeft de gedetailleerde cryptografische instellingen voor het generen van de NSEC3 records. Zonder goede aanleiding hoef je hier niets aan te veranderen.

kasp.xml: de sleutelparen

<Keys>
  <!-- Parameters for both KSK and ZSK -->
  <TTL>PT3600S</TTL>
  <RetireSafety>PT3600S</RetireSafety>
  <PublishSafety>PT3600S</PublishSafety>
  <!-- <ShareKeys/> -->
  <Purge>P14D</Purge>

  <!-- Parameters for KSK only -->
  <KSK>
    <Algorithm length="2048">8</Algorithm>
    <Lifetime>P1Y</Lifetime>
    <Repository>SoftHSM</Repository>
  </KSK>

  <!-- Parameters for ZSK only -->
  <ZSK>
    <Algorithm length="1024">8</Algorithm>
    <Lifetime>P30D</Lifetime>
    <Repository>SoftHSM</Repository>
    <!-- <ManualRollover/> -->
  </ZSK>

</Keys>

De instellingen voor de sleutelparen beginnen met de TTL (Time-To-Live) voor de DNSKEY records: één uur. Gezien de lange geldigheidsduur van de sleutelparen — jaren voor KSK, maanden voor ZSK — en de refresh van een week voor de handtekeningen, kun je deze TTL beter in overeenstemming brengen met die van je gewone DNS records: bijvoorbeeld één dag:

<TTL>PT24H</TTL>

In het algemeen is het voor de meeste domeinen geen probleem om langere TTL's aan te houden; dat vermindert immers de load op de servers. Die trend naar veel kortere TTL's is een gevolg van grote online dienstverleners die het gebruiken voor load-distributie en van systeemleveranciers die zo de behoefte aan hardware willen vergroten. Maar als je maar weinig wijzigingen hebt op een zone, en die ook best een dagje kunnen doorlopen, dan is zo'n lage TTL voor de meeste domeinen niet nodig. Wel is het een goed idee om tijdens migratie-trajecten en de implementatie van nieuwe technologie — DNSSEC — de TTL's kort te houden, zodat veranderingen snel doorgevoerd worden. Bovendien voorkom je zo dat het nog een hele dag duurt om een fout die al op het internet gepropageerd is overal uit de caches te spoelen.

<RetireSafety> en <PublishSafety> breiden het publicatie-window van de DNSKEY aan beide kanten uit met een uur, om eventuele problemen (bijvoorbeeld met netwerkverbindingen en kleine tijdsafwijkingen van clients) op te vangen.

<ShareKeys/> kun je aanzetten als je de sleutelparen voor de domeinen onder deze policy wilt delen. Dat kun je bijvoorbeeld overwegen als je capaciteitsproblemen hebt in een hardware-matige HSM. Daarmee gaan wel belangrijke voordelen van de veelgebruikte orthogonale aanpak verloren: de opslitsing in KSK- en ZSK-sleutelparen maakt sleutelbeheer op lokaal niveau "onafhankelijk" van dat op registry-niveau, en het gebruik van aparte sleutelparen voor elk domein isoleert (veiligheids)problemen.

<Purge> tenslotte geeft de periode aan waarna verlopen sleutelparen uit de database worden verwijderd, hier dus ingesteld op twee weken.

Daarna volgen de instellingen voor de KSK- en ZSK-sleutelparen afzonderlijk. Voor KSK is een geldigheidsduur van een jaar en een sleutellengte van 2048 bits gespecificeerd, voor ZSK zijn dat respectievelijk een maand en 1024 bits.

Je zou deze perioden bijvoorbeeld ook kunnen verdubbelen naar respectievelijk twee jaar en twee maanden.

De sleutellengten zijn uiteraard afhankelijk van het gekozen cryptografische algoritme. Nummer 8 staat in dit geval voor RSASHA256: RSA public key cryptografie in combinatie met SHA2 hashing. Algoritme 10 zou een alternatief kunnen zijn; RSASHA512 biedt een sterkere cryptografische bescherming, maar het is daarvoor eigenlijk nog wat vroeg omdat deze extra verwerkingskracht vraagt op 32-bits systemen (mobiele devices).

KLIK HIER voor extra informatie over de verschillende cryptografische algoritmen.

De <Repository> hebben we aangepast naar de 'SoftHSM' die we eerder in de file conf.xml in de <RepositoryList> hadden gedefinieerd.

Tenslotte biedt de <ManualRollover/> optie nog de mogelijkheid om ook voor de ZSK-sleutelparen te wachten op bevestiging door de beheerder alvorens deze in gebruik te nemen. Daarmee wordt het gedrag voor ZSK precies hetzelfde als voor KSK. Bij die laatste moet echter altijd door de beheerder een signaal worden gegeven als het DS record door de bovengelegen registry is gepubliceerd. Voor ZSK-sleutelparen is er alleen in uitzonderingssituaties reden om die niet geautomatiseerd in gebruik te nemen.

kasp.xml: zones

<Zone>
  <PropagationDelay>PT43200S</PropagationDelay>
  <SOA>
    <TTL>PT24H</TTL>
    <Minimum>PT1200S</Minimum>
    <Serial>datecounter</Serial>
  </SOA>
</Zone>

Met de <PropagationDelay> geeft je aan hoe lang het duurt om aangepaste zone-informatie van de eerste, administratieve master server naar alle slave servers te transporteren en te publiceren. In dit geval staat die op 12 uur (43200 seconden). Dat lijkt op het eerste gezicht heel lang, maar komt goed overeen met een bump-in-the-wire opzet: Als op de eerste hidden master een record wordt aangepast, dan duurt het tot twee uur (<Signatures><Resign>) voordat deze worden ondertekend. Ervan uitgaande dat de Signer via <NotifyCommand> gelijk daarna een seintje geeft aan de tweede master, dan duurt het daarna nog tot 8 uur (de SOA refresh) voordat deze informatie ook op de slave servers gepubliceerd wordt. Dat is tezamen 10 uur, wat nog twee uur marge overlaat.

Tegenwoordig zal die SOA-refresh van 8 uur echter niet zo vaak meer voorkomen: De tweede master zal immers gelijk een NOTIFY naar de slaves sturen. En oude software die daarmee niet overweg kan, zal zeer waarschijnlijk ook geen DNSSEC ondersteunen.

De informatie in de <SOA> sectie vervangt de instellingen van het SOA record in de originele zone. <TTL> geeft de TTL specifiek voor het SOA record. De <Minimum> parameter specificeert de periode dat NXDOMAIN-antwoorden gecached moeten worden. En <Serial> geeft de methode voor de serienummering van de zones.

We hebben van die laatste 'datecounter' gemaakt, het traditionele 'YYYYMMDDxx'-formaat. Hoewel er nog meer opties zijn, willen we hier alleen 'keep' nog noemen. Daarbij blijft het serienummer van de originele zone na ondertekening behouden. Dat betekent dat je je zone files goed moet bijhouden en na een aanpassing inderdaad niet mag vergeten om het serienummer op te hogen. De 'datecounter'-optie biedt wat dat betreft een extra zekerheid.

kasp.xml: parents

In het laatste gedeelte van dit configuratiebestand specificeren we de informatie over de bovenliggende zone, van belang vanwege de publicatie van de DS records.

<Parent>
  <PropagationDelay>PT9999S</PropagationDelay>
  <DS>
    <TTL>PT7200S</TTL>
  </DS>
  <SOA>
    <TTL>PT7200S</TTL>
    <Minimum>PT900S</Minimum>
  </SOA>
</Parent>

<PropagationDelay> geeft de tijd tussen de publicatie van het KSK DNSKEY record in een vernieuwde zone en het verschijnen van het bijbehorende DS record in de bovenliggende zone. Zolang deze stap niet geautomatiseerd is, staat deze op een "maxwaarde" ingesteld. Nu wordt deze periode immers bepaald door de beheerder die een 'ods-ksmutil key ds-seen' commando moet geven voordat een KSK-sleutelpaar in gebruik kan worden genomen.

<DS><TTL> bevat de TTL voor het DS record. Voor de .nl zone is dat twee uur (7200s). Je kunt dat opzoeken door dit record op te vragen bij een autoritatieve nameserver:

[root ~]# dig @ns1.dns.nl. dnssec.nl. +noall +answer DS
dnssec.nl.  7200  IN  DS  7279 8 2 252F91202E729BFB9861C507C3459B8DD1E1900AC29C44F9F60648D6 C7B2C683
[root ~]#

Je moet hiervoor natuurlijk wel eerst een DNSSEC-ondertekend domein weten te vinden.

<SOA><TTL> en <Minimum> geven de TTL en de caching-periode voor NXDOMAIN-antwoorden. Voor de .nl zone zijn dat respectievelijk 2 uur en 15 minuten. Dit kun je achterhalen door een query uit te voeren voor het SOA record op het .nl-domein zelf:

[root ~]# dig @ns1.dns.nl. nl. +noall +answer +multiline SOA
nl.  7200  IN  SOA  ns1.dns.nl. hostmaster.domain-registry.nl. (
               2014081206 ; serial
               7200       ; refresh (2 hours)
               900        ; retry (15 minutes)
               2419200    ; expire (4 weeks)
               900        ; minimum (15 minutes)
               )
[root ~]#

KLIK HIER voor extra informatie over het uploaden van DNSKEY/DS records.

kasp.xml: Policies

Het configuratiebestand kasp.xml specificeert een intimiderende hoeveelheid instellingen voor de encryptie en timing van DNSSEC. De default instellingen bieden gelukkig een goed uitganspunt. We hebben zelf voor deze opzet maar beperkte wijzigingen aangebracht:

  • de TTL voor de DNSKEY records: 1 dag
  • de geldigheidsduur voor de KSK- en ZSK-sleutelparen: respectievelijk twee jaar en twee maanden
  • de naam van de Repository: SoftHSM
  • de settings voor het SOA record: respectievelijk 1 dag, 20 minuten en datecounter
  • de parameters voor het .nl top-level domein: respectievelijk 2 uur, 2 uur en 15 minuten

Die laatste instellingen in de <Parent> sectie zullen meestal de reden zijn om naast de default Policy nog andere policies aan te maken: deze parameters kunnen voor elk top-level domein immers weer anders zijn. Bijvoorbeeld voor de .com/net/org-domeinen zijn deze waarden respectievelijk 24 uur, 15 minuten en 1 dag.

zonelist.xml: input en output files

Het configuratiebestand zonelist.xml bevat een opsomming van alle te ondertekenen domeinen, tezamen met de input en output adapters, en een policy die we zojuist in de file kasp.xml hebben gedefinieerd. Het ophalen en wegschrijven van een zone file voor BIND zou er bijvoorbeeld als volgt uitzien:

<Zone name="example.nl">
  <Policy>nl</Policy>
  <SignerConfiguration>/var/opendnssec/signconf/example.nl.xml</SignerConfiguration>
  <Adapters>
    <Input>
      <Adapter type="File">/var/named/chroot/var/named/db.example.nl</Adapter>
    </Input>
    <Output>
      <Adapter type="File">/var/named/chroot/var/named/opendnssec-signed/example.nl</Adapter>
    </Output>
  </Adapters>
</Zone>

De <SignerConfiguration> is een "interne" file waarin informatie voor dit domein wordt overgedragen van de Enforcer naar de Signer; we hoeven deze alleen een goede (unieke) naam te geven.

De zone files in de directory /var/named/chroot/var/named/ hebben de permissies '640 root:named'. Om deze bestanden ook door de Signer te kunnen laten inlezen, hebben we de ods gebruiker aan de named groep toegevoegd:

usermod -aG named ods

De locatie van de output file vraagt meer aandacht. Als BIND inderdaad in een chrooted omgeving draait, zal deze geen zone files kunnen inlezen vanaf de standaard ingestelde /var/opendnssec/signed/ directory. Ervan uitgaande dat het file system geen hard links voor directories ondersteund (om loops te voorkomen meestal niet toegestaan), kun je niet anders dan de ondertekende zone files in de /var/named/chroot/ hierarchie opslaan:

mkdir /var/named/chroot/var/named/opendnssec-signed/
chown root:ods /var/named/chroot/var/named/opendnssec-signed/
chmod 775 /var/named/chroot/var/named/opendnssec-signed/

In deze opzet blijft de root eigenaar van de directory, mag de gebruiker ods hier in schrijven, en mag named (others) alleen lezen.

Om de ondertekende zone file ook door BIND named in te laten lezen, geven we deze nieuwe locatie op in het configuratiebestand /var/named/chroot/etc/named.conf:

zone "example.nl" {
  type master;
  file "opendnssec-signed/example.nl";
  };

Als je in conf.xml een 'rndc reload' commando hebt gedefinieerd als <NotifyCommand>, dan krijgt de named daemon vanzelf een reload-opdracht als deze zone file klaar is voor publicatie.

Bijkomend voordeel van deze aanpak is dat je zo alle zone files bij elkaar houdt. Op dit moment ondersteunen immers nog niet alle TLD's DNSSEC, nog niet alle registrars bieden een invoermogelijkheid voor sleutelmateriaal, en diegenen die dat wel doen doen dat ook niet voor alle TLD's die wel DNSSEC ondersteunen.

zonelist.xml: bump-in-the-wire

Voor een bump-in-the-wire set-up waarbij OpenDNSSEC de input en output met behulp van zone transfers direct uitwisselt met een DNS-server, ziet een <Zone> er als volgt uit:

<Zone name="example.nl">
  <Policy>nl</Policy>
  <SignerConfiguration>/var/opendnssec/signconf/example.nl.xml</SignerConfiguration>
  <Adapters>
    <Input>
      <Adapter type="DNS">/etc/opendnssec/addns.xml</Adapter>
    </Input>
    <Output>
      <Adapter type="DNS">/etc/opendnssec/addns.xml</Adapter>
    </Output>
  </Adapters>
</Zone>

Je zou ook nog een hybride vorm kunnen kiezen, waarbij de input uit een zone file wordt geladen en de ondertekende output via een zone transfer aan een slave server wordt overgedragen:

<Zone name="example.nl">
  <Policy>nl</Policy>
  <SignerConfiguration>/var/opendnssec/signconf/example.nl.xml</SignerConfiguration>
  <Adapters>
    <Input>
      <Adapter type="File">/var/named/chroot/var/named/db.example.nl</Adapter>
    </Input>
    <Output>
      <Adapter type="DNS">/etc/opendnssec/addns.xml</Adapter>
    </Output>
  </Adapters>
</Zone>

Hierbij is het goed op te merken dat de OpenDNSSEC database niet noodzakelijk via de zone list hoeft te worden geladen. Voor grotere aantallen domeinen kan dat ook via de command line:

ods-ksmutil zone add ...
ods-ksmutil zone delete ...
ods-ksmutil zone list
ods-ksmutil zonelist export

Bijvoorbeeld:

ods-ksmutil zone add --zone example.nl --policy nl 
    --in-type File --input '/var/named/chroot/var/named/db.example.nl' 
    --out-type DNS --output '/etc/opendnssec/addns.xml'

Wie dat wil kan zelfs beide mogelijkheden combineren: je kunt vanuit de database een dump naar een zone list maken, deze file editen en vervolgens weer inladen.

Voor de details van deze commando's verwijzen we naar de documentatie van OpenDNSSEC.

addns.xml: versleutelde zone transfers

Het laatste configuratiebestand van ons viertal bevat informatie voor de Adapters. Voor het File type is verder niets nodig; met de naam is alles bekend. Maar voor de DNS Input en Output adapters moeten we nog het een en ander vastleggen in de <DNS> sectie.

Om te beginnen de informatie voor de versleuteling van de zone transfers:

<TSIG>
  <Name>transfer_key</Name>
  <!-- http://www.iana.org/assignments/tsig-algorithm-names -->
  <Algorithm>hmac-sha256</Algorithm>
  <!-- base64 encoded secret -->
  <Secret>********************************************</Secret>
</TSIG>

TSIG is een symmetrische cryptografie-standaard voor gebruik tussen DNS-servers. Dat betekent dus dat beide partijen een gemeenschappelijke geheime sleutel hebben waarmee AXFR en IXFR transfers worden versleuteld.

In het BIND configuratiebestand /var/named/chroot/etc/named.conf specificeer je deze sleutel als volgt:

key transfer_key {
  algorithm hmac-sha256;
  secret "********************************************";
  };

Je kunt de geheime sleutel genereren met behulp van het dnssec-keygen commando:

cd /etc/bind/
dnssec-keygen -T KEY -a hmac-sha256 -b 256 -r /dev/urandom -n HOST transfers

De sleutel vind je nu in de file Ktransfers.+163+12345.private. Onthoud dat dit een symmmetrische sleutel is; dat betekent dat er één geheime sleutel is die beide partijen in hun bezit moeten hebben en geheim moeten houden.

addns.xml: Inbound en Outbound adapters

<Inbound>
  <RequestTransfer>
    <Remote>
      <Address>192.168.7.3</Address>
      <Key>transfer_key</Key>
    </Remote>
  </RequestTransfer>
  <AllowNotify>
    <Peer>
      <Prefix>192.168.7.3</Prefix>
      <Key>transfer_key</Key>
    </Peer>
  </AllowNotify>
</Inbound>

In de <Inbound><RequestTransfer> sectie kunnen meerdere master servers opgegeven worden voor het ophalen van zone-informatie. Door deze ook als <Peer> in de <AllowNotify> sectie te zetten, wordt er door OpenDNSSEC als slave gereageerd op binnenkomende NOTIFY-berichten van deze masters.

De configuratie van de Outbound adapter is precies hetzelfde:

<Outbound>
  <ProvideTransfer>
    <Peer>
      <Prefix>192.168.7.131</Prefix>
      <Key>transfer_key</Key>
    </Peer>
  </ProvideTransfer>
  <Notify>
    <Remote>
      <Address>192.168.7.131</Address>
      <Key>transfer_key</Key>
    </Remote>
  </Notify>
</Outbound>

Nu zal de OpenDNSSEC-server op zijn beurt NOTIFY-berichten sturen naar de slaves als er een nieuwe zone file klaarstaat.

SoftHSM

De laatste stap voordat we OpenDNSSEC kunnen opstarten is de configuratie van SoftHSM. Bij de installatie van dit pakket is al een token (keystore) 0 aangemaakt met als label 'OpenDNSSEC' en voor beide paswoorden (PIN en SO PIN) '1234'.

Check om te beginnen het configuratiebestand /etc/softhsm.conf:

0:/var/softhsm/slot0.db

Gooi vervolgens die bestaande (lege) keystore weg:

rm /var/softhsm/slot0.db

En creëer/initialiseer een nieuwe:

[root ~]# softhsm --init-token --slot 0 --label "OpenDNSSEC"
The SO PIN must have a length between 4 and 255 characters.
Enter SO PIN: ************
The user PIN must have a length between 4 and 255 characters.
Enter user PIN: ************
The token has been initialized.
[root ~]#

Zorg voor goede PIN-wachtwoorden. Die laatste is degene die je als <PIN> in de file /etc/opendnssec/conf.xml zet. De SO PIN is bedoeld voor de beheerder (Security Officer) en wordt door OpenDNSSEC verder niet gebruikt.

Zorg tenslotte dat deze keystore ook toegankelijk is voor de ods gebruiker:

chown root:ods /var/softhsm/slot0.db
chmod 664 /var/softhsm/slot0.db

Meer is voor het gebruik van SoftHSM nu niet nodig. Je kunt nog een overzicht van de slots en hun status opvragen:

softhsm --show-slots

Voor het importeren en exporteren van sleutels verwijzen we naar de documentatie en het help-overzicht:

softhsm --help

Opstarten

Nu dit alles voor elkaar is, kunnen we de inhoud van onze configuratiebestanden in de database laten inlezen door de Enforcer:

ods-ksmutil setup

Lees de waarschuwingen goed door en pas waar nodig de instellingen aan. Je kunt ze daarna gewoon opnieuw in laten lezen door het 'ods-ksmutil setup' commando opnieuw uit te voeren.

Het opstarten van de Enforcer en de Signer gaat als volgt:

ods-control start

Maar je kunt de twee daemons ook afzonderlijk besturen:

service ods-enforcerd start
service ods-signerd start

Om te zorgen dat OpenDNSSEC ook na een reboot wordt opgestart zetten we deze twee services permanent aan:

chkconfig ods-enforcerd on
chkconfig ods-signerd on

Controleer nu de log messages om te zien of alles in orde is. Het inlezen van de zone files verliep in onze opzet zonder grote problemen. Ook wat minder gangbare resource record types werden goed verwerkt: SPF (anti-spam), SSHFP (voor Secure Shell), SRV en NAPTR (voor internet-telefonie). Alleen het TYPE37 record werd geweigerd. Dit is een wat exotisch catch-all type dat bijvoorbeeld gebruikt wordt om PGP-sleutels te publiceren.

Uploaden van KSK-sleutelmateriaal

Als alles inderdaad goed draait, dan rest alleen nog het uploaden van het KSK-sleutelmateriaal naar de registry. Je kunt een overzicht van de opgeslagen sleutels en hun status als volgt opvragen:

[root ~]# ods-ksmutil key list (--verbose)
Keys:
Zone:        Keytype: State:  Date of next transition (to):  ...  Keytag:
example.nl.  ZSK      active  2014-10-12 16:07:40 (retire)   ...  17008
example.nl.  KSK      ready   waiting for ds-seen (active)   ...  15272
[root ~]#

Hier zien we dat het KSK-sleutelpaar in de 'ready' state is. Dat betekent dat de Enforcer wacht op een signaal van de beheerder dat het DS record gepubliceerd is in de bovenliggende zone.

Daarvoor moeten we eerst het publieke KSK-sleutelmateriaal naar de registry uploaden. Sommige registries — waaronder SIDN — vragen daarvoor het DNSKEY record, dat de hele publieke sleutel bevat. Andere vragen om het DS record zelf, dat alleen een hash van de publieke sleutel bevat. Dat laatste is ook wat er uiteindelijk door de registry in zijn zone gepubliceerd wordt. Reden om niet het DS record maar het hele DNSKEY record te vragen, is dat de registry zo zelf het hash-algoritme kan bepalen.

De informatie voor registries die het DS record gebruiken kun je direct overnemen van je eigen instellingen:

  • algoritme: 8 (RSASHA256 voor de sleutelparen en handtekeningen)
  • digest: 2 (SHA256 voor de hash)

De records zelf kun je op deze manier opvragen:

ods-ksmutil key export --zone example.nl (--ds)
[root ~]# ods-ksmutil key export --zone example.nl --keystate PUBLISH --ds
;publish KSK DS record (SHA1):
example.nl.  86400  IN  DS  12345 8 1 3c5b5614e4d2940e8e452e980a301caf4bb9e626
;publish KSK DS record (SHA256):
example.nl.  86400  IN  DS  12345 8 2 d33eeed653e36040abc0e85ea5f2e8d3d974a513bd690f772ed1c1e7cd6f93ad
[root ~]#

Joker: DNSSEC .com

Joker: DNSSEC .com

Voor registries die het hele DNSKEY record willen hebben — waaronder SIDN — heeft SIDN Labs een handig tooltje online staan:

Als je daar het complete DNSKEY record invult, berekent deze tool de waarden voor de afzonderlijke velden.

Joker: DNSSEC .de

Joker: DNSSEC .de

Als je het DS record daadwerkelijk kunt zien:

[root ~]# dig @ns1.dns.nl. example.nl. +noall +answer DS
example.nl.  7200  IN  DS  29929 5 2 5AD487D2125717B1D229AD067ABBC43578F286B387781A35144B97BC 58F25A3D
[root ~]#

Dan laat je dat weten aan de Enforcer:

[root ~]# ods-ksmutil key ds-seen -z example.nl. -x 12345
Found key with CKA_ID 4c25e2969c197edf2f6b715f563dc763
Key 4c25e2969c197edf2f6b715f563dc763 made active
Notifying enforcer of new database...
Performed a HUP ods-enforcerd
[root ~]#

Vanaf dit moment begint de Enforcer af te tellen: wanneer zowel het DNSKEY record als het bijbehorende DS record overal bekend zijn, dan kan dit nieuwe sleutelpaar daadwerkelijk worden ingezet om zone-informatie te ondertekenen.

Aandachtspunten

Het is verleidelijk om een DNSKEY/DS record al eerder voor publicatie bij de registry aan te melden. Je loopt dan wel het risico dat je domein op sommige plaatsen tijdelijk geblokkeerd wordt: een validerende resolver ziet dan immers wel dat een domeinnaam ondertekend moet zijn, maar heeft mogelijk nog oude (geen of ongeldige) DNS-informatie in zijn cache staan. Dat is waarom je geen 'ods-ksmutil key ds-seen' opdracht kunt geven voor een KSK-sleutelpaar dat nog niet in de 'ready' state is. De beheerder ontvangt vanzelf bericht (in de logs en per mail) als het sleutelmateriaal klaar is voor publicatie bij de registry. OpenDNSSEC moet hierin leidend zijn; dat is waarom tenslotte waarom we al die timing-informatie hebben ingevoerd.

Als je om wat voor reden dan ook een private sleutel kwijtraakt, en daardoor niet meer in staat bent om een zone ondertekenen, dan heb je een probleem. Je moet dan direct overstappen naar een nieuw sleutelpaar, maar loopt wel het risico dat domeinen tijdelijk niet beveiligd of niet ondertekend zijn. In de niet-zo-verre toekomst, wanneer veel meer resolvers zullen valideren, betekent dat laatste dat domeinen onbereikbaar zullen zijn.

We raden daarom aan om de <RequireBackup/> optie in het configuratiebestand conf.xml aan te zetten. Vervolgens laat je de Enforcer weten dat je een backup van de huidige sleutels in de Repository gaat maken:

ods-ksmutil backup prepare (--repository SoftHSM)

Zijn de sleutels daadwerkelijk veilig opgeslagen, dan geef je de Enforcer opnieuw een signaal:

ods-ksmutil backup commit (--repository SoftHSM)

Pas na deze bevestiging zullen deze sleutels gebruikt kunnen gaan worden.

Zoals dit artikel heeft laten zien is timing een cruciaal onderdeel van DNSSEC. Stel daarom de systeemtijd van je servers in op UTC, zodat je niet in de problemen komt met bijvoorbeeld de wisseling tussen zomer- en wintertijd. En zorg dat je servers allemaal NTP-gesynchroniseerd zijn.

Daarnaast is het van belang de log messages te monitoren, zodat je het op tijd in de gaten hebt als er iets misgaat.

Voor de migratie van bestaande DNSSEC sleutels — eventueel met roll-over voor een veilige overgang naar OpenDNSSEC — verwijzen we tenslotte naar de documentatie. Hetzelfde geldt voor het inhaken van validatie-tools die de geldigheid van een nieuwe ondertekende zone verifiëren alvorens deze gepubliceerd wordt.