jump to navigation

Serving up Sftp and AppArmor September 9, 2009

Posted by jdstrand in security, ubuntu, ubuntu-server.

Recently I decided to replace NFS on a small network with something that was more secure and more resistant to network failures (as in, Nautilus wouldn’t hang because of a symlink to a directory in an autofs mounted NFS share). Most importantly, I wanted something that was secure, simple and robust. I naturally thought of SFTP, but there were at least two problems with a naive SFTP implementation, both of which I decided I must solve to meet the ‘secure’ criteria:

  • shell access to the file server
  • SFTP can’t restrict users to a particular directory

Of course, there are other alternatives that I could have pursued: sshfs, shfs, SFTP with scponly, patching OpenSSH to support chrooting (see ‘Update’ below), NFSv4, IPsec, etc. Adding all the infrastructure to properly support NFSv4 and IPsec did not meet the simplicity requirement, and neither did running a patched OpenSSH server. sshfs, shfs, and SFTP with scponly did not really fit the bill either.

What did I come up with? A combination of SFTP, a hardened sshd configuration and AppArmor on Ubuntu.

SFTP setup
This was easy because sftp is enabled by default on Ubuntu and Debian systems. This should be enough:

$ sudo apt-get install openssh-server
Just make sure you have the following set in /etc/ssh/sshd_config (see man sshd_config for details).

Subsystem sftp /usr/lib/openssh/sftp-server

With that in place, all I needed to do was add users with strong passwords:

$ sudo adduser sftupser1
$ sudo adduser sftpuser2

Then you can test if it worked with:

$ sftp sftpuser1@server
sftp> ls /
/bin ...

Hardened sshd
Now that SFTP is working, we need to limit access. One way to do this is via a Match rule that uses a ForceCommand. Combined with AllowUsers, adding something like this to /etc/ssh/sshd_config is pretty powerful:

AllowUsers adminuser sftpuser1@ sftpuser2
Match User sftpuser1,sftpuser2
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand /usr/lib/openssh/sftp-server -l INFO

Remember to restart ssh with ‘/etc/init.d/ssh restart’. The above allows normal shell access for the adminuser, SFTP-only access to sftpuser1 from and to sftupser2 from anywhere. One can imagine combining this with ‘PasswordAuthentication no’ or GSSAPI to enforce more stringent authentication so access is even more tightly controlled.

The above does a lot to increase security over the standard NFS shares that I had before. Good encryption, strong authentication and reliable UID mappings for DAC (POSIX discretionary access controls) are all in place. However, it doesn’t have the ability to confine access to a certain directory like NFS does. A simple AppArmor profile can achieve this and give even more granularity than just DAC. Imagine the following directory structure:

  • /var/exports (top-level ‘exported’ filesystem (where all the files you want to share are))
  • /var/exports/users (user-specific files, only to be accessed by the users themselves)
  • /var/exports/shared (a free-for-all shared directory where any user can put stuff. The ‘shared’ directory has ‘2775’ permissions with group ‘shared’)

Now add to /etc/apparmor.d/usr.lib.openssh.sftp-server (and enable with ‘sudo apparmor_parser -r /etc/apparmor.d/usr.lib.openssh.sftp-server’):

