Centralizovaná automatizace certifikátů pomocí nástroje uacme

16. 12. 2025
Doba čtení: 8 minut

Sdílet

Ilustrační obrázek
Autor: www.shutterstock.com, podle licence: Rights Managed
Ilustrační obrázek
Na Univerzitě Pardubice používáme centralizované řešení automatizace vydávání certifikátů. Připravuje se zkracování doby platnosti certifikátů a popíšeme si proto nástroje a skripty, které k tomu používáme.

Automatizovanou výměnu certifikátů máme asi všichni spojenou s certifikační autoritou Let's Encrypt a protokolem ACME. Ale jak se nám blíží doba zkracování platnosti certifikátů, začínají podporovat ACME i další autority. Naše univerzitní certifikační autorita Harica, poskytovaná přes CESNET, začala nabízet automatizaci až letos na podzim. Přesně tohle poskytování certifikátů asi většinou nepoužijete, je totiž primárně určené pro univerzity a členy sdružení CESNET. Ale obecný přístup, k této problematice určitě platí pro všechny CA, které automatizaci nabízejí. Dokonce není nutné použít tu samou kombinaci uacme a Ansible, s certbotem a Puppetem to bude fungovat také.

Co se dozvíte v článku
  1. Centrálně nebo lokálně, certbot nebo uacme
  2. Nástroj uacme
  3. Skripty uacme
  4. Vytvoření certifikátu

Harica nám poskytuje certifikáty ověřené na organizaci – OV. Tím se liší od běžných Let's Encrypt certifikátů validovaných pouze na doménu – DV. Abyste získal OV certifikát, máte s CA nějakou „papírovou“ smlouvu, kterou se stanete jejich zákazníkem. Pak si u CA zaregistrujete své domény, pro které chcete certifikáty vydávat. Potom si žádáte o automatizovaný certifikát a obdržíte automatizační kódy. S těmito kódy si pomocí nějakého ACME klienta vydáte certifikát.

Poznámka: Dnes už CA konečně dbají na správnost CAA záznamů v DNS. Dlouhou dobu jim to bylo jedno. Ale dnes bez správného CAA záznamu vám CA doménu nezaregistruje.

Centrálně nebo lokálně, certbot nebo uacme

U této kapitoly jsem si nebyl jistý jak ji psát. Je to jako co bylo dříve, slepice nebo vejce. Jedno ovlivňuje druhé.

ACME klientů, nebo-li prográmků co tvoří certifikáty pomocí ACME protokolu, je celá řada. Asi nejznámější je certbot. Je psaný v Pythonu a Harica ho sama doporučuje. Jenže, když jsem ho začal zkoušet, zatím s Let's Encryptem, velmi často jsem se dostával do takových zvláštních stavů. Padal na tracebacky. Ano, často padal proto, že jsem se ho snažil donutit, aby certifikáty vydával centrálně pro více serverů.

Nakonec jsem zjistil, že jsem měl chybu v parametru. Jenže místo jednoduché a srozumitelné hlášky: „máš špatně parametry“, jsem dostával obecný pád Pythonu. Když jsem ho pak rozchodil, ne pokaždé se jeho spuštění při obnově certifikátu povedlo. Často padal, aby se vzápětí normálně spolehlivě spustil. Nebyla to nějaká experimentální verze, byla normální z repozitáře Debianu. Později jsem se dozvěděl, že kolegům z CESNETu se to dělo také.

Následně jsem zjistil, že Harica doporučuje nepoužívat systémového certbota, ale použít jeho nejnovější verzi pomocí Snapu. Ono to dává smysl, protože tam určitě přišla nějaká aktualizace v protokolu ACME, ale jaká, to sám nevím. Jenže představte si, na každý server s certifikátem ještě instalovat snapd, aby automatizace fungovala? No to určitě ne, to musí jít lépe.

Už před časem, když jsem občas potřeboval certifikát od Let's Encryptu, jsem narazil na prográmek uacme. Je psaný v C a je součástí debianího repozitáře. Bohužel s Haricou se dá použít až v Debianu 13, protože tam je verze 1.7.6. Verze 1.7.4 z Debianu 12 je někdy z roku 2023 a s Haricou pracovat neumí. To omezuje lokální použití na starších hostitelích, ale protože jsem se rozhodl použít centrální řešení, nevadilo mi to.

