How to setup isolated sftp-only access for untrusted users

This is a very common scenario: you want to setup SSH access for an untrusted user, but strictly limit his capabilities to SFTP (or scp).

Usually the requirements are just two:

  • The user can only access your machine to run the SFTP command, no other uses of the SSH service will be allowed for this user
  • The user can only access a very restricted environment and not break outside of it (so he cannot access files that he’s not supposed to access)

Depending on the degree of untrustyness, you may also want to avoid DoS attacks on the service, but for this, the best measure is the hardening of the whole SSH service.

Solution 1: SFTP chroot

Spoiler: this is way more complicated than solution 2

This method is the most common. The idea is to force users belonging to a group (or single user ids) to just run a specific command and be rooted to a specific directory. The command is the SSH subsystem for SFTP (internal-sftp). On Ubuntu, this may not be the default, and you may have to change this setting in the sshd_config.

Concisely, you can setup this solution as follows:

  1. Please ensure not to lock yourself out because of SSH misconfigurations that would crash the ssh daemon when it restarts (e.g., outdated SSH not supporting the options, typos, etc)
  2. Check your sshd configuration in /etc/ssh/sshd_config and use the internal-sftp subsystem for sftp. You may have to comment-out the line that sets the sftp-server (if it’s there) and add the new line for the internal-sftp (here is an excellent overview of internal-sftp vs sftp-server):
    #Subsystem sftp /usr/lib/openssh/sftp-server
    Subsystem sftp internal-sftp
  3. Use a system group of your choice (e.g., sftponly) to apply the restriction (you can also do this on single users). Users belonging to this group will be “sftp-restricted”. Create the group:
    groupadd sftponly
  4. Define sshd directives for users belonging to this group. Add these lines at the very end of the sshd_config file or what will follow them will be interpreted as part of the block (and this may prevent the ssh service from (re-)starting):
    Match group sftponly
         ChrootDirectory %h
         X11Forwarding no
         PermitTunnel no
         AllowTcpForwarding no
         ForceCommand internal-sftp
  5. Restart the ssh service
  6. From now, I will assume that the user you have to give sftp access to is named “username” on the system. Ensure that the home directory of the user is owned by root, but the shared directory is owned by the user, so he can upload files there (run these commands as root):
    chown root:root /home/username
    chmod 0755 /home/username
    mkdir /home/username/shared
    chown username:username /home/username/shared

    The .ssh folder and the .ssh/authorized_keys file should also be owned by root and only readable/traversable by the user. This is to avoid that the user uploads a new version of the authorized_keys file (run these commands as root, you may need to create the .ssh folder and authorized_keys files first):

    chown root:root /home/username/.ssh
    chown root:root /home/username/.ssh/authorized_keys
    chmod 755 /home/username/.ssh
    chmod 744 /home/username/.ssh/authorized_keys
  7. Add the user to the group:
    gpasswd -a username sftponly

With this setup, users belonging to the sftponly group will not be able to establish a “normal” ssh connection to the server:

$ ssh sftpuser@
This service allows sftp connections only.
Connection to closed.

Sftp connections will instead work. Users will land on a read-only environment (the chroot directory) and will have to move to the shared directory to be able to upload files (note that they will be able to download files from the chroot directory, that is, their home folder).

# User cannot write on the landing folder
sftp> put Vagrantfile .
Uploading Vagrantfile to /./Vagrantfile
remote open("/./Vagrantfile"): Permission denied

# Shared subfolder is writable
sftp> put Vagrantfile shared
Uploading Vagrantfile to /shared/Vagrantfile

Solution 2: use a Docker container

The atmoz/sftp is an excellent docker image that will allow you to instantiate an isolated sftp environment similar to what is described in “Solution 1”, but in a couple of minutes.

A simple usage of the command to setup an sftp service for user username with password password and bind-mount a local directory at the shared path is:

docker run -v /var/sftp/:/home/username/shared -p 1022:22 -d atmoz/sftp username:password

User will be able to write the shared directory:

$ sftp -P 1022 username@n7
username@n7's password: 
Connected to n7.
sftp> ls

It’s also easy to provide authorized keys or host keys for a known fingerprint. For example, public key files can be mounted to the /home/username/.ssh/keys/ directory:

-v /var/

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s