Configure SFTP access with ProFTPd

Since version 1.3.3rc1 ProFTPd have a mod_sftp module. This module implements the core functionalities of the SSH2 protocol and its SFTP subsystem.

Using ProFTPd implementation brings some practical advantages:

  • no need to spawn another OpenSSH daemon on a another port
  • no need to tweak sshd_config to allow chrooted SFTP
  • you can chroot a user into any directory even ones which doesn’t belong to root
  • you can use ‘virtual’ accounts instead of unix ones

Enable SFTP support

Add the following block to /etc/proftpd/proftpd.conf:

SFTPEngine on

Port 115
SFTPLog /var/log/proftpd/sftp.log
TransferLog /var/log/proftpd/sftp-xferlog

# Host Keys
SFTPHostKey /etc/ssh/ssh_host_rsa_key
SFTPHostKey /etc/ssh/ssh_host_dsa_key

# SFTP specific configuration
DefaultRoot ~

I arbitrary chose the port TCP 115 because that the port for SFTP after all (just not the same SFTP) 😉

Choose the authentication method

Like OpenSSH it can be done by password or by public key. For password add the following snippet to /etc/proftpd/proftpd.conf:

# Authentication method
SFTPAuthMethods password
AuthUserFile /etc/proftpd/sftp.passwd

If you prefer using keys:

# Authentication method
SFTPAuthMethods publickey
SFTPAuthorizedUserKeys file:/etc/proftpd/sftp.passwd.keys/%u

Create users accounts

We will use ProFTPd virtual account system. First we create the account file:

touch /etc/proftpd/sftp.passwd
chown proftpd /etc/proftpd/sftp.passwd
chmod go-rwx /etc/proftpd/sftp.passwd

File syntax is very simple:

username:PASSWORD_HASH:UID:GID:Comment for human:/home/user_home:/bin/bash

To generate the password you can use pwgen and hash it with md5 like this:

PASS=$(pwgen -Bs1 15); echo $PASS
mkpasswd --hash=md5 $PASS

UID and GID must be numerical values. You can use value from an actual unix account to map the virtual user to it.

Add user public keys

If you prefer using keys authentication, create a dedicated directory for storing keys:

mkdir /etc/proftpd/sftp.passwd.keys
chown proftpd /etc/proftpd/sftp.passwd.keys
chmod go-rwx /etc/proftpd/sftp.passwd.keys

Then create a file per SFTP user and fill it with the public keys you want. Don’t forget to convert them into RFC4716 format before:

ssh-keygen -e -f key_to_convert.pub > key_in_rfc4716.pub

After all theses modifications, restart ProFTPd and test. Adjust firewall rules accordingly.

Further Reading and sources

[OpenBSD] pf tips

Find a rule match

Let say you think a port is filtered by IP but it’s not. You have a somewhere a rule to open for your taste. How to find it ?

First establish a connection from a given IP:

test-host ~ $ nc -v 91.216.209.157 21

Then on the firewall list state connection from this IP:

fw5:~# pfctl -vvv -ss | grep -A3 78.192.224.148
all tcp 91.216.209.157:21 <- 78.192.224.148:56272       ESTABLISHED:ESTABLISHED
   [899608849 + 29200] wscale 7  [1508798648 + 5889] wscale 4
   age 00:00:41, expires in 04:59:19, 3:2 pkts, 164:164 bytes, rule 72
   id: 5565c647ffd1505e creatorid: 410e4752

The matched rule has the number 72.

Find a rule by its number

When doing a tcpdump on the pflog interface, matches are displayed using a number. To find the corresponding rule list them all and filter them:

fw3:~# pfctl -sr -g | grep '@72'

Purge a 'stuck' rule

When a relayd failover goes wrong, you can find yourself with a 'stuck' anchor rule. To list them all:

fw3:~# pfctl -a relayd/* -s rules

Find the outdated rule, then remove it manually:

fw3:~# pfctl -a relayd/foobar_https -F rules

Restricted SFTP access

FTP is an old protocol created when network was a ‘new thing’ and everybody was a ‘care bears’, therefore it’s insecure by design and you shouldn’t even propose it to yours customers. Instead always push the SFTP option first.