Ale i pro lokální použití má uacme jednu pěknou vlastnost. Server by neměl mít přístup do internetu, pokud ho vysloveně nepotřebuje. Pro tyto případy má uacme  svou vlastní systémovou proměnnou UACME_PROXY. Umí pracovat i s klasickou systémovou proměnnou HTTP_PROXY, ale oddělit to, mi přijde šikovné.

Nástroj uacme

Pro DV certifikáty s webovým ověřováním od Let's Encrypt je uacme snadno použitelné:

uacme -y new
uacme -h /usr/share/uacme/uacme.sh issue prvníDoménovéJméno dalšíDoménovéJméno

Ověřovací adresář je /var/www/.well-known/, certifikáty najdeme v /etc/ssl/uacme. Hook uacme.sh se používá právě pro vytváření validačních kódů. Pro OV certifikáty hook nepotřebujeme, ale co je stejné, je postup – nejdříve registrace u CA a pak teprve žádost.

Stejná je i výchozí adresářová struktura. Soubor key.pem v adresáři private není klíčem certifikátu, ale podpisovým klíčem použitým při komunikaci s CA. Tento klíč se vytváří při registraci příkazem uacme  ‑ y new. Vlastní certifikát je pak v podadresáři s názvem prvního doménového jména. Soubor s certifikátem obsahuje automaticky celý řetězec důvěry, tedy v sobě má nejen certifikát hostitele, ale i certifikát autority. Klíč k němu je logicky v podadresáři private prvního doménového jména.

/etc/ssl/uacme
├── prvníDoménovéJméno
│   └── cert.pem
└── private
    ├── prvníDoménovéJméno
    │   └── key.pem
    └── key.pem

Poznámka: Příjemnou vlastností uacme je, že ve výchozím stavu nemění při obnově certifikátu klíč. U webového serveru by to nevadilo, ale u poštovního ano. Protože tam míváte v DNS zveřejněný TLSA záznam. Certbot má sice také parametr blokující výměnu klíče, ale dost často mi to ten parametr ignorovalo. Především když jsem se snažil konfiguraci nacpat do ini souboru místo použití parametru v CLI.

Pro OV certifikáty potřebujete nejdříve získat automatizační kódy- acmeURL, idKlíče a hmacKlíč. Ty získáte při registraci doménového jména. V mém případě je to po přihlášení na stránkách TCS CESNET. Myslím, že ostatní CA to budou mít podobně. S těmito kódy můžete vytvořit registraci:

uacme -v -y -a https://acmeURL -e idKlíče:hmacKlíč new

Parametr -v větší ukecanost a -y automatické odsouhlasení pravidel. Pokud vše proběhne správně, v /etc/ss/uacme/private  se vám vytvoří podpisový soubor key.pem. Pak můžeme pokračovat podáním žádosti:

uacme -v -o -a https://acmeURL -e idKlíče:hmacKlíč issue prvníDoménovéJméno dalšíDoménovéJméno

Pokud se vše povedlo, v adresáři uacme se nám objevil podadresář s certifikátem. Parametr -o říká ignoruj OCSP. Pro obnovu certifikátu stačí příkaz spustit znovu, ale protože je certifikát nový, jen nám vypíše, kolik dní je ještě platný. Ve výchozím stavu se certifikát mění 30 dní před vypršením, ale tuhle dobu lze pomocí parametru -d změnit. Když jí změníte třeba na 349 dní, nasimulujete si výměnu. Sám jsem zvědavý, až se začnou certifikáty zkracovat, jestli se ta doba automaticky upraví nebo ji budeme muset upravovat sami ručně. To uvidíme, až to přijde.

Když tohle si dáme do cronu, máme na serveru OV certifikát s automatickou výměnou:

*  *  0 * * root /usr/bin/uacme -o -a https://acmeURL -e idKlíče:hmacKlíč issue prvníDoménovéJméno dalšíDoménovéJméno && systemctl reload apache2.service

Tak a ještě sedmdesátkrát a máme certifikáty na všech serverech. Proto raději použijeme šikovnější centrální řešení.

Poznámka: Každý certifikát má své vlastní automatizační kódy vázané na přesně určená doménová jména. To znamená, že změna doménových jmen (přidání nové domény) změní aktuální ACME kódy. V tom případě je třeba aktuální certifikát, jeho klíč a podpisový klíč smazat. Acme jinak neprovede novou registraci a novou žádost o certifikát. U DV certifikátů jsem se s tímhle nesetkal.

Skripty uacme

Pro práci s certifikáty jsem si vytvořil pomocné skripty uacmeNew a uacmeIssue a textový soubor s automatizačními ACME kódy. Prográmek uacme potřebuje dost parametrů a proto jsem se snažil eliminovat komplikované příkazy.

Automatizační kódy pro všechny certifikáty mám v jednom souboru. Každý řádek znamená jeden certifikát, parametry jsou oddělené mezerami. Tedy kromě HMAC klíče, tam je oddělovačem dvojtečka. Seznam všech domén certifikátu se uvádí na konec řádku. Jméno certifikátu mám použité jako název adresáře, kde je pak certifikát uložen a musí se shodovat s prvním doménovým jménem. Jméno je velmi důležité, protože ho pak používám v konfiguraci Ansible.

automateCodes.txt
jménoCertifikátu acmeUrl idKlíče:hmacKlíč doménovéJméno doménovéJméno...

Skript uacmeNew se používá pro registraci certifikátu u CA a vytvoření podpisového klíče pro komunikaci. Mazání původního adresáře s certifikátem je nutnost. Při změně domén v certifikátu musíte udělat novou registraci. Pokud už jedna registrace na jméno existuje, uacme skončí chybou. Novým parametrem uacme pro centrální řešení, na rozdíl od lokálního, je -c, každý certifikát má svůj vlastní podadresář.

/usr/local/bin/uacmeNew 
#!/usr/bin/bash
if [[ -d "/etc/ansible/roles/certs/files/$1" ]]; then
  rm -r /etc/ansible/roles/certs/files/$1
fi
uacme -v -y -c /etc/ansible/roles/certs/files/$1 -a $2 -e $3 new $4

Pokud skript uacmeIssue nedostane žádné parametry, je v módu obnovy certifikátů a konfigurační parametry si bere ze souboru automateCodes.txt. Obnovu certifikátu a kontaktování CA zkusí, až když je platnost certifikátu kratší než 30 dní. Výstupy sype do systémového logu.

Ale když skript parametry má, požádá o nový certifikát. Výstupy sype do CLI.

/usr/local/bin/uacmeIssue 
#!/usr/bin/bash
if [[ $@ != "" ]]; then
  domeny=`echo -n $@ | awk '{$1=$2=$3="";print $0}'`
  uacme -v -o -c /etc/ansible/roles/certs/files/$1 -a $2 -e $3 issue $domeny
else
  while read radek; do
    certName=`echo -n $radek | awk '{print $1}'`
    url=`echo -n $radek | awk '{print $2}'`
    key=`echo -n $radek | awk '{print $3}'`
    domeny=`echo -n $radek | awk '{$1=$2=$3="";print $0}'`
    if [[ $certName != "" && -d  "/etc/ansible/roles/certs/files/$certName" ]]; then
      uacme -v -o -c /etc/ansible/roles/certs/files/$certName -a $url -e $key issue $domeny 2>&1 | logger -p daemon.notice -t uacmeIssue
    fi
  done < /etc/ansible/automateCodes.txt
fi

Poznámka: Skript kontroluje, že řádek obsahuje název certifikátu a že adresář s certifikátem existuje. Prázdný řádek nebo poznámka je tak přeskočena a negeneruje to zbytečně chyby.

Vytvoření certifikátu

Jak postupuji při vytvoření nového certifikátu?

Školení Zabbix

  • na webových stránkách CA požádám o ACME kódy a ty zapíšu do souboru  automateCodes.txt
  • celý řádek s kódy si zkopíruji do schránky
  • spustím uacmeNew + kódy ze schránky
  • spustím uacmeIssue + kódy ze schránky

V adresáři /etc/ansible/roles/certs/files se mi objeví nový adresář s certifikátem, který nastavím jako cílový stav v Ansible pro ukázkový server.

Příště si ukážeme, jak to celé orchestrovat pomocí nástroje Ansible a jak se připravit na zkracování platnosti certifikátů.

Autor článku

V současné době pracuje jako správce linuxových systémů na Univerzitě Pardubice.