Disassembler

Artificial intelligence is no match for natural stupidity.
07březen2018

Vzdálené odemykání šifrovaných systémů


Za chvíli nám začne platit GDPR v plné parádě a tak spousta administrátorů v malých a středních podnicích ještě narychlo zjišťuje, co se po nich vlastně chce, a na poslední chvíli šifrují, heslují nebo jinak zabezpečují záležitosti, které se do té doby nijak zvlášť neřešily. Ani mě radosti se zvyšováním bezpečnosti neminuly. Největším oříškem pro mne však bylo přijít na způsob, jakým se dá na linuxu (Ubuntu) šifrovat komplet celý systém a data pomocí LVM-on-LUKS, ale zároveň nevyžadovat fyzickou přítomnost při startu a zadávání hesla. S vymoženostmi jako IPMI, iLO nebo jinými KVM-over-ethernet je to jednoduché, ale ty na malých serverech nemám a tak si musím poradit jinak.

Když už, tak pořádně


Nejprve jsem přemýšlel, co všechno hodlám šifrovat. Provozuju nějaké mailové, webové a souborové servery, takže bylo jasné, že pod zámek musí jít veškerá uživatelská data. Ta sice existují převážně jako jednotlivé soubory v souborovém systému, ale zároveň některé služby mají metadata, repozitáře uživatelů nebo logy přístupů a akcí uloženy i v databázích. To tedy efektivně znamená, že musím vyloučit prakticky všechny služby, které nejsou nezbytně nutné k tomu, aby se server vůbec rozběhl, a až se milostivě rozběhne, stejně se na něj musím přihlásit, datový oddíl ručně odemknout a služby spustit.

Naskýtala se možnost udělat to tak, aby se vlk nažral a koza zůstala celá. Šifrovací klíč k datovému oddílu uložit v systému a nechat startovací sekvenci, ať si vše odemkne sama. Pak bych mohl tvrdit, že mám data šifrovaná, ale skutečný bezpečnostní přínos by byl nulový, protože kdokoliv nepovolaný, kdo viděl linux alespoň na obrázku v časopise, by se k nim stejně dostal. A nějaké tanečky kolem uzamykání zavaděče nebo silného rootovského hesla taky smysl moc nemají. Přestože silná hesla samozřejmě jsou extrémně důležitá, zavaděč se prostě dá nastartovat z jiného média a jakákoliv hesla bez patřičného šifrování, včetně rootovského, se dají prostě resetovat. Stručně řečeno, opět platí poučka, že pokud je počítač schopen něco dešifrovat, odemknout nebo spustit automaticky, může to stejným způsobem udělat i útočník. Pokud se útočníkovi podaří získat fyzický přístup (nebo v případě virtuálek přístup k hypervizoru), automaticky se dá počítat s tím, že je schopen získat nejvyšší možné oprávnění. Jediný způsob jak tomu zabránit, je obsah zašifrovat a dešifrovací klíč uložit mimo hostitele, přičemž slovo uložit zde má velmi volný výklad, protože může být uloženo klidně jen v něčí hlavě.

No, takže když mám v plánu šifrovat skoro všechno, tak můžu stejně tak dobře šifrovat úplně všechno.

Vejce a slepice


Potřeboval jsem tedy najít způsob, jak bych mohl vzdáleně zadat heslo pro dešifrování systémového oddílu. Linux bootuje tím způsobem, že při startu počítače BIOS + MBR příslušného disku nebo EFI (stage 1 bootloader) ukáže kamsi do /boot oddílu, nastartuje se zavaděč (stage 2 bootloader, typicky grub), který pak může dál předat řízení dalšímu zavaděči nebo začne rovnou načítat kernel a moduly potřebné k ovládání veškerého hardwaru a abstrakce nad ním postavené. Linux má tyto ovladače a moduly úhledně zabalené do balíčku, který při startu rozbalí do operační paměti a spustí sekvenci skriptů, která je v něm připravena a která by měla vést k úspěšnému zavedení systému. Právě proto, že se tento balíček rozbaluje do operační paměti, jmenuje se Initial RAMdisk, zkráceně initrd. V deb-based distribucích se taky označuje jako initramfs. Sekvence skriptů v něm pak nahraje všechny potřebné ovladače, připojí disky, nastartuje síť a udělá ještě hromadu dalších low-level opičáren a až je vše hotovo, předá řízení do userspace, kde už se o zbytek parády stará init (SysV init, Systemd, OpenRC, Upstart nebo cokoliv jiného, dle vašeho vyznání). Mluvím o tom proto, aby bylo milému čtenáři jasné, že právě initrd je ta komponenta, která se dožaduje dešifrovacího klíče, aby mohla namapovat všechna zařízení a připojit všechny diskové oddíly předtím, než se z nich init začne pokoušet spouštět služby. Cílem mého snažení tedy nebude nic jiného, než vnutit do initramfs SSH server a nějaké nastavení kolem networkingu, abych mohl kýžený klíč zadat i z gauče.

Zubatá koala


