2016-04-23 "restricting user to sshfs and rsync" notes
Grzegorz Wierzowiecki
self-link: https://docs.google.com/document/d/1BU0YpshTPSEXYktlGcsZWdRAqDlHUkZmcxkt-MC5Wwc/pub
Example use-case:
You might want special restricted ssh accounts on server, that your semi-trusted machines (or your family members, etc) automatically backup via cron rsync.
Also you might want to let them have some sshfs mounts. (bikeshedding why sshfs not nfs or why it's Linux not OpenBSD etc are out of scope of this doc).
Recap from :
To keep in mind: Ubuntu Server LTS keeps directories of users encrypted, that’s why I have to keep their ssh configuration in /etc/ssh/users_configs/${username}/ , like authorized_keys or “allowed_commands” introduced by below configuration.
Final goal of below configuration:
Purpose:
Let me repeat all steps I did on nas in zrh , on nas in waw, so here are captured:
# setup variables:
# Where to run commands: srv$ cln$ both$
both$ username=LIMITED_USER
cln$ clnuser=USERNAME_ON_CLIENT
cln$ server=1.2.3.4 or name in .ssh/config # this line on client side
srv$ testport=1234 # test port you will use for running test sshd
srv$ wrapper=/etc/ssh/users_configs/whitelisting_wrapper.sh # for whitelisting in Part 2
############### Part 1 sftponly
### As user directories are encrypted let’s make sshd to look for authorized_keys in /etc…
srv$ grep AuthorizedKeysFile /etc/ssh/sshd_config
AuthorizedKeysFile /etc/ssh/users_configs/%u/authorized_keys
srv$ sudo mkdir -p /etc/ssh/users_configs/"${username?}"
### Make sftponly group
srv$ sudo addgroup sftponly
### Make limited user
srv$ sudo useradd -d /home/"${username?}" -s /usr/lib/sftp-server -M -N -g sftponly "${username?}"
### Add public key for passwordless login
# make key
cln$ ssh-keygen -b 521 -t ecdsa -C 'LIMITED_USER key' -f ~/.ssh/id_ecdsa521_${username?}
srv$ sudo vim /etc/ssh/users_configs/"${username?}"/authorized_keys
# and put contents of your client://~/.ssh/id_ecdsa521_${username}.pub public key...
srv$ sudo chmod 700 /etc/ssh/users_configs/"${username?}"/authorized_keys
srv$ sudo chown ${username?}:sftponly /etc/ssh/users_configs/"${username?}"/authorized_keys
# and test it -> don't expect normal shell, as you have set /usr/lib/sftp-server as shell, but if it's not rejecting, that's good.
cln$ ssh -i ~/.ssh/id_ecdsa521_"${username?}" "${username?}"@${server?}
### Allow it just sftp
# add /usr/lib/sftp-server as shell if it's not yet there
srv$ if ! grep -Fxq '/usr/lib/sftp-server' /etc/shells ; then echo '/usr/lib/sftp-server' | sudo tee -a /etc/shells ; fi ;
# change /etc/ssh/sshd_config
srv$ grep 'Subsystem.*sftp' /etc/ssh/sshd_config
Subsystem sftp internal-sftp
srv$ grep -A 4 'Match group sftponly' /etc/ssh/sshd_config
Match group sftponly ChrootDirectory %h X11Forwarding no AllowTcpForwarding no ForceCommand internal-sftp |
# test with test instance in debugging mode (it will not fork! Accept only one connection and you need to rerun)
srv$ sudo /usr/sbin/sshd -D -ddd -p ${testport?}
# test sshfs!
srv$ sudo mkdir /home/"${username?}"/uploads ; sudo chown "${username?}":sftponly /home/"${username?}"/uploads
cln$ mkdir /tmp/sshfs
cln$ # let's assume that gid of "users" is 100
cln$ sshfs ${username?}@${server?}:/home/${username?}/uploads /tmp/sshfs -p ${testport?} -o uid=${UID},gid=100 -o IdentityFile=/home/${clnuser?}/.ssh/id_ecdsa521_${username?} # you might like to consider -idmap=user here, instead of "-o uid=,gid="
cln$ echo 'Test' > /tmp/sshfs/test.txt
cln$ ls -lha /tmp/sshfs # check uid:gid mapping
cln$ ls -lan /tmp/sshfs # you might like by numbers
cln$ fusermount -u /tmp/sshfs
srv$ ls -lha /home/${username?}/uploads
total 12K drwxr-xr-x 2 sftplenovox230 sftponly 4.0K Apr 23 16:20 . drwxr-xr-x 3 root root 4.0K Apr 23 15:34 .. -rw-r--r-- 1 sftplenovox230 sftponly 5 Apr 23 16:20 test.txt |
srv$ ls -lan /home/${username?}/uploads
############### Part 2 : add whiltelist of commands and whilelist rsync !
### ssh ForceCommand wrapper.sh to check is commands are whitelisted
srv$ sudo vim $wrapper <-- make it like in gist: https://gist.github.com/gwpl/66652d96fce1ac1b9e92267d69c9be37
srv$ sudo chmod +x $wrapper
srv$ sudo vim /etc/ssh/sshd_config
# so it looks like : grep -B 2 -A 5 'Match group sftponly' /etc/ssh/sshd_config
# now make wrapper logging files /home/${username?}/{.ssh_commands_history,.ssh_last_wrapper_invocation_error.log}:
srv$ sudo $wrapper make_files_for_user ${username?} sftponly
# Change sshd_config a bit to use new wrapper:
srv$ grep -A 4 'Match group sftponly' /etc/ssh/sshd_config
Match group sftponly #ChrootDirectory %h X11Forwarding no AllowTcpForwarding no ForceCommand /etc/ssh/users_configs/whitelisting_wrapper.sh |
# Make again /bin/bash a shell so wrapper can execute!
srv$ sudo usermod -s /bin/bash ${username?}
# Whitelist 'echo Test' and test it!
srv$ echo 'echo Test' >> /etc/ssh/users_configs/${username?}/allowed_commands
src$ sudo /usr/sbin/sshd -D -ddd -p "${testport?}"
cln$ ssh -i /home/${clnuser?}/.ssh/id_ecdsa521_${username?} ${username?}@${server?} -p ${testport?} echo Test
Test
# Once you are confided during testing with change that restart will not break your main ssh, do it:
srv$ sudo service ssh restart
# Now try rsync command you might with to use
cln$ mkdir /tmp/t
cln$ rsync -av -e 'ssh -i /home/${clnuser?}/.ssh/id_ecdsa521_'"${username?}" ${username?}@${server?}:/home/${username?} /tmp/t
protocol version mismatch -- is your shell clean? (see the rsync man page for an explanation) rsync error: protocol incompatibility (code 2) at compat.c(176) [Receiver=3.1.1] |
# take it easy -> rsync is not whitelisted. Let'c check logs for command that failed to run and whilelist it!
srv$ sudo tail /home/$username/.ssh_commands_history
# Sat Apr 23 18:06:37 CEST 2016 echo Test # Allowed: Found in ALLOWED_COMMANDS file : /etc/ssh/users_configs/LIMITEDUSER/allowed_commands # Sat Apr 23 18:11:52 CEST 2016 rsync --server --sender -vlogDtpre.iLsfx . /home/LIMITEDUSER # Denied. |
srv$ sudo tail /home/$username/.ssh_commands_history -n 2 | head -n 1 | sudo tee -a /etc/ssh/users_configs/"${username?}"/allowed_commands
# Now try again the same command! It should work :)
cln$ rsync -av -e 'ssh -i /home/${clnuser?}/.ssh/id_ecdsa521_'"${username?}" ${username?}@${server?}:/home/${username?} /tmp/t
### Adding new users
TODO: carefully test all below
srv$ username=ANOTHERUSER
srv$ sudo useradd -d /home/"${username?}" -s /bin/bash -M -N -g sftponly "${username?}"
### Add public key for passwordless login
# make key
cln$ ssh-keygen -b 521 -t ecdsa -C 'ANOTHERUSER key' -f ~/.ssh/id_ecdsa521_${username?}
srv$ sudo vim /etc/ssh/users_configs/"${username?}"/authorized_keys
# and put contents of your client://~/.ssh/id_ecdsa521_${username}.pub public key...
srv$ sudo chmod 700 /etc/ssh/users_configs/"${username?}"/authorized_keys
srv$ sudo chown ${username?}:sftponly /etc/ssh/users_configs/"${username?}"/authorized_keys
# now make wrapper logging files /home/${username}/{.ssh_commands_history,.ssh_last_wrapper_invocation_error.log}:
srv$ sudo $wrapper make_files_for_user ${username?} sftponly
# Now try rsync command you might with to use
cln$ mkdir /tmp/t
cln$ rsync -av -e 'ssh -i /home/${clnuser?}/.ssh/id_ecdsa521_'"${username?}" ${username?}@${server?}:/home/${username?} /tmp/t
# And whitelist it
srv$ sudo tail /home/$username/.ssh_commands_history -n 2 | head -n 1 | sudo tee -a /etc/ssh/users_configs/"${username?}"/allowed_commands
Postword:
One might want to limit commands for given public keys. This can be achived without touching sshd_config, just by using authorized_keys file with like looking more or less like this:
command="$HOME/bin/rrsync -ro ~/backups/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa AAA...vp Automated remote backup
More info: https://www.guyrutenberg.com/2014/01/14/restricting-ssh-access-to-rsync/ (or https://learninginlinux.wordpress.com/2009/05/07/rsync-fixed-server-side-options/ or http://positon.org/rsync-command-restriction-over-ssh )
Please note that similar effect can be achieved via “command=” option in authorized_keys file.