In this recipe, you will learn how to implement virtual users in order to break away from the restriction of using local system user accounts. During the lifetime of your server, there may be occasions when you wish to enable FTP authentication for a user that does not have a local system account. You may also want to consider implementing a solution that allows a particular individual to maintain more than one account in order to allow access to different locations on your server. This type of configuration implies a certain degree of flexibility afforded by the use of virtual users. Since you are not using a local system account, it can be argued that this approach gives improved security.
To complete this recipe, you will require a working installation of the CentOS 7 operating system with root privileges and a console-based text editor of your choice. It is expected that your server will be using a static IP address and that vsftpd
is already installed with a chroot jail and is currently running. This recipe needs the policycoreutils-python
package installed.
vsftpd
server and create a plain text file called virtual-users.txt
that maintains a list of usernames and passwords of the virtual users. To do this, type the following command:vi /tmp/virtual-users.txt
virtual-username1 password1 virtual-username2 password2 virtual-username3 password3
db_load -T -t hash -f /tmp/virtual-users.txt /etc/vsftpd/virtual-users.db
vi /etc/pam.d/vsftpd-virtual
auth required pam_userdb.so db=/etc/vsftpd/virtual-users account required pam_userdb.so db=/etc/vsftpd/virtual-users
vsftpd
configuration file in your favorite text editor as follows:vi /etc/vsftpd/vsftpd.conf
pam_service_name=vsftpd
and disable it by adding a #
sign at the beginning of the line so that it reads as follows:#pam_service_name=vsftpd
local_root
to suit your own specific needs—this will be the base directory in which all your virtual users will live in (for example, we will use /srv/virtualusers/$USER
as shown here):virtual_use_local_privs=YES guest_enable=YES pam_service_name=vsftpd-virtual user_sub_token=$USER local_root=/srv/virtualusers/$USER hide_ids=YES
/tmp/virtual-users.txt
file within the directory that you stated with the local_root
directive. Remember to delegate the ownership of this folder to the FTP user. To keep up with our /srv/virtualusers
example, we will use the following commands to do this in an automatic way (again, customize the /srv/virtualusers
directory if needed):for u in `sed -n 1~2p /tmp/virtual-users.txt`; do mkdir -p /srv/virtualusers/$u chown ftp: /srv/virtualusers/$u done
local_root
directory outside of the typical /home
directory:setsebool -P allow_ftpd_full_access on semanage fcontext -a -t public_content_rw_t "/srv/virtualusers(/.*)?" restorecon -R -v /srv/virtualusers
systemctl restart vsftpd
rm /tmp/virtual-users.txt chmod 600 /etc/vsftpd/virtual-users.db
Having followed the previous recipe, you will be now able to invite an unlimited number of virtual users to access your FTP service. The configuration of this feature was very simple; your overall security has been improved and all access is restricted to a defined local_root
directory of your choice. Please note that this usage of virtual users will disable your system users' login to the FTP server from the first recipe.
So what did we learn from this experience?
We began this recipe by creating a new temporary text file that will contain all our usernames with the corresponding passwords in plain text. We then added all the required usernames and passwords one after another sequentially separated by newlines. Having done this for each of our virtual users, we then saved and closed the file before proceeding to run the db_load
command that is installed on CentOS 7 by default. This can be used to generate a BerkeleyDB database out of our text file, which will be used for the FTP user authentication later in this process. Having completed this step, our next task was to create a Pluggable Authentication Modules (PAM) file at /etc/pam.d/vsftpd-virtual
. This reads the previous database file to provide authentication from it for our vsftpd
service using a typical PAM configuration file syntax (for more, see man pam.d
). Then, we opened, modified, and added new configuration directives to the main vsftpd
configuration file at /etc/vsftpd/vsftpd.conf
in order to make vsftpd
aware of our virtual users' authentication via PAM.
The most important setting was the local_root
directive that defines the base location where all your user directories will be placed for your virtual users. Don't forget to put the $USER
string at the end of your path. You were then prompted to create the relevant virtual hosting folder for every virtual user you have defined in the text file before.
Since virtual users are not real system users, we had to assign the FTP system user to take full ownership of the files for our new FTP users. We used a bash for
loop to automate the process for all our users defined in the temporary /tmp/virtual-users.txt
file. Next, we set the proper SELinux boolean to allow virtual users access to the system and also the right context on our /srv/virtualusers
directory. Applying all these changes was simply a matter of restarting the vsftpd
service using the systemctl
command.
Afterwards, we removed the temporary user text file because it contains our passwords in plain text. We protected the access to the BerkleyDB database file by removing all access other than root. If you update, add, or remove FTP users on a regular basis, it's better to not delete this temporary plain text /tmp/virtual-users.txt
file but rather put it in a safe place such as the /root
directory. Then, you should also protect this using chmod 600
. Then, you can rerun the db_load
command whenever you make a change to this file to keep your users up-to-date. If you need to add new users at a later point, you have to create new virtual user folders for them as well (Please rerun the commands from step 9). Run the restorecon -R -v /srv/virtualusers
command afterwards.
You can now test your new virtual user accounts by logging in to the FTP server using your newly created accounts from this recipe.