Jak nastavit "chrooted" SFTP s OpenSSH a SELinuxem ve Fedoře 16.

Základní požadavky

Pro dále popisované řešení je potřeba aktualizovaná Fedora 16 nebo novější, nainstalovaný balík openssh-server ve verzi alespoň openssh-5.8p2-24.fc16 a zapnutý SELinux.

Nastavení openssh serveru

Abychom neomezili všechny uživatele, ale jen vybranou skupinu, vytvoříme skupinu sftponly s tím, že každý uživatel patřící do této skupiny bude omezen jen na sftp:

server# groupadd sftponly

V konfiguračním souboru /etc/ssh/sshd_config přidáme následující řádky:

Match Group sftponly
 ForceCommand internal-sftp
 ChrootDirectory %h

Nebo-li pokud je uživatel ve skupine sftponly, pak vynuť internal-sftp a změň pro něj kořenový adresář do jeho domovského adresáře. Na závěr proveďte restart serveru:

server# systemctl restart sshd.service

Nastavení uživatele

server# useradd -M -g sftponly sftponlyuser

Tímto příkazem vytvořím nového uživatele "sftponlyuser" s nastavenou hlavní skupinou "sftponly" a domovským adresářem /home/sftponlyuser, který ale nebude vytvořen. Tento adresář bude použit jako kořenový, musí ho vlastnit uživatel root a nesmí být zapisovatelný pro nikoho jiného. Proto v něm vytvoříme podadresář upload, který bude určen pro data uživatele.

server# mkdir -p /home/sftponlyuser/upload
server# chown sftponlyuser: /home/sftponlyuser/upload
server# restorecon -R -v /home/sftponlyuser
restorecon reset /home/sftponlyuser context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:user_home_dir_t:s0
restorecon reset /home/sftponlyuser/upload context unconfined_u:object_r:home_root_t:s0->unconfined_u:object_r:user_home_t:s0

Teď už se uživatel může zkusit připojit:

client$ sftp sftponlyuser@f16-openssh
Connecting to f16-openssh...
sftponlyuser@f16-openssh's password: password
sftp> ls
upload
sftp> cd upload
sftp>

Vypadá to dobře, ale...

SELinux

sftp> put myfile.txt
Uploading myfile.txt to /upload/myfile.txt
Couldn't get handle: Permission denied

To je způsobeno tím, že všechny ssh/sftp procesy se změněným kořenovým adresářem běží v SELinuxovém kontextu chroot_user_t:

system_u:system_r:chroot_user_t:s0-s0:c0.c1023 \_ sshd: sftponlyuser@notty
system_u:system_r:chroot_user_t:s0-s0:c0.c1023 \_ sshd: sftponlyuser@internal-sftp

A tento typ nemá v základní konfiguraci právo na zápis do souborů s typem user_home_t:

type=AVC msg=audit(1328793486.912:654): avc: denied { write } for pid=12722 comm="sshd" name="upload" dev=vda3 ino=971 scontext=system_u:system_r:chroot_user_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir

Tato operace se povolí nastavením SELinuxové proměnné ssh_chroot_rw_homedirs:

server# setsebool -P ssh_chroot_rw_homedirs on

sftp> put myfile.txt
Uploading myfile.txt to /upload/myfile.txt
myfile.txt 100% 29 0.0KB/s 00:00

Výhoda chroot_user_t je hlavně v tom, že tento typ nemůže číst jiné typy než ty, které jsou určeny pro domovské adresáře. Takže pokud by se stalo, že v rámci chyby v openssh se uživatel dostane mimo svůj domovský adresář, nebude schopný si prečíst žádný soubor:

server# echo 'secret data' > ~sftponlyuser/upload/secret_file.txt
server# chcon -t admin_home_t ~sftponlyuser/upload/secret_file.txt
server# cp /etc/passwd /home/sftponlyuser/upload
server# chcon -t etc_t /home/sftponlyuser/upload/passwd

sftp> ls
myfile.txt
sftp> get secret_file.txt
Couldn't stat remote file: Permission denied
File "/upload/secret_file.txt" not found.
sftp> get passwd
Couldn't stat remote file: Permission denied
File "/upload/passwd" not found.

Vidíme, že nové soubory nevidíme. Ale stačí přepnout do permissive modu a soubory začnou být viditelné:

server# setenforce 0

sftp> ls
myfile.txt passwd secret_file.txt
sftp> get secret_file.txt
Fetching /upload/secret_file.txt to secret_file.txt
/upload/secret_file.txt                           100%   12     0.0KB/s   00:00