Logging sFTP activity for chrooted users
The goal here is to allow one or more new users to connect to the server using SFTP over SSH. Each user will have a unique username and password and once logged in will be restricted (chrooted) to their own directory (or you can let them access a shared directory).
All of the following commands need to be run either by the root user or using sudo.
Creating sftp only users
The first step is to create a group sftponly:
# groupadd sftponly
and then create and assign the users to that group:
# GROUPID=$(getent group sftponly | cut -d: -f3)
# useradd someuser -d /path/to/somedirectory -g sftponly -M -N -o -u $GROUPID -s /bin/false
# useradd anotheruser -d /path/to/anotherdirectory -g sftponly -M -N -o -u $GROUPID -s /bin/false
We're assuming here that the directories already exist. If not, you should create them first:
# mkdir -m2755 /path/to/somedirectory
# mkdir -m2755 /path/to/anotherdirectory
These directories, and all upstream directories, need to be owned by root:root and not be writable by any other users. Otherwise you will see the error "bad ownership or modes for chroot directory" in your auth.log.
You can check that the users and group have been created properly using:
# getent group sftponly
# getent passwd someuser
As you can see our new user or users have been created with both their uid and gid set to the sftponly group id. Their home directory is the location they will be able to connect to, and only via SFTP, because we've configured their shell as /bin/false which prevents SSH logins.
Finally, don't forget to assign passwords:
# passwd someuser
Enter new UNIX password: ********
Retype new UNIX password: ********
passwd: password updated successfully
Now we need to tell the SSH daemon how to recognise and handle our new sftp users by editing /etc/ssh/sshd_config.
Starting with the default configuration, we remove the line:
Subsystem sftp /usr/lib/openssh/sftp-server
replacing it with:
Subsystem sftp internal-sftp -l INFO
And at the end of the configuration file we append the following:
Match Group sftponly
ForceCommand internal-sftp -l INFO
Now any connections from users in the sftponly group will be handled by the internal-sftp in-process SFTP server with a log level of INFO. They will not be able to connect using SSH, and will not have access to files outside of their home (%h) directory.
To apply the new configuration you will need to:
# systemctl restart ssh.service
Blocked SSH gotcha
With the above Match Group setting any users who belong to the sftponly group will be restricted to sFTP and blocked from SSH - not just those with sftponly as their primary group.
So if you have SSH users who also belong to the sftponly group, in order to have write permission on uploaded files, you will need to exclude them from the Match criteria, for example:
Match Group sftponly User *,!adminuser
Otherwise the affected user/s will have no access to SSH, and will also not be able to connect via sFTP if their home director is not write-only to root.
Other options for Match are described in the man page:
The arguments to Match are one or more criteria-pattern pairs or the single token All which matches all criteria. The available criteria are User, Group, Host, LocalAddress, LocalPort, and Address.
If your SSH configuration includes an AllowUsers command then you will need to replace it with AllowGroups because the two aren't compatible. So instead of:
you will have:
AllowGroups staff sftponly
where adminuser is now a member of the staff group.
With these settings all members of staff as well as our new sftponly users can connect to the server. The former will enjoy full SSH access while the latter will be restricted to their own chrooted sftp environment.
To add a user to a group without having to edit the /etc/group and related files directly:
# usermod -a -G staff adminuser
# groups adminuser
adminuser : adminuser staff
# groups someuser
someuser : sftponly
Making a connection
At this stage you should already be able to connect and log in using sftp from the command line:
bye Quit sftp
cd path Change remote directory to 'path'
If not, check your auth.log. The problem is likely to do with missing directories or the wrong directory permissions.
But where are the logs?
A good question. By default you won't see any logs for sftp actions, only for the usual sshd "session opened" and "session closed" events in the auth.log.
The issue is that because each sftp user is chrooted into their own directory, they have no access to write to the usual system logs. The details are pretty complicated and hard to explain, so we'll trying and stick to simple instructions.
First, create a /dev directory in the home directory of each chrooted sftp user:
# mkdir -m2755 ~someuser/dev
# mkdir -m2755 ~anotheruser/dev
Now edit a new file /etc/rsyslog.d/sftp.conf to open a socket in each of the new directories, and pipe them to a new sftp.log log file:
# create additional sockets for the sftp chrooted users
input(type="imuxsock" Socket="/path/to/somedirectory/dev/log" CreatePath="on")
input(type="imuxsock" Socket="/path/to/anotherdirectory/dev/log" CreatePath="on")
# log internal-sftp activity to sftp.log
if $programname == 'internal-sftp' then /var/log/sftp.log
Restart the rsyslog daemon, and we're done:
# systemctl reload-or-restart rsyslog
If you see a syslog message 'imuxsock' already in this config then you can omit the first line (highlighted above) as imuxsock is already available.
Now checking the contents of the new /dev directory you should see that a file log has appeared:
# ls -l ~someuser/dev/
srw-rw-rw- 1 root root 0 Jul 20 17:57 log
This is actually not a file, but a socket feeding in to rsyslog. The users sFTP actions will not appear here, but in the new /var/log/sftp.log file:
==> sftp.log <==
Jul 20 18:13:09 hostname internal-sftp: session opened for local user someuser from [22.214.171.124]
Jul 20 18:13:15 hostname internal-sftp: opendir "/"
Jul 20 18:13:15 hostname internal-sftp: closedir "/"
Jul 20 18:13:25 hostname internal-sftp: opendir "/html"
Jul 20 18:13:26 hostname internal-sftp: closedir "/html"
Jul 20 18:14:20 hostname internal-sftp: session closed for local user someuser from [126.96.36.199]
And we're done. All that's left is to arrange for log rotation, and if there are already files in the sftp directories their permissions will need to be changed to grant read/write access to the sftp accounts, but those are trivial problems.
For non-Debian or older systems look under References below. And if you have any questions or comments there's a Feedback button below.
The following configuration should work for logrotate:
create 640 root adm
Showing incorrect timestamp
In the chroot enviroment sftp doesn't have acccess to the system time settings so the displayed timestamps can be off by the difference between your timezone and UTC.
If it bothers you, the simplest fix is to run the following as root:
cp -af /etc/localtime ~someuser/etc/.
The copies the server timezone settings (binary) file making it accessible in the chroot'ed environment.
- Implement a SFTP Service for Ubuntu/Debian With a Chroot'ed, Isolated File Directory
- How to log internal-sftp chroot jailed users
Related Articles - Log Files
- SQL Using a PostgreSQL foreign data wrapper to analyze log files
- System Controlling what logs where with rsyslog.conf
- System Logging sFTP activity for chrooted users
- System Analyzing Apache Log Files
- System Bash script to generate broken links report
- System Blocking Unwanted Spiders and Scrapers
- System Referer Spam from Microsoft Bing
- System Fake Traffic from AVG
- System Referer Spam from Live Search