Skript, který spustí OpenVPN a nikdy se nepřipojí, obvykle není problém sítě: klient sedí u výzvy bez terminálu, na kterém by ji vykreslil. OpenVPN má přesně dva podporované způsoby, jak na tuto výzvu odpovědět bez člověka, soubor přihlašovacích údajů za auth-user-pass a řídicí socket, a nejsou zaměnitelné. Soubor stojí jednu direktivu a odpovídá na jednu výzvu; socket odpovídá na každou výzvu a dá čemukoli, co umí otevřít loopback port, neautentizovaný řídicí kanál. Který z nich patří do vašeho nasazení, závisí na tom, která výzva skutečně blokuje, a na tom, které tajemství si můžete dovolit nechat v klidu.

Pojmenujte výzvu, než zvolíte mechanismus

Čtyři výzvy vypadají na terminálu stejně. Pár pro účet přichází z nastavení PAM nebo auth-user-pass-verify na serveru a odpovídá na něj auth-user-pass. Heslová fráze soukromého klíče patří k souboru klíče a čte se přes --askpass nebo se píše ručně. Balík PKCS#12 si žádá vlastní heslo. Proxy autentizace používá soubor auth, který bere --http-proxy, ne přihlašovací údaje účtu.

Když OpenVPN běží jako potomek systemd, PHP nebo Node, není tam terminál, takže kterákoli z nich tiše blokuje. Proces tam sedí, log se zastaví po řádku šifry a jednotka nakonec vyprší; to ticho je důvod, proč lidé přidávají smyčku opakování nebo sleep místo toho, aby se podívali, která výzva čeká. Jen řídicí socket umí odpovědět na všechny čtyři. Soubor přihlašovacích údajů odpovídá na první a na nic jiného.

auth-user-pass: jeden soubor, jedna výzva

Soubor obsahuje uživatelské jméno na prvním řádku a heslo na druhém, a nic jiného: žádné uvozovky, žádné názvy klíčů, žádný komentář. Nastavte režim 600 a vlastníkem udělejte účet, který spouští openvpn, což je u služby často vyhrazený uživatel, ne vaše přihlášení. Soubor vlastněný rootem pod /root je rozdíl mezi příkazem, který funguje ve vašem shellu, a jednotkou, která při startu selže.

Dva detaily promění správný soubor ve výzvu. Editor, který ukládá CRLF, nechá návrat vozíku přilepený k heslu, takže server odmítne heslo, které v souboru vypadá správně; zkontrolujte pomocí cat -A nebo od -c, ne okem. A auth-user-pass bez argumentu uvnitř profilu znamená podle návrhu «zeptej se uživatele», což druhá direktiva na příkazovém řádku nemusí přebít, protože profil se parsuje tam, kde leží.

Pořadí voleb je třetí past a závisí na verzi. Některá sestavení OpenVPN 2.4 ignorují --auth-user-pass, když se objeví před --config, takže stejné dvě volby v opačném pořadí se připojí. Umístěte direktivu do profilu, nebo za --config na příkazovém řádku, a před jakoukoli další změnou prohledejte profil na každý výskyt.

auth-nocache patří k tomuto mechanismu, ale nic nedodává. Omezuje, jak dlouho klient drží údaje v paměti, což pomůže po pádu a vůbec ne, když soubor chybí. Opětovné připojení po vypršení relace na straně serveru soubor znovu načte, takže údaje, které při startu fungovaly, mohou přesto vypršet uprostřed dne.

Řídicí socket: každá výzva, větší povrch

Spusťte klienta s posluchačem a výslovně uveďte, že výzvy se budou hlásit na něm, pomocí direktiv dokumentovaných v manuálu OpenVPN 2.6:

management 127.0.0.1 3030
management-query-passwords

V bashi držte spojení na volném deskriptoru souboru a odpovídejte podle názvu výzvy, ne podle pozice, protože opětovné připojení se může zeptat v jiném pořadí:

exec 3<>/dev/tcp/127.0.0.1/3030
while read -r -u 3 line; do
  case "$line" in
    *"Need 'Auth' username/password"*)
      echo 'username "Auth" alice' >&3
      echo 'password "Auth" secret' >&3 ;;
    *"Need 'Private Key' password"*)
      echo 'password "Private Key" secret' >&3 ;;
  esac
done

Hranicí je přenos. Řídicí protokol je prostý text přes TCP na loopbacku, takže posluchač nesmí být publikován na adrese LAN nebo tunelu, aby se k němu dostal vzdálený správce; vzdálený správce znamená SSH přesměrování, ne širší navázání. Komunitní démon také přijímá jen jednoho řídicího klienta najednou, takže GUI nebo monitor nemohou socket sdílet s vaším skriptem. Druhé spojení je odmítnuto, ne zařazeno do fronty, a selhání vypadá jako skript, který ohluchl.

Tento socket je také řídicí kanál. Bez řídicího hesla může cokoli, co se umí připojit k 127.0.0.1:3030, číst stav, zabít tunel nebo samo odpovědět na výzvu. Řídicí heslo a soubor přihlašovacích údajů jsou tajemství stejné třídy a obě si zaslouží stejnou péči.

Který se hodí k nasazení

Zvolte soubor přihlašovacích údajů, když je jedinou výzvou pár pro účet, klient běží jako služba se stabilním vlastníkem a můžete držet soubor 600 mimo zálohy, které nekontrolujete. Zvolte řídicí socket, když je ve hře heslová fráze klíče nebo heslo PKCS#12, když obal už proces dohlíží, nebo když potřebujete sledovat stav a výzvy při ladění opětovného připojení.

Dvě podmínky hýbou rozhodnutím. Pokud je obalem /bin/sh, jednotka systemd, která volá binárku přímo, nebo minimální kontejner, lepidlo socketu jen pro bash není k dispozici a soubor je levnější odpověď. Pokud se tajemství často mění, žádný ze souborů pro ně není dobrým domovem: vyžádejte klíčenku z malého obalu a nechte jednotku volat obal, což drží rotaci na jednom místě a heslo mimo historii shellu.

Nahrazení procesu stojí mezi oběma a nepatří ani jednomu. Jednořádkový příkaz níže funguje, protože jej bash rozvine před spuštěním openvpn, ne proto, že by klient rozuměl syntaxi:

openvpn --config client.ovpn --auth-user-pass <(printf "%s
%s
" "$USER" "$PASS")

Selhává pod /bin/sh, v jednotce, která obchází shell, a v obrazech bez bashe nebo /dev/fd. Ponechte jej pro interaktivní testování, nikdy jako smlouvu, na níž služba závisí.

Chraňte tajemství, pak ověřte z logu

Oba mechanismy zanechávají tajemství čitelné pro proces OpenVPN. Nikdy nedávejte heslo na příkazový řádek ani do souboru jednotky, kde je ps a systemctl ukážou každému místnímu uživateli; předejte cestu k souboru, ne hodnotu v něm. Tam, kde certifikáty mohou nahradit pár pro účet, to odstraňuje kategorii výzvy místo jejího skrývání.

Správný běh ukazuje dokončení sledu výzev a relaci dosahující «Initialization Sequence Completed». Pokud se klient zastaví na stejné výzvě, porovnání selhalo: vytiskněte přesné řádky, které socket poslal, zkontrolujte uvozovky a název výzvy a opravte vzor místo přidávání sleepu. Tunel, který hlásí úspěch a nic nepřenáší, je problém směrování nebo push, ne přihlašovacích údajů.

Pak otestujte opětovné připojení, ne jen první start. Zrušte relaci na straně serveru nebo počkejte na její vypršení; klient se zeptá znovu, a právě tam soubor, který při startu vypadal správně, ukáže, zda je pro účet, který se znovu připojuje, stále čitelný.

Související články