Published using Google Docs
2016-04-23 restricting user to sshfs and rsync
Updated automatically every 5 minutes

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.