Správa DNS zónových souborů v Gitu

20. 12. 2018
Doba čtení: 8 minut

Sdílet

Zónové soubory jsou stále tím nejjednodušším způsobem správy DNS dat na autoritativních serverech. V článku si popíšeme, jak je možné použít Git pro správu historie zónových souborů a ochranu před chybami.

Tradiční zónové soubory jsou stále populární, zejména v mezi poskytovateli přístupu k internetu, kde správa DNS není hlavním předmětem činnosti – řeší se většinou jen reverzní záznamy – a požadavek na rychlé změny není velký. Tím nejjednodušším řešením je editace zónového souboru přímo na primárním DNS serveru a použití klasických mechanizmů zónového přenosu (AXFR, případně inkrementální IXFR) pro přenos na sekundární autoritativní servery. V takovém případě je třeba zónový soubor editovat obezřetně; vložení syntaktické chyby má za následek výpadek služby, nezvýšení sériového čísla zóny při úpravě způsobí, že se zóna nepřenese a každý autoritativní server tedy bude nabízet jiná data.

Použití skrytého primárního serveru situaci vylepšuje. Skrytý primární server drží zónové soubory, ale není zveřejněn jako autoritativní server pro danou doménu. Jeho jediným účelem je přenést zónu zónovým přenosem na veřejné sekundární servery. Díky tomu je zaručeno, že všechny veřejné DNS servery budou mít stejná data a že případný výpadek, způsobený například chybou v zónovém souboru, se neprojeví veřejně. Při podepisování zóny pomocí DNSSEC je navíc praktické nemít privátní klíče přímo na veřejném DNS serveru.

Často je praktické udržovat nějakou míru historie změn v zónových souborech. Tradiční řešení s komentáři přímo uvnitř souborů úplně dobře neškáluje a neobstojí v konkurenci moderních systémů pro správu verzí, jako je například Git. Na druhou stranu, ukládání každé změny do gitovského repozitáře přidává administrátorům další práci. I když jde o sérii jednoduchých úkonů, jejich manuální provádění je nepohodlné a náchylné k chybám. Naštěstí Git obsahuje podporu pro hooks, tedy háčky, kterými lze upravit průběh jednotlivých kroků a tak většinu práce automatizovat. Systém může nakonec vypadat třeba takto:

Většinu komponent tvoří běžně dostupný open-source software od několika výrobců. Jedinou výjimkou je software pro integraci Git repozitáře s DNS serverem. Objevil jsem pouze jeden projekt jménem GitZone, který v sobě kombinuje správu gitovského repozitáře a napojení na DNS server v jednom skriptu v Perlu. Takový přístup mi nevyhovoval – chtěl jsem něco lehčího, co bude možné používat s existujícími a prověřenými správci Git repozitářů, jakým je třeba Gitolite. Po určitém výzkumu jsem se rozhodl napsat vlastní univerzální řešení.

Představujeme dzonegit

Projekt dzonegit je sada háčků pro Git pro automatizaci správy zónových souborů. Je napsán v Pythonu 3.5 a závisí pouze na programu named-compilezone, který je součástí DNS serveru BIND. V háčku pre-commit se pokusí zkompilovat všechny změněné zónové soubory. Pokud se kompilace nezdáří, je commit odmítnut. V opačném případě je porovnáno sériové číslo změněných zón se sériovým číslem předchozích verzí. Pokud se nezvýšilo, je commit rovněž odmítnut, protože by se nová verze zóny nepřenesla.

Vzhledem k tomu, že všechny háčky jsou lokální k danému Git repozitáři, nelze jejich spuštění vynutit na vzdáleném repozitáři. Z toho důvodu se stejné kontroly validity dat provádějí i na straně DNS serveru během přijímání revize od uživatele. K tomu slouží háček pre-receive nebo update  – oba dělají totéž, záleží jen na tom, který se jednodušeji integruje se správcem repozitáře. Díky tomu je zajištěno, že v repozitáři na DNS serveru jsou pouze validní zónové soubory, jejichž sériové číslo se s každou změnou zvyšuje.

Poslední háček, který dzonegit  poskytuje, je post-receive. Je spouštěn po každé aktualizaci repozitáře na serveru. Jeho úkolem je vystavit obsah repozitáře v externí pracovní kopii, odkud budou zónové soubory načteny DNS serverem. Dále je vygenerován úryvek konfiguračního souboru pro DNS server, obsahující definice všech zón v repozitáři. Například pro BIND je pro každou zónu potřeba následující řádek v konfiguraci:

zone "example.com" { type master; file "/path/to/example.com.zone"; }; 

Aby bylo řešení univerzální, tyto úryvky jsou generovány z jednoduché JSON šablony. Pro výše uvedený příklad může šablona vypadat takto:

{
  "header": "# Autogenerated by dzonegit on $datetime. Do not edit.\n",
  "item": "zone \"$zonename\" { type master; file \"$zonefile\"; };"
} 

Posledním krokem, který háček post-receive provádí, je notifikace DNS serveru, že došlo ke změně zónových souborů. Slouží k tomu dva příkazy. Příkaz uložený v proměnné zonereloadcmd je volán pro každou zónu, jejíž obsah se změnil; název zóny je přidán na konec příkazu. Druhý příkaz v proměnné reconfigcmd je volán pokaždé, je-li nějaký zónový soubor přidán nebo odebrán.

Všechny proměnné nástroje dzonegit jsou uloženy jako konfigurační volby Git repozitáře. Běžným příkazem git config je možné nastavit je jak pro repozitář, tak i pro uživatele nebo globálně.

Podepisování technologií DNSSEC

V počátcích technologie DNSSEC byl jediným dostupným řešením nástroj dnssec-signzone. Ten načte zónový soubor, podepíše ho a zapíše vedle nový, podepsaný soubor. Tuto utilitu je teoreticky možné stále používat ještě před vložením zónového souboru do repozitáře, takové použití by ale bylo nepohodlné a vyžadovalo by pravidelnou údržbu podpisů, jejichž platnost je časově omezená. Dnes je situace jiná, na trhu je mnoho dobrých open-source řešení nabízejících automatickou správu podpisů i klíčů – například BIND, OpenDNSSEC, PowerDNS, nebo český Knot DNS.

Aby byl systém co nejvíce modulární, je dobré oddělit proces DNSSEC podpisů a správy klíčů do samostatného funkčního bloku. V režimu zvaném bump-in-the-wire se nepodepsané zóny přenášejí na podepisovač, který následně přenáší podepsané zóny na veřejné sekundární servery.

Jako podepisovač jsem zvolil Knot DNS. Argumenty pro jeho výběr jsou v podstatě shodné s argumenty prezentovanými organizací RIPE NCC. Během testování jsem objevil několik chyb v implementaci správy klíčů. Všechny byly vývojáři promptně opraveny, opravy jsou ale dostupné jen v nejnovějších vydáních. Z toho důvodu je třeba silně doporučit použití oficiálních balíčků namísto distribučních, které mohou být zastaralé.

Nastavení Knot DNS je velmi jednoduché. V hlavním konfiguračním souboru nastavíme šablonu pro zóny a politiku podpisů:

template:
  - id: default
    storage: "/var/lib/knot"
    zonefile-load: none   # vůbec nepoužíváme zónové soubory
    zonefile-sync: -1
    journal-content: all  # obsah zón držíme v žurnále
    master: primary       # odkaz na primární server
    acl: acl_primary      # povol zprávy NOTIFY z primárního serveru
    acl: acl_secondary    # povol zónové přenosy na sekundární servery
    notify: secondary     # posílej sekundárním serverům zprávy NOTIFY
    dnssec-signing: on
    dnssec-policy: ecdsa

policy:
  - id: ecdsa
    algorithm: ecdsap256sha256
    zsk-lifetime: 30d
    rrsig-lifetime: 30d
    rrsig-refresh: 15d
    nsec3: on 

Nakonec do souboru vložíme úryvek vygenerovaný post-receive háčkem nástroje dzonegit  – je možné vygenerovat více různých úryvků zároveň. V tomto případě můžeme využít proměnných pro každou zónu a tak nastavit různé politiky podepisování či nepodepisování pro různé zóny.

Sdílet či nesdílet

