Disassembler

Artificial intelligence is no match for natural stupidity.
03června2017

MikroTik SSTP server s Let’s Encrypt certifikátem


Nebojte se, žádná velká magie s RouterOSem se nekoná. MikroTiky bohužel umí certifikáty vyměňovat jen pomocí nestandardizovaného SCEP. Let’s Encryptí ACME vůbec neumějí a skriptovací jazyk RouterOSu je natolik strašný a omezený, že se v něm reálně žádný jednoduchý ACME klient vyrobit nedá. Popíšu tedy, jak tyto nedostatky obejít pomocí linuxového stroje a mého oblíbeného ultralehkého Let’s Encrypt ACME klienta v kombinaci se SSH a Apache HTTP Serverem. Tyto komponenty budou dělat celou špinavou práci a RouterOS už si jen přijde k hotovému. Samozřejmě je podobnou anabázi možno absolvovat i s Windows Serverem, ale já mám daleko radši servery linuxové, takže budu operovat s tím, co mám k dispozici.

Důvěřuj, ale prověřuj


Možná to znáte. To takhle máte někde nějakou malou firmičku a v ní MikroTik a hejno počítadel. A když uživatel počítadlo rozbije, tak si ho vezmete domů a ve volném čase přeinstalujete a nastavíte. Ale ouha, ve firmičce je i server, na něm nějaká data, účetnictví a bůh ví co ještě, takže by to chtělo, aby počítač u vás doma zároveň dosáhl i do firmy a vy nemuseli strávit celý den ježděním tam a zpět a dokončováním nastavení na místě. Jede-li firma na Windowsových pracovních stanicích a laptopech, nabízí se sestavení VPN pomocí SSTP protokolu, který Windows nativně umí od Vista SP1 a RouterOS od verze 5.

SSTP je dílem Microsoftu, což může mnohé odradit, ale musím říci, že tenhle protokol je elegance sama. Tak především se z venku tváří jako obyčejné HTTPS. Nejen že jako výchozí port používá 443, který je povolený téměř na všech firewallech, ale i samotné požadavky a odpovědi na vyjednání spojení vypadají jako HTTP. Díky tomu je i poměrně přizpůsobivý a funguje s klasickými, dobře známými a prověřenými algoritmy (AES, SHA2) a PPP autentizačními metodami (EAP-TLS, MS-CHAP, ale i obyčejný PAP a CHAP). Také, stejně jako další služby založené na TLS, i SSTP používá digitální certifikáty k ověřování autenticity během navazování spojení (ale nemusí, nicméně SSTP bez certifikátů silně nedoporučuju, protože je náchylné k Man-in-the-Middle útokům). Windows jsou, navzdory své pohnuté minulosti, relativně bezpečným systémem, a pokud mají navázat spojení se stranou prokazující se TLS certifikátem, bezpodmínečně vyžadují jeho důvěryhodnost. Tady právě přichází na řadu náš Let’s Encrypt. Jeho kořenový certifikát je Windowsům již znám a důvěřují mu, takže na služby používající jím podepsaný certifikát se připojí bez keců. Samozřejmě se dá operovat i se self-signed certifikáty nebo vlastní certifikační autoritou, ale pak musíte Windows ohýbat přes koleno, importovat certifikát do systémového úložiště a hlídat jeho exspiraci vlastními silami.

Wile E. Coyote


Let’s Encrypt ověřuje vlastnictví domény pomocí challenge-response mechanismu. Existují tři možnosti, jak doménu nechat ověřit. Ta nejběžnější (alespoň v mých kruzích) se nazývá http-01 a funguje tak, že ACME klient při žádosti o certifikát dostane od ACME serveru (Let’s Encrypt) za úkol vystavit na webu soubor s určitým názvem a obsahem. Server si na něj poté přes internet zkusí sáhnout a pokud se mu to podaří, má se za to, že ověření vlastnictví bylo úspěšné a žádost o certifikát podepíše. Druhá varianta zvaná dns-01 pak používá DNS záznam typu TXT, který je třeba nastavit tak, jak vám sdělí ACME server. Tato varianta tedy nepotřebuje žádný webový server nebo port přístupný zvenčí, a pokud je doména navíc podepsaná DNSSECem, je zdaleka nejbezpečnější. Bohužel se ale nejhůře automatizuje, protože challenge je při každé obnově jiná a je tedy pokaždé nutno DNS záznam upravit. Pokud ale máte vlastní DNS server nebo hostujete doménu u někoho s rozumným API, není to nemožné. Třetí a pravděpodobně nejméně využívanou variantou, je tls-sni-01, kdy má klient žádající o certifikát za úkol nastavit SNI konfiguraci HTTPS serveru na hodnotu sdělenou opět ACME serverem. Ten potom naváže TCP spojení na hostname v požadovaném certifikátu, ale požádá o úplně jiný SNI název. Pokud HTTPS server požadavku porozumí a spojení sestaví, ověření bylo úspěšné.

