Hlavní navigace

Validace certifikátů Let's Encrypt pomocí DNS včetně wildcard

Petr Krčmář

Drtivá většina klientů ověřuje certifikáty u Let's Encrypt pomocí HTTP. Někdy ovšem tuhle možnost nechceme či nemůžeme použít, pak přichází na řadu validace pomocí DNS. Popíšeme si postup na vlastní DNS infrastruktuře.

Doba čtení: 5 minut

Sdílet

Certifikační autorita Let's Encrypt je velmi populárním řešením pro pohodlné získávání certifikátů. Jednak nabízí tvorbu certifikátů zdarma, ale především je vše možné provést plně automaticky. Celý proces je tak možné udělat spuštěním jednoho příkazu, navíc některé aplikace mají podporu integrovanou a vše proběhne prakticky bez uživatelova zásahu.

Během získávání podepsaného certifikátu je potřeba projít procesem validace. Při něm musí žadatel prokázat, že má možnost manipulovat s doménou či obsahem na ní. Tradiční metoda spočívá v tom, že se na web serveru na správné cestě vystaví výzva, kterou si pak autorita stáhne. Je to nejjednodušší a není k tomu potřeba nic, kromě web serveru.

Existuje ale řada případů, kdy není možné tuto metodu použít. Můžeme mít například centrální server pro získávání certifikátů, který vše vyřídí za všechny naše služby a poté jen rozdistribuuje aktuální certifikáty. Nebo chceme získat certifikáty pro zařízení, na kterých nemůžeme žádného ACME klienta spouštět – třeba pro síťové prvky. Dalším důvodem může být potřeba získat wildcard cerfitikáty, které je možné validovat jen pomocí DNS.

Validace s proxy DNS

Pokud chceme žádost ověřit pomocí DNS, musíme řetězce dodané autoritou vystavit v DNS. Konkrétně se jedná o záznamy typu TXT pro subdoménu _acme-challenge. Samozřejmě to vyžaduje, abychom měli v danou chvíli automatizovaný přístup k zóně a mohli ji editovat.

O první možnosti psal před časem Dan Ohnesorg, můžeme část zóny přesměrovat k poskytovateli, který nám nabízí API. Není vůbec potřeba předávat kontrolu nad doménou jako celkem, stačí nám jen přesměrovat zmíněnou subdoménu. Do zóny na svých serverech tak přidáme následující záznam:

_acme-challenge.example.com. IN CNAME _acme-challenge.domena-s-api.cz.

Poté už použijeme klienta, který je schopen pomocí API přidávat požadované TXT záznamy. Stále to ale vyžaduje použít cizí API a navíc potřebujeme mít navíc jednu zbytečnou doménu, kterou takto využijeme jen pro server s API.

DNS na naší infrastruktuře

Pokud máme vlastní infrastrukturu pro DNS a máme tedy své autoritativní servery, nebudeme tohle všechno vůbec používat a můžeme přímo měnit záznamy v zóně pomocí dynamických updatů dle RFC 2136. Ty nám dovolují zasahovat vzdáleně do zóny, aniž bychom museli mít přímý přístup do zónových souborů.

Budeme potřebovat úpravu konfigurace autoritativního serveru a ACME klienta, který podporuje nsupdate. V tomto příkladu použijeme skript ACME.sh, ale vy můžete použít svého oblíbeného.

Pro autorizaci použijeme TSIG (Transaction SIGnature), což je standardní způsob podepisování DNS přenosů definovaný v RFC 2845. Zjednodušeně řečeno: obě strany znají sdílené tajemství (klíč), kterým je komunikace zabezpečena. Bez znalosti tohoto tajemství není možné do zóny na dálku zasahovat.

Konfigurace DNS serveru

Předpokládám, že už nám autoritativní DNS servery běží a máme na nich platné zónové soubory. Nejprve musíme vygenerovat klíč pro TSIG. Použijeme k tomu utilitu dnssec-keygen z balíčku  bind9utils.

$ dnssec-keygen -a hmac-sha256 -b 256 -n HOST acme-tsig.example.com
Kacme-tsig.example.com.+163+33240
$ cat Kacme-tsig.example.com.+163+33240.key
acme-tsig.example.com. IN KEY 512 3 163 /GQWpBMMsl5QnYxNaHfCqj5MzURSroW6lgYJqRtN/L0=

