In this post we will see step by step how we can set up a SFTP Server on SLES 15 SP6. I already wrote a post below about how to set up a SFTP Server on Ubuntu 20.04.3 by using a chroot jail to lock the users in their home directory from which they can’t escape and are not able to access the root file system.

The same we will now configure on SLES 15 SP6. Finally we will create a dedicated file upload/download folder for each new sftp user which will be placed on a dedicated disk and path different from the root file system. The users then will be locked to their home directory and this dedicated file upload/download folder which is mounted to the users home directories.




Configure/Adjusting SSH (sshd_config file)

First we need to configure SSH, so open the /etc/ssh/sshd_config file. By default the subsystem SFTP part will looks like this on SLES15 SP6.

# override default of no subsystems
Subsystem       sftp    /usr/lib/ssh/sftp-server

# This enables accepting locale enviroment variables LC_* LANG, see sshd_config(5).
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL

# Example of overriding settings on a per-user basis
#Match User anoncvs
#       X11Forwarding no
#       AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand cvs server



To tell OpenSSH to lock user’s from a specific group, I will create here a group named sftp, for which user’s inside this group, should be locked aka chrooted to a specific folder.

So adjust the /etc/ssh/sshd_config file as follows.

# override default of no subsystems
#Subsystem      sftp    /usr/lib/ssh/sftp-server

Subsystem sftp internal-sftp

# This enables accepting locale enviroment variables LC_* LANG, see sshd_config(5).
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL

# Example of overriding settings on a per-user basis
        Match Group sftp
        ChrootDirectory %h
        ForceCommand internal-sftp

        X11Forwarding no
        AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand cvs server



Finally restart the sshd service.

# systemctl restart sshd.service


First I commented above the line with the default subsystem libraries to avoid the need for installing additional libraries (dedicated standalone sftp server).

OpenSSH: Difference between internal-sftp and sftp-server
Subsystem sftp /usr/lib/openssh/sftp-server
Subsystem sftp internal-sftp

Both sftp-server and internal-sftp are part of OpenSSH. The sftp-server is a standalone binary. The internal-sftp is just a configuration keyword that tells sshd to use the SFTP server code built-into the sshd, instead of running another process (what would typically be the sftp-server).

The internal-sftp was added much later (OpenSSH 4.9p1 in 2008?) than the standalone sftp-server binary. But it is the default by now. The sftp-server is now redundant and is kept probably for a backward compatibility.

Source: https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server


The next lines with

Match Group sftp
ChrootDirectory %h
ForceCommand internal-sftp


will force all users which are members in the sftp group to be locked (chrooted) to its own home directory (%h).

ChrootDirectory accepts the tokens:
%h -> The home directory of the user
%u -> The local username
%U -> The numeric user ID of the target user
%% -> A literal ‘%’

Source: https://man.openbsd.org/sshd_config#TOKENS


ForceCommand internal-sftp will make sure that these user sessions will just be able to execute sftp commands.

Note that specifying “internal-sftp” on the sshd_config keyword ForceCommand enables an in-process sftp server to be the only command to be run, regardless of the command specified by the user.

For example, this prevents the user from running scp or from starting an interactive shell session via ssh on the server.

In addition, the in-process sftp server allows users without shell access on the server to still transfer files via sftp.

Using the ForceCommand keyword in this manner allows the administrator to apply this restriction to a limited set of users when placed inside a Match keyword as described in Match.

Source: https://www.ibm.com/docs/en/zos/2.4.0?topic=administrators-limiting-file-system-name-space-sftp-users


X11 Forwarding will support to open graphical programs like browsers, GUI text editors and more by using a SSH terminal like putty, for our case we do not need and want to enable them. Further down we also deny for the user in general to access a shell or terminal.

More about X11 Forwarding you will find in my following post.


AllowTcpForwarding will allow you to tunnel local application ports by the client to the server or vice versa through the SSH tunnel.



The following output and behavior is finally because of using the above ForceCommand internal-sftp directive.

This service allows sftp connections only.



Creating SFTP Users and SFTP Group

We now also need to create the new users they should be able to upload and download files from the SFTP server.

Further we will create a new group and add our new users to this group. This group we will then use to lock all members to a dedicated path and folder we use for the file upload and download.

On most distributions adduser and addgroup can be also used and are interactive ‘convenience’ wrappers around the commands useradd and groupadd.

# groupadd sftp
# useradd -m -s /bin/false -G sftp sftpuser01
# useradd -m -s /bin/false -G sftp sftpuser02
# useradd -m -s /bin/false -G sftp sftpuser03

The -m option will create the user’s home directory and the -s option will set the user’s shell to the folder path /bin/false and therefore will prevent the user from accessing the shell.

The -s option to prevent the user from accessing the shell we actually doesn’t really need here, as mentioned previously, because of using the ForceCommand internal-sftp directive in our /etc/ssh/sshd_config file, we already prevent the user from accessing the shell. On the other hand, by setting the users shell to /bin/false in addition, it is also not possible to substitute the user by using the su – <user> command from an existing shell session.

The -G flag will add our sftp users to our previously new created sftp group.



We also have to set a password for our newly created sftp users by executing the following command for each new user.

# passwd sftpuser01
# passwd sftpuser02
# passwd sftpuser03


In order to add existing users to the sftp group, we can execute the following commands.

# usermod -G sftp user123
# usermod -s /bin/false user123


To determine in which groups a user is, we can run the following command.

# groups sftpuser01


To list members of a group use.

# getent group sftp



Set Permissions for the Home Directory

First we need to make the root user as owner on the home directories of our new sftp users in order they will be able to login to. So just the root user finally will have owner and write permission for the sftp users home directories directly, not subdirectories.

The reason for is because of the design of the sshd service.

man page sshd_config:
ChrootDirectory
Specifies the pathname of a directory to chroot to after authentication. At session startup sshd checks that all components of the pathname are root-owned directories which are not writable by any other user or group. After the chroot, sshd changes the working directory to the user’s home directory.

# man sshd_config


chmod 0755 will allow read, write, execute permission for the owner and read, execute for everyone.

Unix file permissions are expressed in three octal digits. The first 7 indicates a files owners permission, the second 5 is a user groups permission and the third 5 is public permission for everyone else.

The first digit, here 0 in a four-digit permission is the sum of set user idset group id and sticky. A three-digit permission is just like a four-digit permission with the first digit set to zero. Thus:

0755 is exactly the same as 755. More about setuid, setgid and the sticky bit you will find here https://en.wikipedia.org/wiki/Setuid.

# chown root:root /home/sftpuser01
# chmod 0755 /home/sftpuser01

# chown root:root /home/sftpuser02
# chmod 0755 /home/sftpuser02

# chown root:root /home/sftpuser03
# chmod 0755 /home/sftpuser03


We will also create a new folder in the home directories of each new sftp user where they can later upload, download and edit files within.

In this folder later we mount the dedicated disk used for the file uploads and downloads different from the root file system and its disk.


Further we will set the sftp users as owner for this new folder (subdirectory within the users home directory) and also the root user by adding the root group.

# mkdir /home/sftpuser01/files
# chown sftpuser01:root /home/sftpuser01/files

# mkdir /home/sftpuser02/files
# chown sftpuser02:root /home/sftpuser02/files

# mkdir /home/sftpuser03/files
# chown sftpuser03:root /home/sftpuser03/files



From now on the users are able to access this new folder but without the option to break out from its home directory.


Finally we need to mount the new disk and dedicated folder for each new sftp user on it to the previous created new files folder withing the users home directory and shown below.




Mounting the dedicated File Upload/Download Folders to the Users Home Directories

As we want to enable the users to upload, download and edit files within their new dedicated file upload/download folder, which is placed on a dedicated disk and path, different from the root file system and the users home directories, which still be placed on the root file system, we finally need to mount these new folders to our users home directory and the previously created files folder within.


On my SFTP Server I will have finally three disks (virtual on vSphere), the first disk (sda) with 1 GB is storing the dedicated EFI boot loader partition, the second disk (sdb) with 40 GB will store the root filesystem (including the home directories) and the swap partition, and on the third disk (sdc) with 100 GB I will use for the file uploads and downloads of the sftp users.


To be able to later easily resize and manage this dedicated disk space for the file uploads and downloads, I will first add this disk to be managed by the Logical Volume Manager (LVM). The disk for the root filesystem is already managed by LVM.

More about the Logical Volume Manager (LVM) you will find in my blog here https://blog.matrixpost.net/?category=logical-volume-manager-lvm.


Finally I will have a new logical volume (LV) which will be used for the sftp file uploads and downloads.


To create the folders for each sftp user where they will finally upload and download their files, we now first need to mount this disk (logical volume) to the root file system.

To mount the disk to the root file system, I will create a new folder in the root file system to which the disk will be mounted.

# mkdir sftp_root


We can now mount the dedicated disk (logical volume) to our newly created sftp_root folder on the root file system.

To determine the correct path to mount you can first check the existing mount by enter the df -hT command.

#  mount /dev/mapper/sftp_root_vg-sftp_root /sftp_root/


In order to not lost this mount after a reboot of the SFTP server, we also need to add the mount in the /etc/fstab file in order to get mounted every time the system boots.

defaults
use default options. The default depends on the kernel and the filesystem. mount does not have any hardcoded set of default options. The kernel default is usually rw, suid, dev, exec, auto, nouser, and async.

