If you want to replace the buggy and not-encrypted FTP protocol, and get rid of the FTP daemon on your system, the SFTP protocol comes to the rescue. Note that the SFTP protocol is something more than the SCP protocol (Secure copy), as it provides resuming interrupted transfers, directory listings, and remote file removal. This makes it more similar to the FTPS protocol (FTP over SSL) with the difference that it doesn’t require a separate FTP daemon, because the SSH daemon supports SFTP, which simplifies your network setup and lowers maintenance costs.
A standard security feature of the FTP servers is that logged in users are placed in a chroot jail directory, which restricts users from viewing and manipulating any other files but their own ones. Fortunately, the OpenSSH daemon supports chroot() too — see the sshd_config(5) man page.
Now that I’ve convinced you that SFTP is the right way to go for secure file transfers and remote file mounts, let’s see how we can configure it on a Debian or Ubuntu based server. All SFTP users will be kept in a root chroot() directory:
mkdir -m 751 /home/sftp-chroot /home/sftp-chroot/{dev,home}
The man page says that all components of the pathname must be root-owned directories that are not writable by any other user or group. Let’s verify this before going further:
ls -lad / /home /home/sftp-chroot /home/sftp-chroot/home drwxr-xr-x 23 root root 4096 2011-01-31 17:15 / drwxr-x--x 9 root root 4096 2011-01-31 18:05 /home drwxr-x--x 4 root root 4096 2011-01-31 17:38 /home/sftp-chroot drwxr-x--x 3 root root 4096 2011-02-01 08:46 /home/sftp-chroot/home
SFTP users’ home directories will be placed in “/home/sftp-chroot/home/$SFTPUSER” (after the chroot() the actual directory would be “/home/$SFTPUSER”). Note that this still gives full privacy, because users can’t list the root chroot() directory “/” nor the root home directory “/home”, as their permissions are 0751. Furthermore, even if one user guessed the username and home directory of another user, they cannot enter their home directory, because the users’ home directories give no permissions for the group “others”. The commands for managing users’ home directories are at the very end of this article.
In order for the chroot()’ed users and processes to be able to do logging, a listening UNIX socket of syslog must be created inside the root chroot() directory:
cat > /etc/rsyslog.d/sftp-chroot.conf <<'EOF' # the single quotes are important # the following syslog socket will be used by all chrooted users $AddUnixListenSocket /home/sftp-chroot/dev/log # Log internal-sftp activity in a separate file :programname, isequal, "internal-sftp" -/var/log/sftp.log :programname, isequal, "internal-sftp" ~ EOF /etc/init.d/rsyslog restart
We verify that the syslog UNIX socket was created:
ls -la /home/sftp-chroot/dev/log srw-rw-rw- 1 root root 0 2011-01-31 16:42 /home/sftp-chroot/dev/log
We will also rotate the log files weekly:
cat > /etc/logrotate.d/sftp-chroot <<'EOF' /var/log/sftp.log { weekly missingok rotate 52 compress delaycompress postrotate invoke-rc.d rsyslog reload > /dev/null endscript } EOF
Finally, let’s set up the OpenSSH daemon accordingly:
# disable the standard "sftp" subsystem in the sshd config perl -pi -e 's/^(\s*Subsystem\s+sftp\s+)/#$1/i' /etc/ssh/sshd_config # enable the chroot "sftp" subsystem cat >> /etc/ssh/sshd_config <<'EOF' Subsystem sftp internal-sftp Match group sftponly ChrootDirectory /home/sftp-chroot ForceCommand internal-sftp -l VERBOSE AllowTcpForwarding no PermitRootLogin no X11Forwarding no AllowAgentForwarding no # Change to yes to enable tunnelled clear text passwords, not recommended PasswordAuthentication no EOF groupadd sftponly /etc/init.d/ssh restart
A few notes about the OpenSSH configuration:
- This configuration requires OpenSSH 5.2 or later — discussion about this in the reference links below.
- The SCP protocol is not supported, at least not very easily. If you really need SCP, you’d need to re-create a full binary environment, in order to provide standard SSH access in a chroot() way. This is not discussed here, nor tested by me. You are encouraged to use SFTP instead. [source article]
- Some users report that the time-stamp of the messages in the syslog log file were wrong. This is indeed possible since there is no /etc/timezone file in the root chroot() directory. I haven’t encountered this bug, as my system is in GMT+0, or the bug no longer exists. [source article]
In the end, let’s take a look at Users management (sample Bash script below in the comments).
Adding an SFTP user:
export SFTPUSER='testsftp1' useradd -d "/home/$SFTPUSER" --groups sftponly -s /bin/false -p '!' "$SFTPUSER" passwd "$SFTPUSER" # if you enabled tunnelled clear text passwords, regardless of the security implications mkdir -m 770 "/home/sftp-chroot/home/$SFTPUSER" chown root:"$SFTPUSER" "/home/sftp-chroot/home/$SFTPUSER"
Enabling public/private key authentication, the more secure choice, for an SFTP user:
export SFTPUSER='testsftp1' mkdir -m 750 "/home/$SFTPUSER" "/home/$SFTPUSER/.ssh" chown root:"$SFTPUSER" "/home/$SFTPUSER" "/home/$SFTPUSER/.ssh" vi "/home/$SFTPUSER/.ssh/authorized_keys" # add the public key
Deleting an SFTP user and its data:
export SFTPUSER='testsftp1' userdel "$SFTPUSER" rm -r "/home/sftp-chroot/home/$SFTPUSER" rm -r "/home/$SFTPUSER" # if you authenticate using public keys
The end-result of all those efforts is that when an SFTP user logs in to your system, they see only their home directory and nothing else. This is because after the chroot, sshd(8) changes the working directory to the user’s home directory. Furthermore the user cannot list nor enter other home directories in the root chroot() directory, because of the directory setup we created.
Here is a sample log from the SFTP syslog file, click “show source” to view it:
Jan 31 17:55:10 m1 internal-sftp[13237]: session opened for local user testsftp1 from [127.0.0.1] Jan 31 17:55:10 m1 internal-sftp[13237]: received client version 3 Jan 31 17:55:10 m1 internal-sftp[13237]: realpath "." Jan 31 17:55:12 m1 internal-sftp[13237]: open "/home/testsftp1/fb.php" flags WRITE,CREATE,TRUNCATE mode 0644 Jan 31 17:55:13 m1 internal-sftp[13237]: close "/home/testsftp1/fb.php" bytes read 0 written 735 Jan 31 18:04:14 m1 internal-sftp[13237]: session closed for local user testsftp1 from [127.0.0.1]
References: