23 December, 2015
A major new feature in fwknop has been introduced today with the
2.6.8 release
(
github tag) - the
ability to integrate with third-party devices. This brings SPA operations easily to
any device or software that offers a command line interface. By default,
the fwknop daemon supports four different firewalls: iptables, firewalld, ipfw, and PF.
But, suppose you want to have fwknopd leverage
ipset instead? Or, suppose you have an
SSH pre-shared key between a Linux system and a Cisco router, and you want fwknopd
(running on the Linux box) to control the ACL on the router for the filtering portion of
SPA? Finally, suppose that you want a stronger measure of protection for an SSH daemon
that
may have been backdoored, and that runs on a
proprietary OS where fwknopd can't be deployed natively? The sky is the limit, and
I would be interested in hearing about other deployment scenarios.
These scenarios and many others are now supported with a new "command open/close cycle"
feature in
fwknop-2.6.8. Essentially, fwknopd has the ability to execute an arbitrary command
upon receiving a valid SPA packet (the "open"), and then execute a different command after a
configurable timeout (the "close"). This allows fwknopd to integrate with any third-party
device or software if open and close commands can be defined for how to interact. These
commands are specified on a per-stanza basis in the access.conf file, and a set of variable
substitutions are supported such as '
$SRC', '
$PORT',
'
$PROTO', and '
$CLIENT_TIMEOUT'. Naturally, the IP address, port, and
protocol are authenticated and decrypted out a valid SPA packet - i.e., SPA packet headers
are not trusted.
Let's see an example on a Linux system ("
spaserver"). Here, we're going to have fwknopd interface with
ipset instead of iptables. First, we'll create an ipset named
fwknop_allow,
and we'll link it into the local iptables policy. If a packet hits the
fwknop_allow ipset and there is no matching source IP, then the DROP rule at the
end of the iptables policy implements the default-drop policy. No userspace daemon such
as SSHD can be scanned or otherwise attacked from remote IP addresses without first
producing a valid SPA packet.
[spaserver]# ipset create fwknop_allow hash:ip,port timeout 30
[spaserver]# iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
[spaserver]# iptables -A INPUT -m set --match-set fwknop_allow src,dst -j ACCEPT
[spaserver]# iptables -A INPUT -j DROP
Now, we create a stanza in the fwknop
/etc/fwknop/access.conf file and fire up
fwknopd like this:
[spaserver]# cat /etc/fwknop/access.conf
SOURCE ANY
KEY_BASE64 <base64 string>
HMAC_KEY_BASE64 <base64 string>
CMD_CYCLE_OPEN ipset add fwknop_allow $SRC,$PROTO:$PORT timeout $CLIENT_TIMEOUT
CMD_CYCLE_CLOSE NONE
[spaserver]# service fwknopd start
With fwknopd running and iptables configured to drop everything except for IP
communications that match the
fwknop_allow ipset, let's use the fwknop client
from a remote system "
spaclient" to gain access to SSHD on the server for 30 seconds
(note that the iptables conntrack module will keep the connection open after the SPA
client IP is removed from the ipset). We'll assume that the encryption and HMAC keys
have been previous shared between the two systems, and on the client these keys have
been written to the "spaserver" stanza in the
~/.fwknoprc file:
[spaclient]$ fwknop -A tcp/22 -a 1.1.1.1 -f 30 -n spaserver
[spaclient]$ ssh user@spaserver
[spaserver]$
So, behind the scenes after the SPA packet has been sent above, fwknopd on the server has
authenticated and decrypted the SPA packet, and has executed the following ipset command.
In this case, there is no need for a corresponding close command because ipset implements
the timer provided by the client itself, so the client IP is deleted from the ipset
automatically. (In other scenarios, the close command can be fully specified instead of
using the string '
NONE' as we have above.) Here are the syslog messages that
fwknopd has generated, along with the
'
ipset list' command output to show the 1.1.1.1 IP as a member of the set:
[spaserver]# grep fwknopd /var/log/syslog |tail -n 2
Dec 23 15:38:06 ubuntu fwknopd[13537]: (stanza #1) SPA Packet from IP: 1.2.3.4 received with access source match
Dec 23 15:38:06 ubuntu fwknopd[13537]: [1.2.3.4] (stanza #1) Running CMD_CYCLE_OPEN command: /sbin/ipset add fwknop_allow 1.1.1.1,6:22 timeout 30
[spaserver]# ipset list
Name: fwknop_allow
Type: hash:ip,port
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 timeout 30
Size in memory: 224
References: 0
Members:
1.1.1.1,tcp:22 timeout 27
In addition to the ability to swap out the existing firewall with a completely
different filtering infrastructure, there are other notable features and fixes in the
2.6.8 release. The most important of these is a new feature implemented by Jonathan Bennett
(and suggested by Hank Leininger in github issue
#62)
that allows access.conf files to be imported via a new '
%include' directive.
This can be advantageous in some scenarios by letting non-privledged users define
their own encryption and authentication keys for SPA operations. This way, users do
not need write permissions to the main
/etc/fwknop/access.conf file to change keys
around or define new ones.
The complete ChangeLog is available
here, and the current test suite has achieved
90.7% code coverage (measured by lines).