The fifth field below the 0 digit -> This field is used by dump to determine which filesystems need to be dumped. Defaults to zero (don’t dump) if not present.

The sixth field below also the 0 digit -> This field is used by fsck to determine the order in which filesystem checks are done at boot time. The root filesystem should be specified with a fs_passno of 1. Other filesystems should have a fs_passno of 2. Filesystems within a drive will be checked sequentially, but filesystems on different drives will be checked at the same time to utilize parallelism available in the hardware. Defaults to zero (don’t check the filesystem) if notpresent.

Source: https://man7.org/linux/man-pages/man5/fstab.5.html

/dev/mapper/sftp_root_vg-sftp_root /sftp_root ext4 defaults                       0  0


Next we need to create for each sftp user a dedicated folder on our newly mounted disk (logical volume) which then finally needs to be mounted to the users home directory and files folder within we created previously to mount the new space to.

# cd /sftp_root

# mkdir sftpuser01_files
# mkdir sftpuser02_files
# mkdir sftpuser03_files


We can now mount these newly created folder on our dedicated disk to the users home directory and the files folder within we just created previously to mount this disk and folder to.

By using the -B, –bind flag we can mount a subtree somewhere else (same as -o bind)

Bind mounts in Linux enable you to mount an already-mounted file system to another location within the file system. Generally, bind mounts are used when restricting the access of specified users to designated parts of a website by replicating the website’s directory into a jailed user’s home directory.

Source: https://docs.rackspace.com/docs/bind-mounts-in-linux

# mount --bind /sftp_root/sftpuser01_files /home/sftpuser01/files
# mount --bind /sftp_root/sftpuser02_files /home/sftpuser02/files
# mount --bind /sftp_root/sftpuser03_files /home/sftpuser03/files


In case on the mounted disk and folders are already stored files, we will also set the permissions recursive for the root user and the corresponding sftp users.

# chown -R sftpuser01:root /home/sftpuser01/files
# chown -R sftpuser02:root /home/sftpuser02/files
# chown -R sftpuser03:root /home/sftpuser03/files


From now on our three users should be able to upload, download and edit files within their dedicated mounted folder on the dedicated disk. Further because of the ChrootDirectory directive set to the users home directory in the /etc/ssh/sshd_config file, they can’t escape from their home directory and are not able to navigate to the root file system.



Testing the SFTP Server by using WinSCP

We can now test if our new sftp users are able to upload and download files from and into their dedicated files folder to which our dedicated disk and folders are mounted.


I will now create a new folder and file within the files folder (to which our dedicated disk is mounted) in order to check if they will finally be really placed to our mounted disk (third 100 GB disk sdc).


Looks good!



Testing the SFTP Server by using the Command Line in Windows

We can also use the SFTP command line in Windows by default and not just on Linux.

Starting with Windows 10 (build 1803) and Windows Server 2019, Windows includes a native OpenSSH client that supports SFTP. You can use SFTP directly from the Windows command line (Command Prompt or PowerShell).

> sftp <sftp user>@<FQDN or IP SFTP Server>
> sftp sftpuser01@192.168.2.84

Prints the current working directory on the remote server
> pwd 

Prints the current working directory on the local computer
>lpwd

List information about the FILEs (the current directory by default)
> ls

It create a directory on the remote server
> mkdir testfolder2




Troubleshooting

If you run into the following error by trying to change files with WinSCP.

Upload of file .. was successful, but error occurred while setting the permissions and/or timestamp. If the problem persists, turn off setting permissions or preserving timestamp. Alternatively you can turn on ‘Ignore permission errors’ option.

  • On some systems (e.g. Linux), you need to be an owner of the file (write permissions are not enough) to modify its permissions or timestamp (you will see an error like “Permissions denied” in error details).
  • Some servers do not support updating file timestamp or permissions at all (you will see an error like “The server does not support the operation” in error details).
  • Some servers are set up to pickup any uploaded file immediately, process it somehow and delete or move it away. If the server is quick enough, it does that before WinSCP is able to update the file timestamp or permissions (you will see an error like “No such file or directory” in error details).


Whatever the reason is, you need to turn off Set permissions and Preserve timestamp options or turn on Ignore permission errors.

Source: https://winscp.net/eng/docs/message_preserve_time_perm





Links

How to chroot SFTP sessions on SLES 10 SP4 or higher version
https://www.suse.com/support/kb/doc/?id=000017689

Configure an sftp server with a shared chroot directory
https://access.redhat.com/solutions/5928701

Difference between OpenSSH internal-sftp and sftp-server
https://serverfault.com/questions/660160/difference-between-openssh-internal-sftp-and-sftp-server