Klíč vložíme do konfigurace serveru a povolíme jeho držiteli aktualizovat záznamy v zóně. Pozor na to, že jméno klíče je součástí podepisované zprávy a musí být tedy nastavené na stejnou hodnotu na serveru, jako v klientovi (utilitě nsupdate, kterou budeme provádět vlastní změny v zóně). Na vlastním jménu klíče nezáleží, abychom ale předešli zbytečným kolizím, je dobrou praxí použít libovolné doménové jméno, které máme pod kontrolou.

Pokud používáme BIND, bude konfigurace vypadat takto:

key "acme-tsig.example.com." {
  algorithm hmac-sha256;
  secret "/GQWpBMMsl5QnYxNaHfCqj5MzURSroW6lgYJqRtN/L0=";
};

zone "example.com." IN {
  type master;
  file "named.example.com";
  update-policy {
    grant acme-tsig.example.com. name _acme-challenge.example.com. txt;
    grant acme-tsig.example.com. name _acme-challenge.www.example.com. txt;
  };
};

Pokud používáte Knot DNS, bude stejné nastavení vypadat takto:

key:
   - id: "acme-tsig.example.com"
     algorithm: "hmac-sha256"
     secret: "/GQWpBMMsl5QnYxNaHfCqj5MzURSroW6lgYJqRtN/L0="

acl:
   - id: acme_update
     key: "acme-tsig.example.com"
     action: update
     update-type: TXT
     update-owner: name
     update-owner-name: [_acme-challenge.example.com., _acme-challenge.www.example.com.]
     update-owner-match: equal

zone:
   - domain: "example.com"
     acl: acme_update
     …

To je z hlediska serveru vše, klient se znalostí sdíleného tajemství je teď schopen měnit patřičné záznamy.

Získání certifikátu

V první řadě budeme potřebovat klienta, který dokáže komunikovat s certifikační autoritou a pomocí protokolu ACME vyjednat získání certifikátu. Nainstalujeme si zmíněný skript ACME.sh:

$ git clone https://github.com/Neilpang/acme.sh.git
$ cd acme.sh
$ ./acme.sh --install

Před spuštěním klienta musíme nastavit dvě proměnné prostředí, které ho nasměrují na správný DNS server a soubor s vygenerovaným sdíleným tajemstvím pro autorizaci. To je potřeba udělat jen na začátku, klient si pak údaje uloží do konfiguračního souboru ~/.acme.sh/account.conf a příště je použije sám.

$ export NSUPDATE_SERVER="ns-master.example.com"
$ export NSUPDATE_KEY="/home/letsencrypt/Kacme-tsig.example.com.+163+33240.key"

Teď už můžeme požádat o certifikát pro naše doménová jména. Klient má všechny informace potřebné k tomu, aby podal žádost a pomocí změny TXT záznamu v DNS nechal autoritu ověřit její oprávněnost.

$ acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com --key-file /home/letsencrypt/certs/example.com.key --fullchain-file /home/letsencrypt/certs/example.com.cer

V příslušných souborech se nám objeví privátní klíč a důvěryhodný certifikát. Ten už teď stačí jen nasadit v našem web serveru nebo v jiné službě, která jej bude používat. Pokud bychom potřebovali wildcard certifikát, stačí použít parametr  -d *.example.com.

Pozor na wildcard DNS

Při ověřování pomocí DNS nás může nepříjemně zaskočit způsob, jakým jsou v DNS implementovány wildcard záznamy, tedy takové záznamy, které začínají *.. Ty z definice dokáží nahradit libovolný neexistující DNS záznam, takže doména vypadá, že obsahuje všechny myslitelné subdomény.

Pokud ovšem do domény zavedeme například záznam _acme-challenge.www.example.com, přestane být záznam www.example.com neexistujícím záznamem (stane se z něj takzvaný empty-non-terminal), takže se na něj přestane hvězdička uplatňovat. Aby vše fungovalo podle očekávání, je potřeba každé jméno, které chceme validovat, zavést explicitně a na expanzi žolíku v takovém případě nespoléhat.