Pro Let’s Encrypt a ACME protokol existuje hromada klientů. Já osobně mám nejraději takové, které pro nějaké pitomoučké posílání HTTP requestů a volání OpenSSL knihovny nepotřebují 50 MB závislostí, takže používám acme.sh. Jedná se o naprosto kouzelného klienta. Nejen, že mimo přítomnosti openssl a curl binárek nepotřebuje nic dalšího, ale navíc je celým klientem jediný soubor psaný přímo v POSIX-compliant shellu, takže může vesele běžet i na BSD, AIXu, Solarisu nebo třeba v Cygwinu. I jeho instalace a použití je triviálně jednoduché. Jelikož hodlám pro žádání certifikátů používat http-01, musím si nejprve trochu prošlapat cestičku v konfiguraci Apache.

Kryptografická skládačka


Mimo samotné přítomnosti linuxové mašinky s Apache HTTP Servererm budu ještě předpokládat, že IP adresa, na které je websever dostupný, je shodná s IP adresou budoucího SSTP VPN serveru. Jako příklad budu používat název vpn.example.com. Celé moje řešení spočívá v tom, že na Apachi bude sedět virtualhost pro danou VPN subdoménu na portu 80 (HTTP). Jakmile ACME klient obdrží podepsaný certifikát, spustí skript, který za použití scp a SSH klíčů natlačí nový certifikát včetně privátního klíče na MikroTik. Na tom pak bude naplánovaný další skript, který jednou za čas koukne, zda nepřišel nějaký nový certifikát a pokud ano, zahodí starý, nainstaluje nový a nastaví jej jako výchozí pro SSTP server. Tak jedeme.

Nejprve je třeba povolit NAT na portu 80 a nastavit DNS záznam pro vpn.example.com. To nijak do detailu popisovat nebudu, protože předpokládám, že domény hostujete u registrátorů s nějakým pěkným klikacím rozhraním. Dalším krokem je nastavení onoho virtualhosta na Apachi. To by měla být celkem brknačka.

<VirtualHost *:80>
    ServerName vpn.example.com
    DocumentRoot /srv/vpn
    <Directory /srv/vpn>
        Require all granted
    </Directory>
</VirtualHost>

Po reloadu Apache by měl začít odpovídat na http://vpn.example.com, což je možno otestovat podstrčením nějakého obsahu do /srv/vpn/index.html. Pozor, nezaměňujte /srv/vpn, což by měl být prázný adresář, sloužící pouze potřebám pro umístění response ACME klienta a /opt/vpn, což bude umístění pro všchny konfigurace, skripty, certifikáty a klíče. Adresář /opt/vpn v žádném případě nesmí být dostupný skrze webový server a už vůbec ne přes nezabezpečené HTTP.

Pokračovat budeme žádostí o certifikát. Klienta acme.sh je možno stáhnout přímo z GitHubu. Dokonce má jakýsi instalační mód, ale ten se mi zdá poněkud obtruzivní, protože modifikuje .bashrc a crontab, takže jej nepoužívám a nastavuji si jej po svém. Pro potřeby tohoto článku bude veškeré nastavení spočívat pouze v přidání --home /opt/vpn ke všem jeho příkazům.

mkdir /opt/vpn
wget https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh -O /opt/vpn/acme.sh
chmod u+x /opt/vpn/acme.sh
/opt/vpn/acme.sh --home /opt/vpn --issue -d vpn.example.com -w /srv/vpn

Pokud všechno klaplo, objeví se v /opt/vpn/vpn.example.com hromádka souborů, z nichž nás zajímá zejména fullchain.cer a vpn.example.com.key. První soubor obsahuje podepsaný koncový certifikát a také mezilehlý certifikát, který jej podepsal. V druhém se pak nalézá soukromý klíč potřebný k tomu, aby se koncovým certifikátem bylo možno prokazovat.

Teď tedy musíme vymyslet, jak soubory dopravit na MikroTik. V perexu už jsem se prořekl, že se budou používat SSH, takže teď je dobrá příležitost pro jeho nastavení. Nejdříve na linuxovém stroji klíč vygeneruji. Komponenty RouterOSu jsou bohužel strašlivě zastaralé, takže umí používat jen RSA a DSA klíče a pro vzdálený přístup bez hesla je možno použít pouze RSA.

ssh-keygen -t rsa -b 2048 -f /opt/vpn/vpn-ssh-key

Soubor /opt/vpn/vpn-ssh-key.pub pak libovolnou vhodnou metodou přeneste na MikroTik. Tam zapněte SSH, pokud ještě není, a naimportujte veřejnou část SSH klíče pro uživatele, pod kterým se budou certifikáty nahrávat (ne že by na tom vzhledem k prapodivnému systému oprávnění MikroTiku záleželo).

/ip service enable ssh
/ip ssh set strong-crypto=yes
/user ssh-keys import public-key-file=vpn-ssh-key.pub user=admin