#include <tunables/global>
/usr/lib/openssh/sftp-server {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  # Served files
  # Need read access for every parent directory
  / r,
  /var/ r,
  /var/exports/ r,
  /var/exports/**/ r,
  owner /var/exports/** rwkl,
  # don't require ownership to read shared files
  /var/exports/shared/** rwkl,

This is a very simple profile for sftp-server itself, with access to files in /var/exports. Notice that by default the owner must match for any files in /var/exports, but in /var/exports/shared it does not. AppArmor works in conjunction with DAC, so that if DAC denies access, AppArmor is not consulted. If DAC permits access, then AppArmor is consulted and may deny access.

This is but one man’s implementation for a simple, secure and robust file service. There are limitations with the method as described, notably managing the sshd_config file and not supporting some traditional setups such as $HOME on NFS. That said, with a little creativity, a lot of possibilities exist for file serving with this technique. For my needs, the combination of standard OpenSSH and AppArmor on Ubuntu was very compelling. Enjoy!

OpenSSH 4.8 and higher (available in Ubuntu 8.10 and later) contains the ChrootDirectory option, which may be enough for certain environments. It is simpler to setup (ie AppArmor is not required), but doesn’t have the same granularity and sftp-server protection that the AppArmor method provides. See comment 32 and comment 34 for details. Combining ChrootDirectory and AppArmor would provide even more defense in depth. It’s great to have so many options for secure file sharing! :)


1. mossholderm - September 9, 2009

THis might be a little more precise:


Using AppArmor, in the fashion you sugges only locks down the SSH daemon to the overall group of directories, rather than restricting the users to a per-user distinct set of directories. Depends on what you need, really.

jdstrand - September 9, 2009

It does depend on what you need. The article you referenced is rather complicated to setup and appears a little brittle. I am also not a fan of having to keep up with what is in a chroot for security updates, etc. I’ve been there and don’t want to do that again. AppArmor can achieve the same types of protection (and more) as a traditional chroot, but without the setup and maintenance overhead. For the kind of access you describe, Jeff’s ChrootDirectory approach will be much easier to maintain. Do keep in mind there is a security benefit to actually confining the sftp-server process itself as described in the article in the event there is a vulnerability in OpenSSH that is exposed via SFTP (though ChrootDirectory should largely mitigate that as well). Also, there is also nothing saying that ChrootDirectory and the AppArmor approach couldn’t be combined….

2. Balau - September 9, 2009

Actually, chrooting is supported withouth patch since release 4.8: http://openssh.org/txt/release-4.8
You can now add a simple line in the configuration file:
ChrootDirectory [your_desired_path_here]
You then need to use the internal sftp command because the root directory is changed and the original sftp binary can’t be seen. The following options do the trick:
Subsystem sftp internal-sftp
ForceCommand internal-sftp

I implemented a solution for sshfs that is similar to what you want to do, if you want to take a look:

3. Jeff Schroeder - September 9, 2009

The internal-sftp server is in-process (sshd) and requires 0 libs or messy device nodes for a full chroot

===== Put this in /etc/ssh/sshd_config =====
#Subsystem sftp /usr/libexec/openssh/sftp-server
Subsystem sftp internal-sftp

# Chroot third parties into their home directory for security
Match Group thirdparty
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no

jdstrand - September 9, 2009

This is very interesting and I believe would cover the use case I described in the article. However, this only works in OpenSSH 4.8 and higher (Ubuntu 8.04 LTS has 4.7) and it doesn’t have quite the granularity that I actually needed, though it comes very close. Eg, the ChrootDirectory method that approaches the AppArmor method would be:

AllowUsers adminuser sftpuser1@ sftpuser2
Match User sftpuser1,sftpuser2
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp
    ChrootDirectory /var/exports

This is likely fine for many people, as DAC would control access, but I actually wanted the additional ‘owner’ matching to prevent accidental read access. That said, this is an excellent alternative for people who have OpenSSH 4.8 and higher. Thanks!

4. sharms - September 9, 2009

Great article, this was very helpful, well thought out and written.

5. jef spaleta - September 9, 2009


would rssh’s chroot approach have worked for you as an alternative to the ForceCommand approach?


jdstrand - September 10, 2009

It would basically, yes, which was mossholderm’s suggestion. The setup and maintenance is more complicated and it lacks AppArmor’s ‘owner’ matching, which though not explicitly described in the article, was desired.

6. yamo - November 14, 2009

How can I made that sftpuser1 can only access by LAN?
sftpuser1@ ?

Thanks in advance,

jdstrand - December 14, 2009

For, use:

For use:

Leave a Reply

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

WordPress.com Logo

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

Facebook photo

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

Connecting to %s

%d bloggers like this: