Protecting SSH Servers with Single Packet Authorization

Lock down access to SSH with Single Packet Authorization.
SPA via Symmetric Encryption

On the spa_client system, we use fwknop to build an SPA packet encrypted via Rijndael and send it on its way to the spa_server system. We want access to SSHD, and the -A argument below encodes the desired access within the SPA packet. The -w argument resolves the IP address of the client system by querying (this is useful if the fwknop client is behind a NAT device), the -k argument is the IP address of the destination SPA server, and -v runs in verbose mode so we can view the raw packet data:

[spa_client]$ fwknop -A tcp/22 -w -k -v
[+] Starting fwknop in client mode.
    Resolving external IP via:
    Got external address:

[+] Enter an encryption key. This key must match a key
    in the file /etc/fwknop/access.conf on the remote system.

Encryption Key:

[+] Building encrypted single-packet authorization
    (SPA) message...
[+] Packet fields:

        Random data: 7764880827899123
        Username:    mbr
        Timestamp:   1171133745
        Version:     1.0.1
        Action:      1 (access mode)
        MD5 sum:     yzxKgnAxwUA5M2YhI8NTFQ

[+] Packet data:

U2FsdGVkX1+BvzxXj5Zv6gvfCFXwJ+iJGKPqe2whdYzyigkerSp \
2WtvON/xTd8t6V6saxbg1v4zsK+YNt53BE8EInxVCgpD7y/gEBI \

[+] Sending 150 byte message to over udp/62201...

As you can see from the Packet data section above, the SPA packet is a completely unintelligible blob of encrypted data. On the spa_server system, the following syslog message is generated indicating that an ACCEPT rule has been added for the source IP ( that generated the SPA packet. Note that the source IP is put within the SPA packet by the fwknop client. In this case, the SPA packet was not spoofed, so the real source address and the source address embedded in the SPA packet match. SPA packets can be spoofed by fwknop with the --Spoof-src command-line argument (requires root):

Feb 10 13:55:44 spa_server fwknopd: received valid Rijndael \
encrypted packet from:, remote user: mbr
Feb 10 13:55:44 spa_server fwknopd: adding FWKNOP_INPUT ACCEPT \
rule for -> tcp/22 (30 seconds)

So, for 30 seconds after sending the SPA packet, the iptables policy on the spa_server allows the spa_client system to establish an SSH session:

[spa_client]$ ssh -l mbr
mbr@spa_server's password:

After 30 seconds has expired, knoptm (a dæmon responsible for deleting iptables rules added by fwknopd to the iptables policy) deletes the ACCEPT rule and writes the following messages to syslog:

Feb 10 13:52:17 spa_server knoptm: removed iptables \
FWKNOP_INPUT ACCEPT rule for -> tcp/22, \
30 second timeout exceeded

Our SSH session remains established after the ACCEPT rule is deleted because of the state tracking rules in the iptables policy (see the script above). These rules allow packets that are part of an established TCP connection to pass unimpeded.

SPA via Asymmetric Encryption

To use GnuPG to encrypt and sign an SPA packet, you can execute the fwknop command below. In this case, the key ID of the fwknopd server is specified on the command line with the --gpg-recipient argument, and the key ID used to sign the SPA packet is given with the --gpg-signing-key argument (the output below has been abbreviated):

[spa_client]$ fwknop -A tcp/22 --gpg-recipient ABCD1234 \
--gpg-signing-key 5678DEFG -w -k

[+] Sending 1010 byte message to over udp/62201

As you can see, the length of the application portion of the SPA packet has increased to more than 1,000 bytes, whereas it was only 150 bytes for the Rijndael example. This is because the key length of GnuPG keys (in this case 2,048 bits) and the characteristics of asymmetric ciphers tend to inflate the size of small chunks of data after being encrypted. There is no strict correspondence between the size of clear-text and cipher-text data as in block ciphers such as Rijndael.

Again, on the spa_server system, fwknop adds the ACCEPT rule for us. This time fwknopd reports that the SPA packet is encrypted with GnuPG, and that a valid signature for the required key ID 5678DEFG is found:

Feb 10 14:38:26 spa_server fwknopd: received valid GnuPG
encrypted packet (signed with required key ID: "5678DEFG")
from:, remote user: mbr
Feb 10 14:38:26 spa_server fwknopd: adding
FWKNOP_INPUT ACCEPT rule for -> tcp/22 (30 seconds)