How to secure a Linux FTP server with TLS/SSL certificate and advanced security features

Meher Askri
8 min readAug 2, 2024

--

Hello and welcome to this new one, Today we’re going to explore one of the oldest protocols in existing “FTP” which is still used quite often.

What is FTP ?

I assume everyone know what is FTP ( file transport protocol) , it is a simple protocol used for sharing files over the network . To make it simple FTP operate in client/server model , Like SSH service for example , the ftpd daemon will listen for incoming requests ( generally port 21) from FTP clients . After the client presents a login and password , and after the authentication process , the client can list files , directories or download whatever the type of data for someone else later to upload it and vice-versa .

That’s the summary story of FTP which is all about sharing data between users over the network .

Back in the days when FTP was created security wasn’t taken into consideration because most computer communication was done on private lines or over dial-up , where encryption was not thought to be critical however if someone is sniffing on the communication between the client and the server he would be able not to see only the data being transferred but also the authentication credentials ( login and password information ) .

In order to make FTP secure , an open source FTP project was developed who took security into consideration which is vsftp ( very secure FTP) . The one often used with a lot of Linux distributions today and that’s what I’m focusing on in this article .

I’m using RHEL 8 for this demonstration , So, Let’s start by installing the package :

After we installed the package and before we start the service , let’s take a quick look at the configuration file :

I used the sed command with a regular expression to print the active lines :

I’m not going to explain all of them , check the man page for more details if you want or the examples under /usr/share/doc/vsftpd .

Alright, so to secure the FTP server , we first need to identify the purpose. Do we want it to be as a public server accessible over the internet ( open for everyone ) or be restricted to internal network connections ( intranet server) because there isn’t one fixed way to secure FTP , it’s depends on the specific requirements and objectives to accomplish and based on that we can customize the configuration the way we want .

For simplicity, here’s what we’re going to do :

we’re going to restrict access to the server to specific users (such as Bob and Jack , pick the names you want ). Only these authorized users will have permissions to upload, create, and modify files and directories.

We’re going also to allow anonymous users (basically everyone) to download files and of course we’re going to implement SSL/TLS encryption using a valid certificate ( self_signed) to secure communications between the FTP server and the FTP client .

OK , let’s begin by creating these two local users using a for loop :

Next , let’s remove the default configuration file vsftpd.conf and the user_list file as well :

And let’s create a new one using Vim or any other text editor you prefer :

Let me explain the first part of the parameters :

  • local_root =/path to directory ( The directory which vsftpd will try to change into after a local user login) .
  • anon_root=/path to directory ( The directory which vsftpd will try to change into after an anonymous login).
  • local_enable=YES ( Local users account in /etc/passwd permitted to login ).
  • write_enable=YES ( Allow local users to write , modify , delete … ).
  • userlist_enable=YES ( Allow access only to the users listed in the userlist file , we will create it later ) .
  • userlist_file=/path to file ( The path to the file containing the allowed users ) .
  • userlist_deny=NO ( users will be denied login unless they are explicitly listed in the userlist_file ) .
  • anonymous_enable=YES ( Allow anonymous users to download files ) .
  • no_anon_password=YES ( the anonymous user will log straight in without been asked for password).
  • anon_world_readable=YES ( anonymous users will only be allowed to download files which are world readable).

Let’s continue with the second part :

  • listen=YES ( vsftpd will run in standalone mode and will listen on an IPv4 socket ).
  • listen_ipv6=NO ( vsftpd will not listen on an IPv6 socket ) .
  • hide_ids=YES ( All user and group information in directory or a file will be displayed as “ftp” ) .
  • connect_from_port_20=YES ( vsftpd will use port 20 for initiating passive data transfers ) .
  • pam_service_name=vsftpd ( The name of the PAM service vsftpd will use ) .
  • ssl_enable=YES ( vsftpd will support secure connections via SSL) .
  • rsa_cert_file=/path ( The location of the RSA certificate to use for SSL encrypted connections) .
  • rsa_private_key_file=/path ( The location of the RSA private key to use for SSL encrypted connections) .
  • ssl_tlsv1_2=YES ( The version of SSL , I’m using 1.3 the last one ) .
  • force_local_data_ssl=YES ( force local users to use a secure SSL connection in order to send and receive data) .
  • force_local_logins_ssl=YES ( force local users to use a secure SSL connection in order to send the password) .

And to close with I’m going to add some optional features ( though they are not necessary ) :

  • xferlog_enable=YES ( Enable logging uploads and downloads activities ) .
  • vsftpd_log_file=/path ( the file to which vsftpd write logs to it) .

Notice that we could force SSL on anon_users too and we could also implement additional security measures such as the chroot jail ( I’m just giving you an example here and not an exhaustive guide. so, feel free to customize it according to your preferences) .

Next, let’s proceed with creating the allowed_users file, adding users to it, and creating the certificate and key directories :

And Finally , let’s generate our SSL certificate :

I won’t dive into the detailed workings and components of TLS/SSL certificates ,However I’d like to explain these options used with the openssl tool :

  • req : means that openssl command is being used for certificate requests .
  • x5O9 : means openssl will generate a self-signed certificate rather than a certificate signing request (CSR) .
  • nodes : means the private key should not be encrypted with a passphrase .
  • days 365 : The validity period of the self-signed certificate to 365 days (1 year) .
  • newkey rsa: 2048 : means openssl will generate a new RSA key pair with a key length of 2048 bits .
  • keyout : This option specifies the filename where the private key will be saved .
  • out : This option specifies the filename where the self-signed certificate will be saved .

One thing to be aware of is the the common name ( which is the FQDN of the server ) it must match, otherwise the client will refuse the TLS connection .

Next ,let’s create the anon_root directory and make sure to give the read permission for others :

Next , let’s verify the Selinux file-context on the /var/ftp directory and enable the ftpd_full_access boolean to allow the ftp server to login to local users and read/write all files and start the service ( again Selinux is big topic , we’ll leave it for another day ) .

Finally , let’s open both FTP ports (20 for data and 21 for control ) on the firewall and verify if the service is listening :

Now that everything is in place, let’s put it to the test. I’ll login via a graphical FTP client( FileZilla )and at the same time, I’ll capture the FTP traffic on the server using tshark (which is the text version of Wireshark) to verify if the SSL encryption is functioning correctly.

And as you can see we manage to login successfully, this mean that the TLS handshake worked , let’s further investigate by openning the capture with wireshark :

And as expected , you can see the TLS handshake and subsequent data transmission have been encrypted ( of course we can decrypt the packets using the private key but that will go beyond our subject today) .

Let’s verify the permissions also by uploading some music files.

Great, we’ve confirmed that user Jack can upload files. Now, let’s verify if the anonymous user can only download files. I’ll test this using lftp ( CLI FTP client ) :

Voilà, it seems the anonymous user can indeed download files. Now, let’s test whether the anonymous user can upload files as well :

As expected, the anonymous user cannot upload files.

Notice that there is no need to test the other user (Bob), the result will likely be the same as for user Jack.

I hope you enjoyed this demonstration today. If you have any further questions, feel free to leave them in the comments below.

Thank you for reading. Please don’t forget to like and share, and I’ll see you in the next one .

--

--

Meher Askri

Linux System Engineer || RHCSA, RHCE, VCP-DCV, CCNA and CKA