In this process, 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 Start With: What Do You Need?
To complete this process, 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 process needs the policycoreutils-python package installed.
The Process
- The first step is to login as root on our 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
- Now add your usernames and corresponding passwords in the following way:
virtual-username1
password1
virtual-username2
password2
virtual-username3
password3Note
Repeat this process as required for every user you need but, for obvious reasons, maintain a good password policy and do not use the same virtual-username more than once. - When you have finished, simply save and close the file in the usual way. Then, proceed to build the database file by typing the following command:
db_load -T -t hash -f /tmp/virtual-users.txt /etc/vsftpd/virtualusers.db
- Having done this, we will now create the PAM file that will use this database to validate the virtual users. To do this, type the following command:
vi /etc/pam.d/vsftpd-virtual
- Now add the following lines:
auth required pam_userdb.so db=/etc/vsftpd/virtual-users
account required pam_userdb.so db=/etc/vsftpd/virtual-users - When you have finished, save and close the file in the usual way. Open the main vsftpd configuration file in your favorite text editor as follows:
vi /etc/vsftpd/vsftpd.conf
- Now, in the opened file, search for the line 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
- Scroll down to the bottom of the file and add the following lines by customizing the value for 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 - Now create a subfolder for each virtual user you defined in a previous step in your /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 - Now we need to inform SELinux to allow read/write access to our custom 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 - Next, restart the FTP service as follows:
systemctl restart vsftpd
- For security reasons, remove the plain text file now and protect the generated database file with this:
rm /tmp/virtual-users.txt chmod 600 /etc/vsftpd/virtual-users.db
How Does It Work?
Having followed the previous process, 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 process.
So what did we learn from this experience?
We began this process 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 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 process.