Samozřejmě, pokud máte v cestě nějaká další bezpečnostní opatření, jako třeba firewall zakazující přístup na port 22 nebo rozsah adres povolených pro přihlášení skrze SSH, je třeba je adaptovat, aby se linuxový server dokázal připojit. Pokud tedy MikroTik sedí na lokální adrese 192.168.88.1 a příkaz

ssh -i /opt/vpn/vpn-ssh-key admin@192.168.88.1

Funguje a bez keců se připojí na MikroTik, můžeme přejít k první části automatizace. Náš malý acme.sh totiž umí cron mód, kdy automaticky kontroluje platnost všech nakonfigurovaných certifikátů a také umí po každé obnově a při každé instalaci nového certifikátu automaticky spustit skript. Ideální featura pro navěšení jednoduché rutiny na odeslání certifikátu a privátního klíče. Vytvořte tedy /opt/vpn/upload-cert.sh s následujícím obsahem

#!/bin/sh
scp -i /opt/vpn/vpn-ssh-key /opt/vpn/vpn.example.com/fullchain.cer admin@192.168.88.1:/vpn.pem
scp -i /opt/vpn/vpn-ssh-key /opt/vpn/vpn.example.com/vpn.example.com.key admin@192.168.88.1:/vpn.key

A povolte jeho spouštění

chmod u+x /opt/vpn/upload-cert.sh

Pak oznamte acme.sh, že při instalaci certifikátu má spouštět právě tento skript.

/opt/vpn/acme.sh --home /opt/vpn --installcert -d vpn.example.com --reloadcmd /opt/vpn/upload-cert.sh

Kouknete-li v tuto chvíli do MikroTiku, měli byste ve Files vidět soubory vpn.pem a vpn.key. Pokračujme tedy nastavením SSTP serveru. Ten ve výchozím stavu naslouchá na portu 443 (HTTPS), ale protože hrozí, že HTTPS bude využíváno i samotným webovým serverem, přesunu SSTP server třeba na port 8443. SSTP klientům budou přidělovány adresy ze stejného DHCP poolu jako lokálním klientům. Opět platí, že pokud firewallujete, může být potřeba nějaká dodatečná konfigurace.

/interface sstp-server server set enabled=yes port=8443
/ppp profile add dns-server=192.168.88.1 local-address=192.168.88.1 name=sstp remote-address=pool1
/ppp secret add name=klient password=SuperTajneHeslo profile=sstp service=sstp

V tuto chvíli SSTP server běží a přijímá spojení, a to i přesto, že ještě nebyl nakonfigurován žádný certifikát. Jak jsem zmínil výše, certifikát samotný není k běhu SSTP potřeba, ale v takovém případě se k výměně sdíleného symetrického šifrovacího klíče používá varianta Diffie-Hellman protokolu zvaná DH_anon, kterou každý pologramotný záškodník umí zachytit a přetvořit k obrazu svému. Právě certifikát něčemu takovému dokáže zabránit a zajistí, že si klient bude moci ověřit, kdože mu vlastně posílá data. V MikroTiku tedy stvoříme skript, který koukne, zda náhodou nepřišly nové certifikáty (které náhodou přišly) a do SSTP serveru je nainstaluje. Nový skript tedy pojmenuju třeba vpn-cert-refresh a jako obsah vložím

:if ([:len [/file find name=vpn.pem]] > 0) do={ 
    /certificate remove [find name=vpn.pem_0]
    /certificate import file-name=vpn.pem passphrase=""
    /certificate import file-name=vpn.key passphrase=""
    /interface sstp-server server set certificate=vpn.pem_0
    /file remove vpn.pem
    /file remove vpn.key
}

Nakonec skript jednou ručně spustím

/system script run vpn-cert-refresh

Naplánuju automatické spouštění každou hodinu

/system scheduler add name=vpn-cert-refresh on-event="/system script run vpn-cert-refresh" start-date=jun/01/2017 start-time=00:30:00 interval=1h

A ještě přihodím cron skript pro automatizaci obnovy certifikátu skrze acme.sh na linuxový server

echo "0 0 * * * root [ -x /opt/vpn/acme.sh ] && /opt/vpn/acme.sh --home /opt/vpn --cron >/dev/null" > /etc/cron.d/vpn-cert-refresh

Hotovo.

Dodatek ke konfiguraci Windows


Jakmile jednou na libovolné Windowsovské klientské stanici nastavíte SSTP spojení a důkladně jej vyladíte k obrazu svému (například nastavíte doménové suffixy nebo upravíte routování a metriku), pravděpodobně budete chtít nastavení exportovat, aby jej bylo možno použít i na jiných počítačích. Nevím o žádné jednoduché metodě, jak se dá exportovat nastavení jediné definice VPN, ale pokud jich na počítači více nastavených nemáte, pak jednoduše přejděte do umístění %AppData%\Microsoft\Network\Connections\Pbk a vyzobněte si zde soubor rasphone.pbk. Ten pak můžete přejmenovat a bezpečně distribuovat, protože obsahuje pouze informace o protokolech a koncových bodech, ale není v něm uloženo jméno ani heslo.