V prostředí web hostingu, přinejmenším v Česku, je velmi oblíbené použití jedné sady DNSSEC klíčů pro všechny hostované zóny. Při velkém množství hostovaných zón se tak dramaticky snižuje provozní náročnost podepisování. Navíc FRED, open-source registr vyvíjený a provozovaný sdružením CZ.NIC, takové sdílení klíčů mezi doménami ulehčuje použitím takzvaných Keysetů. Tyto objekty obsahují veřejné DNSSEC klíče a mohou být přiřazeny k libovolnému počtu domén. Je to poměrně velký rozdíl proti běžně používanému řešení podle RFC 5910, kde se DS záznam přidává přímo jako atribut dané domény. Vzhledem k tomu, že DS záznam je otiskem veřejného klíče a doménového jména, není možné jej mezi doménami sdílet.

Minulý rok však CZ.NIC jako první na světě zprovoznil automatickou správu keysetů, takže bezpečnou delegaci z .cz  domény je možné vytvořit a udržovat aktuální čistě pomocí signalizace uvnitř DNS, definované v RFC 7344. Tím se provozní náklady na udržování bezpečné delegace snížily na nulu, bez ohledu na sdílení či nesdílení klíčů.

Z pohledu správy klíčů je nesdílení klíčů mezi zónami jednodušší a více otestované. Dokud nespravujete tisíce zón, asi je lepší se sdílení klíčů vyhnout.

Automatizujte, co se dá!

Automatická správa bezpečné delegace výrazně zjednodušuje správu DNSSECu. Po správném úvodním nastavení není třeba žádná další pravidelná manuální akce. Bohužel existuje jen několik málo nadřazených zón, které automatickou správu podporují, v současné době to jsou .cz, .cr, .ch a .li. Pro všechny ostatní nadřazené zóny je potřeba stále provádět pravidelně výměny klíče ručně.

Nejjednodušší je samozřejmě ignorovat problém. Při použití moderních DNSSEC algoritmů ECDSA s klíčem délky 256 bitů jde o klíče tak silné, že je není potřeba měnit minimálně několik let.

Jiné řešení spočívá v použití CDS/CDNSKEY záznamů, který produkuje podepisovací software, jako univerzální signalizaci nutnosti výměny klíče a implementovat komunikaci s nadřazenou zónou ve vlastní režii. Zabezpečení reverzních zón, delegovaných z RIPE NCC, se ukazuje jako nejjednodušší varianta, protože je k dispozici jednoduché a dobře dokumentované REST API, kterým je možné číst a editovat obsah RIPE databáze, kde jsou uloženy i data bezpečných delegací.

Vyrobil jsem demonstrační příklad porovnávající DS záznam uložený v RIPE databázi s otiskem získaným z CDS  záznamu v zóně, validovaném pomocí DNSSEC. Pokud je nalezen nový otisk, je databáze aktualizována. Během RIPE 77 toto řešení vzbudilo v komunitě jistý zájem, je tedy možné, že v budoucnu bude podobné řešení nasazené přímo na straně RIPE NCC. Obdobný přístup je možné použít i s jinými registry, tedy za předpokladu, že registrátor podporuje DNSSEC i na jiných než .cz a .eu doménách a navíc má pro změnu příslušné API.

bitcoin_skoleni

Největší výzva ovšem spočívá v udržování bezpečných delegací ze zón hostovaných na naší vlastní platformě. Je k tomu potřeba buď nějaký systém automatických commitů do Git repozitáře, kdykoli je potřeba změnit obsah DS záznamu, nebo nějaký skrytý mezikrok přidávání DS záznamů po načtení z repozitáře, před předáním DNS serveru. K tomu by se dal použít například smudge filtr v Gitu.

Shrnutí

Na popsaný systém správy zónových souborů jsme převedli všechny domény hostované ve sdružení CESNET počátkem září 2018, po několikaměsíčním testování. Přechod na Knot DNS nám umožnil přejít ze sdíleného RSA klíče na samostatné ECDSA klíče a zavést DNSSEC i na domény, u kterých nejsme držitelem a nemáme tedy přístup k administraci dané domény. Snížení pracovní náročnosti a bezpečnostní funkce v podobě okamžitých kontrol udělalo rutinní činnost editace DNS záznamů mnohem jednodušší pro operátory. Všechny části systému jsou open-source, příspěvky komunity jsou vítány.

Autor článku

Ondřej Caletka vystudoval obor Telekomunikační technika na ČVUT a dnes pracuje ve vzdělávacím oddělení RIPE NCC, mezinárodní asociaci koordinující internetové sítě.