VsFTPd Notes
[TOC]
Pre-Install notes
The “Very Secure FTP Daemon” is highly configurable package in many
aspects. These include virtual users, SSL transfers, chrooting, and so
on. This guide sets up VSFTP with the following features:
- A modified FTP root at
/tempftpdir
- A sample virtual user called
tempuser
- The user will be chrooted to
/tempftpdir/tempuser
- All transactions will take place over implicit SSL
- The daemon will run as a standalone service (i.e. will not
involve xinetd)
Download and install VSFTPD and associated packages
yum install vsftpd db4-utils db4
The last two packages are for the Berkeley DB which PAM uses to look up
virtual users and their passwords.
Basic configuration
The config file is found at /etc/vsftpd/vsftpd.conf
Here are the
pertinent directives which have changed from the original file (which
I’m assuming you will back up before trying this stuff.)
anonymous_enable=NO
dirmessage_enable=NO
xferlog_file=/var/log/vsftpd.xferlog.tempftpdir.log
ftpd_banner=Welcome to the CLCG FTP droppoint. Please note that all activity is logged.
# Comment this directive (we will be using another for virtual users)
pam_service_name=vsftpd
Managing virtual users
Create the database
You will need to create a text file which has the usernames and
passwords on newlines. E.g.
user1
password1
user2
password2
In this case, I’m going to create a user called tempuser with the
password tempuserpass. So I create a file called “userlist.txt” with
the following contents:
tempuser
tempuserpass
Now I can create the database for the PAM using this:
db_load -T -t hash -f userlist.txt vsftpd-virtual-user.db
Configure the home directory
Since the FTP root is /tempftpdir
, you will need to add a home directory
that tempuser
can be chrooted to.
mkdir /tempftpdir/tempuser
chown -R ftp:ftp /tempftpdir
It should be obvious why ftp:ftp
owns this directory; tempuser
is
a virtual user and so does not have any entry in /etc/passwd
!
Tell PAM about the database
Head over to /etc/pam.d/
and create a file
called vsftpd.withvirtualusers
The filename
can be anything you want. You will need to remember it later!
Add the following to the new file:
#%PAM-1.0
auth required pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user
account required pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user
session required pam_loginuid.so
Configuring VSFTPD to have virtual users
Append the following to the configuration file:
# Allow virtual users
virtual_use_local_privs=YES
guest_enable=YES
user_sub_token=$USER
# Change the FTP root
local_root=/tempftpdir/$USER
chroot_local_user=YES
hide_ids=YES
# Use the new file we just created; this is why it was commented earlier!
pam_service_name=vsftpd.withvirtualusers
# Define passive ports
pasv_min_port=12000
pasv_max_port=12003
At this point, you should be ready to start the service. However, you
need to poke a hole in your firewall to allow FTP connections
Configuring IPTABLES to allow FTP
# Allow VSFTPD and associated passive connections
-A INPUT -m state --state NEW,ESTABLISHED -p tcp --dport 21 -j ACCEPT
-A INPUT -m state --state NEW,ESTABLISHED -p tcp --dport 12000:12003 -j ACCEPT
Restart the iptables service (do it properly and use iptables-save
and iptables-restore
)
Start the service
service vsftpd start
Check if it’s listening to port 21 by trying this…
netstat -tulpn | grep :21
… and seeing something like this:
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN 29790/vsftpd
Try it out by logging in as tempuser
with tempuserpass
. All should go well :)
Securing VSFTPD with SSL
Assuming things have been amazing thus far, you can now SSL enable the
service for logins and transfers.
Generate an RSA certificate
cd /etc/vsftpd
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout vsftpd.pem -out vsftpd.pem
Here’s the standard output of this command:
Generating a 1024 bit RSA private key
.......++++++
........................................++++++
writing new private key to '/etc/vsftpd/vsftpd.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:Iowa
Locality Name (eg, city) [Newbury]:Iowa City
Organization Name (eg, company) [My Company Ltd]:Coordinated Laboratory for Computational Genomics
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:ftp.example.com
Email Address []:clcg.it@gmail.com
SSL-enable VSFTPD
Open up /etc/vsftpd/vsftpd.conf
and append the following:
# Enable SSL
ssl_enable=YES
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/vsftpd/vsftpd.pem
Your certificate must be in PEM format and include both the public and
private keys. Here’s an example of what it would look like:
-----BEGIN CERTIFICATE-----
MIIEHTCCA4agAwIBAgIBFjANBgkqhkiG9w0BAQUFADCB1zELMAkGA1UEBhMCVVMx
DTALBgNVBAgTBElvd2ExEjAQBgNVBAcTCUlvd2EgQ2l0eTEfMB0GA1UEChMWVGhl
IFVuaXZlcnNpdHkgb2YgSW93YTE+MDwGA1UECxM1VGhlIENvb3JkaW5hdGVkIExh
Ym9yYXRvcnkgZm9yIENvbXB1dGF0aW9uYWwgR2Vub21pY3MxHjAcBgNVBAMTFXN1
cHBvcnQuZW5nLnVpb3dhLmVkdTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBlbmcu
dWlvd2EuZWR1MB4XDTEyMDQyNzE4MDgwMFoXDTIyMDQyNTE4MDgwMFowgb8xCzAJ
BgNVBAYTAlVTMQ0wCwYDVQQIEwRJb3dhMR8wHQYDVQQKExZUaGUgVW5pdmVyc2l0
eSBvZiBJb3dhMT4wPAYDVQQLEzVUaGUgQ29vcmRpbmF0ZWQgTGFib3JhdG9yeSBm
b3IgQ29tcHV0YXRpb25hbCBHZW5vbWljczEaMBgGA1UEAxMRcWluLmVuZy51aW93
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANCYdLYqvSJ4XYiJwl2Bcmc7A/bs
7RbmeEqmdCBEF/ORZ1Qz3PZkAgDiaSNCdNU8/Z1RMzK8yxQpNTlUO0rTTxmEpCkl
TLMfvGL5+ef8dry9+dT9VZZTncW9GizQpAlKd9Bix3I7XHN/1MdjWs4zmvjgxARX
qYGKCLrwBX8VueimV2h1ac50ngAxMHMjQGF6LvdqkGJcwOfg/ArWU5dlu1U9DkAI
1QvhTqu0+GfvPKbdVp3VdxPJwbCxBFRbiao7QgrnHBSwnhExR6engcPMMcto3b+R
N+1CJ5RyMmpPVRF9dx+ey3WsZkZBmpCpMMUM8UqMrGyRE36OVnloOPRC3WkCAwEA
AaOBijCBhzAJBgNVHRMEAjAAMDoGCWCGSAGG+EIBDQQtFitDTENHIEdlbmVyYXRl
ZCBDZXJ0aWZpY2F0ZSAoT3BlblNTTCB2MC45LjYpMB0GA1UdDgQWBBTKWGxGUSgn
VW1NrP/04akS1qXtBDAfBgNVHSMEGDAWgBSMMdfJB8d71bkJ62WSA8T2X2GrBTAN
BgkqhkiG9w0BAQUFAAOBgQAhJpwbcbUS7pLYEahppPin5+6DDtPNqTjVvpHHjpL0
ZMYEw1E8STzc96FlWO1r/NrHrB1R3qqn5Ptynk7hEH0IrIJjWhv36GCDEvTxpQri
Kir4Qt3i5hFWiSJnB5/BrRcqnHFYKhcwZvF72Da3B1oxQPI9J0eaAxHLiYfUVfys
IA==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA0Jh0tiq9InhdiInCXYFyZzsD9uztFuZ4SqZ0IEQX85FnVDPc
9mQCAOJpI0J01Tz9nVEzMrzLFCk1OVQ7StNPGYSkKSVMsx+8Yvn55/x2vL351P1V
llOdxb0aLNCkCUp30GLHcjtcc3/Ux2NazjOa+ODEBFepgYoIuvAFfxW56KZXaHVp
znSeADEwcyNAYXou92qQYlzA5+D8CtZTl2W7VT0OQAjVC+FOq7T4Z+88pt1WndV3
E8nBsLEEVFuJqjtCCuccFLCeETFHp6eBw8wxy2jdv5E37UInlHIyak9VEX13H57L
daxmRkGakKkwxQzxSoysbJETfo5WeWg49ELdaQIDAQABAoIBAQCPiakeRXCajKsI
LouB3naD1JdYzhYjoPn7nGjiXxkAMPkidwHAxnaedy4T5kIRDgQSwfJyInm36NdI
GM8oIRoYHC7+ZT1PMTJoBU3TNeXa4PtOdfj0FZvGmuatGfEWt5iU27QUxgZLMBaS
++8Joqb6k5M3pfbuA0wtf083EN/mz20pIC2q/EEWd7Za8PPb7+t8iWMnLECg5Ulp
urSj37X9p7M5b3Spf3FksL5YKG/tzvHa7+9hRFScpldt+dKDtN5SKxanlObD10Dv
RRFqzVwBAoGBAO1YJRnTfYFqCl+Bt311Vtm8TDqYRBNlfaZjX+dG20zEX8LjLbXl
YumrdD62uii+KhJVzLyIwh++cKB5MCR2PZZwPX+WAJ5vGk7pfHEi+/5dPttM5k0q
gtirDlwaGJjTa4lVQTP/x0uxGMT03b8+q9qzDcdisx+7EMtS3EZuNWvpAoGBAOD9
042RpbyTNXfa38Bl2Or2wuuB5Z2T9Zu9+WlnqdwrXNx9ocRl2XyYJVwfL7DY9nSr
9VJF/aWe5Bmc9/um6/IGry0auw7M4vGBSRNIFFx5411DIheVdsuZPZT+Hop6woUk
Xr91AtJhpOci4uErmgq9HM8OA3NAWShRLDIDFnWBAoGBAMhGOcBKMrxyQ2CF79SA
oBHJDzXeaItJd7ZgYnug0co8ZmXoFxlG/6kXkVaeEAXzOUMRfVqVt+DbbOQsftA1
qhB4k5xGci0+qR9vbB93mtXvzut0P11cAt9bsBlNt/W1aSeQdh2vtncLcFA6I6eN
9avsrTLS+T1MN4aqW89ejduJAoGBAKrTLa+cOQkvf/YrYZ1z9rmXd7FWI997uoxw
NhE4mvhGmC/010EFz5ZQ8nS6XPxaDu3Qree0qnv4Ytmrm4EfYJ+XQaPuWr5HA7w3
3CLepE7+YImr8hOT8OluxRn9w3SC9nQehC27itPvPUQc8cPi1gd3RItU6Xu1DLyW
vQaP35qBAoGAbfJUtnAk/FuFFQ3bUmOyqC44lURYXqpDBWlTCiA6cXoZ5ciudcW3
vhIGg1EPda+fliy1LolV1AjG73+vnDgykggu8H1fOKEv7MfvsaLwGUovsz5MeXN+
xTI8WOKyrAg8ON1DI3uWVhb07HBUGcWS1vUxESXqa9K4+bAbRYFT/9U=
-----END RSA PRIVATE KEY-----
Restart the service
service vsftpd condrestart
You can now use an FTP client which supports implicit SSL (Transmit and
Fugu for OS X, FileZilla, etc) and try out the connection. The ordinary
ftp
won’t work and will give you the
following error:
Connected to ftp.example.com.
220 Welcome to the FTP droppoint. Please note that all activity is logged.
Name (ftp.example.com:tech): tempuser
530 Non-anonymous sessions must use encryption.
If you’re a command-line freak like I am, you can always use
ftp-ssl
Other notes
- The passive ports must be defined! Not doing so will result in a
very long delay between initiating a connection and viewing a
directory listing. - VSFTPD can be configured for anonymous logins whereby a user can
download a file but not upload anything (like the CentOS mirrors.) - Add
listen_address=127.0.0.1
to listen on a given address.
Resources
Script to add users to database
#!/bin/bash
# Add a virtual FTP user to VsFTPd's Berkeley DB
# by Nikhil Anand, Mon Feb 22 09:30:45 CST 2010
# Paths to config path and custom FTP directory
VSFTPDPATH="/etc/vsftpd"
DROPPOINT="/data/ftp"
# Usage information
if [ $# -ne 2 ]; then
echo -e "USAGE: `basename $0` <username> <password>\n"
echo -e " Using this without the parameters will refresh the DB used by the VsFTP daemon"
db_load -T -t hash -f $VSFTPDPATH/userlist.txt $VSFTPDPATH/vsftpd-virtual-user.db
echo -e " Database refreshed."
echo -e " Edit $VSFTPDPATH/userlist.txt to make any changes to virtual users."
echo -e " Run this script again when you're done."
exit
fi
# Define username and password
USERNAME="$1"
PASSWORD="$2"
# Add username and password to flat text file
echo $USERNAME >> $VSFTPDPATH/userlist.txt
echo "$PASSWORD" >> $VSFTPDPATH/userlist.txt
echo -e "Added ( $USERNAME : $PASSWORD ) to $VSFTPDPATH/userlist.txt"
# Refresh the Berkeley DB to reflect these additions
db_load -T -t hash -f $VSFTPDPATH/userlist.txt $VSFTPDPATH/vsftpd-virtual-user.db
echo -e "Reloaded database \"vsftpd-virtual-user.db\""
# Create a home directory inside the FTP directory
mkdir $DROPPOINT/$USERNAME
chown -R ftp:ftp $DROPPOINT/$USERNAME
echo -e "Created and changed permissions for $DROPPOINT/$USERNAME"