Debiani a Ubuntu mi v tomto směru udělali velkou radost, protože obrovský kus práce je v repozitářích připraven a čeká pouze na nainstalování a následné drobné učesání konfigurace. Pointou initrd, resp. initramfs je být co nejmenší a nejrychlejší. Proto Debian nenabízí k integraci klasický OpenSSH server, ale místo toho poskytuje Dropbear. Jedná se o lehkou alternativu k OpenSSH, hojně využívanou například v routerech a embedded zařízeních společně s busybox shellem. Dropbear samotný se dá nainstalovat i jako náhrada za OpenSSH v samotném Debianu nebo Ubuntu, ale to dělat nechci, takže nainstaluju jen konkrétní balíček pro integraci do initramfs společně s jeho nutnými závislostmi.

apt-get install dropbear-initramfs

95 % práce je hotovo. Složité, že? Nebojte se, ještě nekončíme. Dále je potřeba medvídka nakrmit SSH klíči. Integrovatelná varianta totiž nepoužívá klasické umístění /root/.ssh/authorized_keys ale místo toho klíče tahá z /etc/dropbear-initramfs/authorized_keys v Ubuntu Bionic (18.04) nebo z /etc/initramfs-tools/root/.ssh/authorized_keys v Ubuntu Xenial (16.04). Syntaxe souboru je ale úplně stejná, takže pokud jste na systému jediným administrátorem, je možno soubor jednoduše zkopírovat. Hipsteři s Ed25519 klíčem ale mají smůlu, protože tyhle medvěd nežere. RSA, DSA a ECDSA s NIST křivkami však zbaští ochotně.

Sezame otevři se


SSH server sice máme nastavený, ale ještě by to chtělo se na něj nějak dostat. I v tom nám Debian se svými initramfs nástroji vychází vstříc a předá za nás patřičné parametry kernelu. Stačí editovat soubor /etc/initramfs-tools/initramfs.conf a fláknout do něj řádek

IP=:::::eth0:dhcp

To hejno dvojteček tam není jen tak z plezíru. To je prostě jen hromada nenastavených parametrů, protože chci všechno brát z DHCP. Parametry jsou IP klienta:IP NFS serveru:gateway:maska:hostname:interface:autoconf:DNS1:DNS2 s tím, že na konci se prázdné dvojtečky už nemusí psát a celá část se může vynechat. Pro konkrétní povolené hodnoty můžete konzultovat dokumentaci pro nfsroot. Statickou adresu bych nastavil následovně

IP=192.168.1.123::192.168.1.1:255.255.255.0:mujserver:eth0:off

Zvýšenou pozornost také věnujte názvu vašeho síťového zařízení. Initramfs používá udev a tedy i názvy přidělené v udev pravidlech v ostrém systému. Na mé virtuálce by to tedy nebylo eth0 ale ens33. Také opět připomínám, že initramfs je pouze prostředím k provedení sekvence skriptů a ideálně by žádné nastavení neměl nepřenášet do userspace. Jedním ze skriptů na konci běhu initramfs je tedy i vypnutí Dropbear daemona (alespoň v Bionicu. V Xenialu zůstane až do odhlášení SSH session) a deregistrace IP adres a vypnutí síťových zařízení. Až se systém přehoupne do userspace, přihlásí se o slovo opět vaše obvyklé síťové nastavení, které může být úplně odlišné.

Co se týká samotného zadávání hesla pro odemknutí disku, Debian Stretch a Ubuntu Bionic se opět pokouší udělat nudnou práci za nás a poskytují v initrd prostředí skript s názvem cryptroot-unlock. Nicméně tento skript je stále ve vývojové fázi a snaží se používat některé aplikace a přepínače, které v initramfs prostředí nejsou dostupné, takže doporučuji jej zatím ještě nepoužívat a napsat si pro zadávání hesla vlastní jednoduchý wrapper. Do souboru /etc/initramfs-tools/hooks/unlock.sh šoupněte následující obsah

#!/bin/sh

PREREQ="dropbear"
prereqs() {
    echo "${PREREQ}"
}

case ${1} in
    prereqs)
        prereqs
        exit 0
        ;;
esac

cat >"${DESTDIR}/bin/unlock" <<EOF
#!/bin/sh
/lib/cryptsetup/askpass "Enter password: " >/lib/cryptsetup/passfifo
EOF
chmod +x "${DESTDIR}/bin/unlock"

A učiňte jej spustitelným

chmod +x /etc/initramfs-tools/hooks/unlock.sh

Na samotný závěr už jen stačí znovu sestavit initramfs obraz a máme vystaráno.

update-initramfs -u

Užití


Při následujícím rebootu přibude v konzoli pár hlášek o nastavení IP adresy. Pokud jste vše udělali správně, budete moci přistoupit po SSH do busyboxového terminálu běžícího v initramfs. Tam spustíte výše uvedený wrapper příkazem unlock, zadáte heslo a protože sled skriptů se tím odblokuje, initramfs vám zanedlouho SSH server sebere pod rukama a spustí systém z šifrovaného disku. Nic víc není třeba dělat. Snad už jen odškrtnout si kolonku z inkvizitivního formuláře GDPR, protože šifrování máte splněno na jedničku.