Jenom SFTP
Ačkoli o tom ještě nepadla zmínka, nepochybuji že všichni čtenáři vědí o tom, že pomocí protokolu SSH je možné přenášet soubory. Funguje to tak, že klientská aplikace (například scp
, sftp
, lftp
, nebo třeba sshfs
) komunikuje pomocí SSH spojení s programem sftp-server
, který na základě přání klienta prochází adresáře, čte, vytváří a maže soubory. Ve skutečnosti je SFTP server zabudován přímo v OpenSSH serveru, což výrazně usnadňuje uzamykání uživatelů v chrootu.
Pojďme například vytvořit uživatele uploader, který bude mít přístup jen pomocí SFTP a navíc bude omezen pouze na svůj domovský adresář. Nejprve založíme domovský adresář a vytvoříme uživatele:
# mkdir -p /home/uploader/upload # useradd -s /bin/noshell -M -c "Ucet pro Upload" -d /home/uploader uploader # chown uploader:uploader /home/uploader/upload
Jméno shellu noshell
ukazuje na prázdný spustitelný soubor, který je vyjmenovaný v souboru /etc/shells
jako povolený shell. To proto, že při autentizaci heslem je kontrolováno, zda má dotyčný uživatel platný shell. Pokud nehodláme používat autentizaci heslem, můžeme bez obav použít jako shell /bin/false
.
Dále přidáme speciální nastavení SSH serveru pro daného uživatele. Zakážeme všechna přesměrování a tunely a vnutíme uživateli jako jediný povolený příkaz internal-sftp
, tedy vestavěný SFTP server. Do souboru /etc/ssh/sshd_config
přidáme na konec:
Match User uploader X11Forwarding no AllowAgentForwarding no AllowTcpForwarding no ForceCommand internal-sftp ChrootDirectory %h
Abychom měli jistotu, že uživatel nepřečte žádná data, u kterých si to nepřejeme, uzamkneme ho pomocí volby ChrootDirectory v jeho domovském adresáři. Z bezpečnostních důvodů není povoleno, aby uživatel vlastnil adresář, ze kterého se později stane kořenový. Proto jsme založili uživatelem vlastněný podadresář upload
, do kterého může uploader bez problému zapisovat.
Jenom tunel
Další, poměrně snadno řešitelnou úlohou, je použití SSH jen pro vytvoření tunelovaného spojení. Například můžeme pomocí SSH tunelu umožnit přístup na firewall a z něj dále do vnitřní sítě, aniž bychom umožňovali uživatelům přístup na firewall samotný.
Opět použijeme direktivu ForceCommand
, pomocí které uživateli vnutíme příkaz, který nic nedělá, jako třeba /bin/false
. Dále můžeme direktivou PermitOpen
omezit adresy a čísla portů, na které je možné tunelované spojení navázat. Nastavení v konfiguračním souboru serveru by mohlo vypadat nějak takto:
Match User fwuser X11Forwarding no AllowAgentForwarding no AllowTcpForwarding yes ForceCommand /bin/false PermitOpen 10.0.0.1:22
Není ale dokonce ani nutné pro každého tuneláře vytvářet nový systémový účet. S výhodou můžeme použít omezujících voleb souboru authorized_keys
. Příslušná omezení vložíme před veřejný klíč daného uživatele:
command="/bin/false",permitopen="10.0.0.1:22" ssh-dss AAAAB…= id_dss_fwuser
Pokud se uživatel přihlásí klíčem uvedeným na daném řádku, je mu povoleno navázat tunel jen na adresu 10.0.0.1 a port 22. Jeden systémový účet může takto bez problému sdílet mnoho různých uživatelů a každý může mít ke svému klíči přiřazeno oprávnění k navázání tunelu na jiný server. Poněkud nepříjemné je, že direktiva PermitOpen
nepodporuje expanzi žolíkových znaků, takže je nutné všechny povolené kombinace adres a portů vyjmenovat.
SSH matrjoška aneb spojení uvnitř spojení
Pomocí výše uvedeného SSH tunelu je možné tunelovat SSH spojením druhé SSH spojení přímo na cílový stroj za firewallem. Na rozdíl od klasického přestupování zřetězením ssh klientů ( ssh firewall ssh server
) není vnitřní SSH spojení na firewallu rozšifrováno, takže jej můžeme považovat za bezpečné i v případě, kdy nemáme důvěru ve firewall a jeho správce. Tedy samozřejmě za předpokladu, že věrohodně ověříme veřejný klíč serveru.
Na straně klienta můžeme takové dvojité spojení snadno navázat využitím direktivy ProxyCommand
a tzv. netcat režimu ssh s přepínačem -W
. Do konfiguračního souboru klienta vložíme:
Host server-behind-firewall ProxyCommand ssh -W 10.0.0.1:22 -i ~/.ssh/id_dss_fwuser fwuser@firewall.example.com
Spojení na server za firewallem navážeme jednoduše použitím názvu server-behind-firewall
na místě adresy serveru v jakémkoli programu, který používá SSH (tedy i např. scp
, rsync
, git
, atd.). Direktiva ProxyCommand
má i další zajímavá využití, rozhodně doporučuji její možnosti prozkoumat.
Omezujeme VPN uživatele
Stejně jako přesměrované TCP porty, můžeme omezit použití SSH VPN, o které jsme psali ve druhém díle seriálu. Manuálová stránka sshd(8) uvádí následující příklad:
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA…= jane@example.net
Protože tun-zařízení vznikne až po navázání SSH spojení a je jej poté třeba nakonfigurovat, využijeme k tomu s výhodou opět direktivu ForceCommand
. Klientovi s daným klíčem přiřadíme pevně určené číslo tun-zařízení a ke spuštění vnutíme skript, který nastaví IP adresy a směrování na straně serveru. Vnucený skript také zabrání tomu, aby uživatel, který navazuje tunel, získal na straně serveru plnohodnotný shell superuživatele.
Certifikáty v akci
Použití uživatelských SSH certifikátů, které jsme představili v minulém díle seriálu, představuje další možnosti omezení činností uživatele. Většinu omezení, která je možné definovat na řádku v souboru authorized_keys
, je možné definovat i při vystavování certifikátu:
$ ssh-keygen -s key-exampleCA -I user@example.com -O force-command="internal-sftp" \ -O no-port-forwarding -n uploader id_dsa.pub
Při přijetí certifikátu SSH klient provede logický součet všech zadaných omezení, takže uživateli jsou povoleny pouze ty akce, které nejsou zakázány ani v konfiguračním souboru serveru, ani v souboru authorized_keys
, ani v certifikátu.
Jenom shell
Může se zdát, že omezení uživatele, aby mohl SSH využívat pouze k terminálovému přístupu, je stejně snadné – prostě v konfiguraci zakážeme všechna tunelování. Opak je ale pravdou. Jak správně upozorňují manuálové stránky, veškerá omezení možností tunelování jsou účinná pouze tehdy, nemá-li uživatel zároveň přistup k shellu. V opačném případě si totiž uživatel může příslušná přesměrování zajistit ručně. Například o kus výše představený netcat režim SSH klienta lze při zakázaném tunelování zcela ekvivalentně nahradit dálkovým voláním programu netcat:
Host server-behind-firewall ProxyCommand ssh -T -i ~/.ssh/id_dss_fwuser fwuser@firewall.example.com netcat 10.0.0.1 22
Jiným příkladem může být návod, jak obejít zakázaný TCP forwarding u SSH místního čtenáře Tomáše Mudruňky. Ten nahradil nefunkční dynamické tunelování tak, že na místní straně nástrojem socat přesměroval spojení z lokálního TCP portu do SSH klienta, který na vzdálené straně spustil SOCKS server v tzv. inetd režimu. Takže SOCKS server místo poslouchání na soketu používá standardní vstup a výstup, ten projde SSH spojením a na straně klienta jej nástroj socat přesune na místní otevřený soket.
Jedinou možností, jak zneužití bránit, je neumožnit uživateli na vzdáleném systému spouštět vlastní kód. Toho lze částečně dosáhnout tak, že uživatelsky zapisovatelné adresáře připojíme s parametrem noexec, takže uživatel nemůže spustit svůj vlastní binární kód. Ani taková ochrana není příliš účinná, nebrání ve spouštění skriptů, které toho na UNIXovém systému dokáží poměrně hodně.
Osobně se domnívám, že tudy cesta nevede. Mezi legitimním užitím shellového účtu a jeho zneužitím je velmi tenká hranice. Takže pokud bychom systém kompletně zabezpečili proti zneužití, pravděpodobně se zároveň stane nepoužitelným. Doporučuji tedy raději zvážit, zda daný uživatel skutečně potřebuje přístup k shellu. Pokud ano, pak je třeba s rizikem zneužití počítat.
Závěr
V dnešním článku jsme si popsali některé zajímavé scénáře, jak je možné omezit funkčnost SSH pouze pro vybraný účel. Možností je samozřejmě mnohem víc. Používáte nějaké speciální nastavení OpenSSH? Podělte se s ostatními v diskuzi pod článkem!