Introduction
FTP Servers have been around for a very long time. On could easily argue that they aren’t always the best option to choose anymore. But for those dealing with legacy systems, the FTP protocol provides one the easiest ways to share and distribute files across external systems. Despite the hate some might give the protocol; it still receives a lot a love from others just because it’s still very compatible with just about everything; heck, even web browsers such as Internet Explorer, Chrome, and Firefox (and many more) have the protocol built right into it.
In my case, I needed to set up an FTP server to help a client with some legacy software they use (and are familiar with). This blog is more or less just the steps I took to make it work in case anyone else is interested.
Security Concerns
FTP preforms all of it’s transactions in ‘plain text’ including it’s authentication. This wasn’t a problem back in 1980 when online security wasn’t an issue. This also isn’t a problem for sites offering anonymous file hosting services. But for everyone else, it pretty much leaves you susceptible to privacy issues and possible intrusions.
FTPS (not to be confused with SFTP) is a way of securing the FTP protocol for the systems that require it allowing you to eliminate the ‘plain text’ problem. But this requires the client uses software that can take advantage of it.
Some additional security concerns I wanted to consider:
- Separate user accounts from the system ones. We don’t want people trying to guess our root password or access anyone’s home directory unless with specifically configure the server to allow it.
Setup VSFTPD
VSFTPD stands for Very Secure FTP Daemon and provides all the flexibility we need. It’s official website can be found here.
The following will set up VSFTPD into your CentOS/RedHat environment in a isolated manor. You see we want to disconnect the users that currently access your system from the users we create for VSFTPD for more flexibility and control.
# First fetch the required packages # db4: The Berkeley Database (Berkeley DB) which is a # quick and dirty way of storing our user accounts. # db4-utils: This provides a tool we'll use to build a small user # database with. Technically you can uninstall (just) # this package afterwards for added security after. # openssl: This is used to grant our FTP server FTPS support # vsftpd: The FTP/FTPS Daemon itself yum -y install db4 db4-utils openssl vsftpd # Create a password file: /etc/vsftpd/users.passwd # This file contains all of the users you want to allow on the # site in the structure: # Line: Entry # 1 | USERNAME1 # 2 | PASSWORD1 # 3 | USERNAME2 # 4 | PASSWORD2 # This below creates a simple user 'foobar' and a password # of 'barfoo'. This isn't the safest way to build your password # file because it leaves a persons password set available in # the shell history... But for the purpose of this tutorial: echo foobar > /etc/vsftpd/users.passwd echo barfoo >> /etc/vsftpd/users.passwd # Protect our password file now from prying eyes: chmod 600 /etc/vsftpd/users.passwd chown root.root /etc/vsftpd/users.passwd # Prepare a directory we want the foobar user to send it's files # to. You can also just use a directory you already have in place # or someone elses home directory. mkdir -p /var/ftp/foobar # Set a comfortable permission to this directory granting the ftp # user (or any user account your later going to assign to this user # read/write access) chown root.ftp /var/ftp/foobar chmod 775 /var/ftp/foobar # Convert our plain-text password file into the Berkeley Database # format. This is the only command that requires the db4-utils # rpm package which you can uninstall if you want for security # reasons after you run the below command. You'll need to # re-install it though if you ever want to add or update accounts db_load -T -t hash -f /etc/vsftpd/users.passwd /etc/vsftpd/virtual.users.db # Protect our new (Berkley) database: chmod 600 /etc/vsftpd/virtual.users.db chown root.root /etc/vsftpd/virtual.users.db # Prepare our virtual user directory; this is where we can # optionally place over-riding configuration for each user # we create in the Berkley database above. mkdir -p /etc/vsftpd/virtual.users chmod 700 /etc/vsftpd/virtual.users chown root.root /etc/vsftpd/virtual.users # Create PAM Module that points to our new database. # Note: you do not provide the '.db' extension when creating # this file. The file is valid as you see it below. cat << _EOF > /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 session required pam_loginuid.so _EOF # Protect our Module chmod 644 /etc/pam.d/vsftpd-virtual chown root.root /etc/pam.d/vsftpd-virtual # Create an empty jail directory. This is used for default # configurations only. A well configured system won't even use # this; but it's still good to have since we'll be referencing # it in our configuration. This will become the default # directory a user connects to if they aren't otherwise # configured to go to another location. mkdir -p /var/empty/vsftpd/ chown nobody.ftp /var/empty/vsftpd/ chmod 555 /var/empty/vsftpd/ # Now we want to allow FTPS support, we'll need an SSL key to # do it with. If you already have one, you can skip this step. # Otherwise, the following will just generate you a self-signed # key as a temporary solution. openssl req -nodes -new -x509 -days 730 -sha256 -newkey rsa:2048 -keyout /etc/pki/tls/private/nuxref.com.key -out /etc/pki/tls/certs/nuxref.com.crt -subj "/C=7K/ST=Westerlands/L=Lannisport/O=NuxRef/OU=IT/CN=nuxref.com" # Protect our Keys chmod 400 /etc/pki/tls/private/nuxref.com.key; # Private Key chmod 444 /etc/pki/tls/certs/nuxref.com.crt; # Public Certificate # Create ourselves a little banner we can use to at least alert # human intruders that they are in fact being monitored. This # scare tactic may or may not work, but if you ever have a breach # of security, you may need to reference that you gave the user # ample warning that they were violating someones rights by # continuing. Feel free to adjust the banner to your liking. cat << _EOF > /etc/banner * - - - - - - W A R N I N G - - - - - - - W A R N I N G - - - - - * * * * The use of this system is restricted to authorized users. All * * information and communications on this system are subject to * * review, monitoring and recording at any time, without notice or * * permission. * * * * Unauthorized access or use shall be subject to prosecution. * * * * - - - - - - W A R N I N G - - - - - - - W A R N I N G - - - - - * _EOF # Protect our banner chmod 640 /etc/banner
At this point we have our environment set up the way we want it. The next step is to create our VSFTPD configuration.
# Lets first backup original configuration file mv /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.orig # Create new configuration cat << _EOF > /etc/vsftpd/vsftpd.conf # -------------------------------------------------------------- # Base Configuration # -------------------------------------------------------------- anon_world_readable_only=NO anonymous_enable=NO chroot_local_user=YES hide_ids=YES listen=YES local_enable=YES max_clients=10 max_per_ip=3 nopriv_user=ftp pasv_min_port=64000 pasv_max_port=64100 session_support=NO user_config_dir=/etc/vsftpd/virtual.users userlist_enable=YES use_localtime=YES xferlog_enable=YES xferlog_std_format=NO log_ftp_protocol=YES pam_service_name=vsftpd-virtual banner_file=/etc/banner reverse_lookup_enable=NO # -------------------------------------------------------------- # Secure Configuration (FTPS) # -------------------------------------------------------------- ssl_enable=YES virtual_use_local_privs=NO allow_anon_ssl=NO # forcing SSL makes the FTP portion of your site disabled and it # will only operate as FTPS. This may or may not be what you # want. force_local_data_ssl=NO force_local_logins_ssl=NO ssl_tlsv1=YES ssl_sslv2=NO ssl_sslv3=NO # Point to our certificates rsa_cert_file=/etc/pki/tls/certs/nuxref.com.crt rsa_private_key_file=/etc/pki/tls/private/nuxref.com.key require_ssl_reuse=NO ssl_ciphers=HIGH:!MD5:!ADH # -------------------------------------------------------------- # FTP Configuration # -------------------------------------------------------------- async_abor_enable=YES ftp_data_port=20 connect_from_port_20=YES # -------------------------------------------------------------- # Default Anonymous Restrictions (over-ride per virtual user) # -------------------------------------------------------------- guest_enable=NO guest_username=nobody # Default home directory once logged in local_root=/var/empty/vsftpd # write_enabled is required if the user is to make use of any of # the anon_* commands below write_enable=NO # give the user the ability to make directories anon_mkdir_write_enable=NO # give the user the ability delete and overwrite files anon_other_write_enable=NO # give the user the ability upload new files anon_upload_enable=NO # Give the user permission to do a simple directory listings dirlist_enable=NO # Give the user permission to download files download_enable=NO # if the user has can upload or make new directories, then this # will be the umask applied to them anon_umask=0002 # delete failed uploads (speaks for itself) delete_failed_uploads=YES _EOF # Protect our configuration chmod 600 /etc/vsftpd/vsftpd.conf chown root.root /etc/vsftpd/vsftpd.conf
Technically we’re done now, but because we intentionally specified very restrictive user access rights, our foobar user we created will only connect to the /var/empty/vsftpd directory with no access rights. Therefore, our final step is to create an additional configuration file for the foobar account granting him read/write access to /var/ftp/foobar.
# The file you write to in the /etc/vsftpd/virtual.users/ 'must' be the same # name as the user(s) you created to over-ride their permissions! cat << _EOF > /etc/vsftpd/virtual.users/foobar local_root=/var/ftp/foobar # -------------------------------------------------------------- # User # -------------------------------------------------------------- guest_enable=YES # Set this to any system user you want guest_username=ftp local_root=/var/ftp/foobar # -------------------------------------------------------------- # Permissions # -------------------------------------------------------------- # write_enabled is required if the user is to make use of any of # the anon_* commands below write_enable=YES # give the user the ability to make directories anon_mkdir_write_enable=YES # give the user the ability delete and overwrite files anon_other_write_enable=YES # give the user the ability upload new files anon_upload_enable=YES # Give the user permission to do a simple directory listings dirlist_enable=YES # Give the user permission to download files download_enable=YES # if the user has can upload or make new directories, then this # will be the umask applied to them anon_umask=0002 # delete failed uploads (speaks for itself) delete_failed_uploads=NO _EOF # Protect our foobar permission file chmod 600 /etc/vsftpd/virtual.users/foobar chown root.root /etc/vsftpd/virtual.users/foobar
You are now complete, you can start VSFTPD at any time:
# Have VSFTPD start after each system reboot chkconfig --level 345 vsftpd on # Start VSFTPD if it isn't already running service vsftpd status || service vsftpd start
It’s worth noting that if you ever change any of the configuration or add more, you will need to restart the VSFTPD server in order for the changes you made to take effect:
# Restarting the vsftpd server is simple: service vsftpd restart
Firewall Configuration
The FTP firewall configuration can get complicated especially when the ephemeral ports it chooses to open are random (when operating it in Passive mode). If you scan through the configuration file above, you’ll see that we’ve specified this range to be between 64000 and 64100.
In a nutshell, if you choose to use/enable FTPS (which I strongly recommend you do), the firewall configuration will look like this (/etc/sysconfig/iptables):
#.... #--------------------------------------------------------------- # FTP Traffic #--------------------------------------------------------------- -A INPUT -p tcp -m state --state NEW --dport 21 -j ACCEPT # non-encrypted ftp connections (ip_contrack_ftp) module looks # after these ports, however for the encrypted sessions it can't # spy so we need to disable ip_contrack_ftp and just open the # port range himself -A INPUT -p tcp -m state --state NEW --dport 64000:64100 -j ACCEPT #...
However, if (and only if) you choose not to use FTPS and strictly operate using FTP only then your configuration will look as follows:
- /etc/sysconfig/iptables
#.... #--------------------------------------------------------------- # FTP Traffic #--------------------------------------------------------------- -A INPUT -p tcp -m state --state NEW --dport 21 -j ACCEPT #...
- /etc/sysconfig/iptables-config
This file requires you to add ip_conntrack_ftp to the variable IPTABLES_MODULES which is near the top of this file. You may also need to update /etc/sysconfig/ip6tables-config if you are using ip6; the change is the same. This keeps the entire range of 64000 to 64100 ports closed be default and through packet sniffing, they are opened on demand.
#... IPTABLES_MODULES="ip_conntrack_ftp" #...
If you’re not running any other modules, you can use the following one liner to update the file:
sed -i -e 's/^IPTABLES_MODULES=.*/IPTABLES_MODULES="ip_conntrack_ftp"/g' /etc/sysconfig/iptables-config sed -i -e 's/^IPTABLES_MODULES=.*/IPTABLES_MODULES="ip_conntrack_ftp"/g' /etc/sysconfig/ip6tables-config
Be sure to reload your firewall configuration once you have these in place:
# Restart the firewall service iptables restart
Fail2Ban Brute Force Configuration
The final thing you should consider if your server will be available via the internet is some bruit force prevention. I really recommend you read my blog on Securing Your CentOS 6 System, specifically my blurb on Fail2Ban which I think all systems should always have running. Fail2ban allows you to track all users hitting your FTP server and take immediate action on preventing further access to this potential intruder.
The configuration is as follows (remember to set the email to what you want it as where I’ve specified your@email.goes.here so you can be notified of any intrusions that take place.
cat << _EOF >> /etc/fail2ban/jail.conf [my-vsftpd-iptables] enabled = true filter = vsftpd action = iptables[name=VSFTPD, port=ftp, protocol=tcp] sendmail-whois[name=VSFTPD, dest=your@email.goes.here] logpath = /var/log/vsftpd.log _EOF
Be sure to reload your Fail2Ban configuration once this is done
# Restart Fail2Ban service fail2ban restart
Test Our Configuration
Make sure you have an ftp tool installed into your environment like lftp or even a GUI based tool like FileZilla that supports both FTP and FTPS. The old Linux tool ‘ftp’ will only allow you to test the un-encrypted connection.
# Install lftp to keep things simple yum -y install lftp # Test our server (FTP) [root@nuxref ~]# lftp ftp://foobar:barfoo@localhost lftp foobar@localhost:~> pwd ftp://foobar:barfoo@localhost lftp foobar@localhost:~> exit # Test our server (FTPS) [root@nuxref ~]# lftp ftps://foobar:barfoo@localhost lftp foobar@localhost:~> pwd ftps://foobar:barfoo@localhost lftp foobar@localhost:~> exit
First lets just test the basic FTP portion (plain-text):
# Connect to our server [root@nuxref ~]# ftp localhost Connected to localhost (127.0.0.1). 220-* - - - - - - W A R N I N G - - - - - - - W A R N I N G - - - - - * 220-* * 220-* The use of this system is restricted to authorized users. All * 220-* information and communications on this system are subject to * 220-* review, monitoring and recording at any time, without notice or * 220-* permission. * 220-* * 220-* Unauthorized access or use shall be subject to prosecution. * 220-* * 220-* - - - - - - W A R N I N G - - - - - - - W A R N I N G - - - - - * 220 Name (localhost:nuxref): foobar 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> ls 227 Entering Passive Mode (127,0,0,1,250,83). 150 Here comes the directory listing. 226 Directory send OK.
If you plan on using FileZilla as your solution, You need to configure it to connect as the FTP protocol with the Encryption set to Requires explicit FTP over TLS similar to the screen shot I provided.
You may or may not have to accept your certificate afterwards that we created earlier in this blog.
FileZilla On-Going FTPS Bug
The FileZilla Client is a pretty sweet application for those who like to work with a GUI instead of a command line. Those who choose to test their configuration with this should just know that there is an outstanding bug with FileZilla and the FTPS protocol. Hence, if you’re using Filezilla to to test your new VSFTPD server and it’s not working, it might not be your configuration at the end of the day. The versions seem to be hit and miss of which cause the bug to surface; reports of v3.5.2 working and v3.5.3 not. That all said, I’m using v3.7.3 and am not having a problem.
Here is the ticket #7873 that identifies the problem. One thing that is mentioned is that an earlier version of FileZilla works perfectly fine (specifically v3.5.2). But I’ve also had no problem with the current version (at the time was v3.7.3). I guess my main point is… don’t panic if you see this error; it’s not necessarily anything you’ve configured incorrectly. If you followed this blog then you shouldn’t have any issue at all.
Credit
I may not blog often; but I want to re-assure the stability and testing I put into everything I intend share.
If you like what you see and wish to copy and paste this HOWTO, please reference back to this blog post at the very least; it’s really all that I ask of you.