For practical usage, there is three little downsides to SFTP use:

  • SFTP doesn’t have it own dedicated port. Personally i like to reuse the ‘Simple File Transfer Protocol’ port (TCP 115) but this ideas is enough to trigger heart attacks to network ‘ayatollah’
  • each user must have an unix account
  • an SFTP access isn’t by default chrooted inside the user directory

SFTP on a dedicated port

Until we have SFTP support inside ProFTPD, the only solution is to spawn a second OpenSSH daemon on a separated port.

Here a snippet of my new setting file /etc/ssh/sftp-115:

Port 115

# Protocol
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
UsePrivilegeSeparation yes

# Restriction
AcceptEnv no
AllowAgentForwarding no
AllowTcpForwarding no
Banner no
MaxAuthTries 3

# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768

# Logging
SyslogFacility AUTH
LogLevel INFO
UseDNS no

# Authentication
LoginGraceTime 120
PermitRootLogin no
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile /home/sftp/%u/.ssh/authorized_keys
PasswordAuthentication yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no

# Disable some options
UsePAM no
X11Forwarding no
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes

# Use sftp-internal (allow chroot)
Subsystem sftp internal-sftp
ForceCommand internal-sftp

Before OpenSSH 4.8 there is no internal-sftp module, therefore you must use the external command sftp-server instead:

Subsystem sftp /usr/lib/openssh/sftp-server

For launching the daemon you can use xinetd, clone and modify your distribution OpenSSH init script or simply add a one-liner inside the /etc/rc.local:

/usr/sbin/sshd -f /etc/ssh/sftp-115

Do as you wish.

Unix user account

Not much to say here, you must create a proper unix account for each SFTP. I suggest you to set the home directory to something like /home/sftp/<user> to distinguish easily theses users from regular ones.

In case you use sftp-server you must also change the user shell value. First add sftp-server as a valid shell :

# echo '/usr/lib/stfp-server' >> /etc/shells

Then for each SFTP unix account:

# usermod -s /usr/lib/sftp-server <user>

Chroot user

If you use internal-sftp simply add the following snippet to /etc/ssh/sftp-115:

ChrootDirectory /home/sftp/%u

For sftp-server, bad news, you simply can’t chroot users.

To give user access to a directory use the mount --bind command:

mount --bind /var/www/foobar /home/user/foobar/www

Don’t forget to add this line into your SFTP daemon init script.

Check TCP/UDP port with netcat

netcat, usually abbreviated in nc, is a network tool able to reads and writes data across network connections using TCP or UDP protocol. It’s a feature-rich tool, that every admin should know.

Check TCP port

nc -zv 192.168.0.10 80
Connection to 192.168.0.10 80 port [tcp/http] succeeded!

Check UDP port

nc -zuv 192.168.0.10 123
Connection to 192.168.0.10 123 port [udp/ntp] succeeded!

Not that contrary to TCP, UDP is a connectionless protocol. In theory if an UDP port is formally “closed” (for example via an iptables REJECT rule) the destination host should respond with an ICMP Port unreachable packet. But a lot of firewall simply silently drop the message, resulting in a wrong ‘succeed’ result.

Scan a range of ports

To find all the open ports in a given range:

nc -zv 192.168.0.10 1-500 2>&1 | grep succeeded
Connection to 192.168.0.10 21 port [tcp/ftp] succeeded!
Connection to 192.168.0.10 22 port [tcp/ssh] succeeded!
Connection to 192.168.0.10 80 port [tcp/http] succeeded!

To run a pseudo-server on a given port

nc -l -p 3873

[OpenBSD] relayd

relayd is an open source load balancer which is able to handle protocol layers 3, 4 and 7. It’s the standard “in-house” load-balancing solution of OpenBSD. It can be setup as a forward, reverse or TCP port redirector and/or SSL/TLS ‘terminator’.

Basic commands

Check relayd configuration:

# relayd -n -f /etc/relayd.conf

Show detailed status of hosts and tables:

# relayctl show host

Show detailed status of redirections including the current and average access statistics:

# relayctl show redirects

Show detailed status of relays including the current and average access statistics:

# relayctl show relays

Dump the complete list of running relay sessions:

# relayctl show sessions

Display a list of all relays, redirections, routers, tables, and hosts:

# relayctl show summary

Schedule an immediate check of all hosts:

# relayctl poll

Reloading configuration

You can reload the current configuration file with the command:

# relayctl reload

Beware, this command will flush the current ‘state’ and provoke a short downtime. Also it seems that if you have SSL ressources, reload make relayd crash. So instead of using this command you should make a CARP failover “switch” and restart the process like this :

# pkill relayd && sleep 1 && relayd -f /etc/relayd.conf && relayctl poll

[OpenBSD] Forcing CARP failover

To force a CARP failover from a master firewall/router to its slave, you can manually change the value of the demotion counter like this:

fw1:~# ifconfig -g carp carpdemote 50

This command will increase the advskew value of all CARP interface on the host by the demotion counter value. The interface with the lowest advskew value will be promoted ‘MASTER’. I use a base advskew value of 80 on the master host and 120 on the slave. The failover should be transparent to end users.

You can check the current interfaces states and their advskew values like this:

fw2:~# ifconfig carp | grep adv
        carp: MASTER carpdev em1 vhid 150 advbase 8 advskew 80
        carp: MASTER carpdev em1 vhid 151 advbase 8 advskew 80
        [...]

To switch back simply decrease the demotion counter in order to have a lower value on the master again:

fw1:~# ifconfig -g carp -carpdemote 50

[OpenBSD] ftp-proxy and ephemeral port

As you may already know, FTP is a pain in the a** for firewall configuration and doesn’t work well through NAT. Hopefully OpenBSD propose an elegant solution: diverting FTP traffic through a proxy server while dynamically modify Packet Filter’s rules on the fly 🙂

This proxy is very simple to enable. Just add something like this in your PF setting file:

anchor "ftp-proxy/*"
pass in quick on $int_if proto tcp to port 21 divert-to 127.0.0.1 port 8021

Then start the ftp-proxy daemon. By default it’s bound on TCP 8021.

Now you may encounter a connection issue with some ‘old’ FTP client in active mode. The reason for that is that ftp-proxy doesn’t strictly follow the RFC 959. In order to avoid port collisions ftp-proxy use an ephemeral port as a source port instead of the port 20. To force a very ‘RFC-compliant’ behaviour add the option -r to startup like this:

vi /etc/rc.conf.local
ftpproxy_flags="-r"

[Debian] Network bonding

Network bonding is a technique that ‘bind’ multiple network interfaces into a single channel/NIC in order to increase redundancy or throughput.

Depending the operating system other term are used like :

  • OpenBSD: network trunking
  • Cisco: Etherchannel
  • HP-UX: Auto-port
  • AIX: Link-aggregation

Don’t be fooled by marketing term, in the end the concept is always to aggregate multiple interfaces into a single virtual one.

If you want to increase redundancy your ideal setup should be aggregating two interfaces using two different network cards connected to two separate switches. The bonding will be in active / passive mode, only using one port a time. This setup not only ensures high availability operation, but more importantly, allows for maintenance of network switches without service interruption.

Here’s how to make the bonding on Debian Lenny :

Prerequisites

  • install ifenslave
  • kernel module ‘bonding’ loaded

Modify network setting

lenny:~# vi /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto bond0
iface bond0 inet static
      slaves eth0 eth1
      bond_mode active-backup
      bond_miimon 100
      bond_downdelay 200
      bond_updelay 200
      address xxx.xxx.xxx.xxx
      netmask xxx.xxx.xxx.xxx
      network xxx.xxx.xxx.xxx
      gateway xxx.xxx.xxx.xxx
lenny:~# /etc/init.d/networking restart

The slaves command specify which interfaces to aggregate, and bond_mod how. Here we use active-backup but if you setup bonding in order to increase throughput check the balance_rr mode instead.

Further Reading and sources

[Cisco] ASA – Displaying pre-shared keys

Normally you use the show run command to browse the running configuration. When doing it pre-shared keys for VPN tunnels are displayed as asterisks. In order to view the full configuration with unencrypted passwords, use the command:

more system:running-config