Single_Packet_Authorization

Overview

Single Packet Authorization (SPA) is defined as the communication of authentication information over spa server port, together with the dynamic reconfiguration of a default-drop firewall policy to allow access to services that would otherwise be blocked, SPA communicates authentication information within the payload portion of a single packet. Because packet payloads are used, SPA offers many enhancements over PK such as stronger usage of cryptography, protection from replay attacks, minimal network footprint (in terms of what IDS’s may alert on - PK sequences look like port scans after all), the ability to transmit full commands and complex access requests, and better performance.

For simple, access service is blocked by firewall, SPA client requests to open that service for itself, SPA server authenticates the request, adds proper firewall rules to that client, after that client can access server as normal.

Workflow

A basic outline for using fwknop to conceal an SSH daemon(or any service) with Single Packet Authorization (SPA) involves the following steps. This assumes an SPA client system (hostname: spaclient), and an SPA server system spaserver.domain.com where fwknopd is installed and the SSH daemon listens:

  1. Generate encryption and HMAC keys with fwknop –key-gen.
  2. Transfer the keys you just generated fwknopd to the server (this is where SSHD is listening too).
  3. Start fwknopd and deploy a default-drop firewall policy against all inbound SSH connections.
  4. From anywhere on the Internet, use the fwknop client to send an SPA packets and have fwknopd open the firewall.
  5. Use your SSH client as usual now that you have access. No one else can even see that SSHD is listening.

Network

NOTE

  • SPA sends request in payload to grant access(add firewall rule at spa server) for IP in the payload.
  • Firewall(iptables) checks protocol headers for access.

Install

Here are the steps to install fwknop from source code, first make sure you have dev machine and env to compile from source, install from package is available for ubuntu as well, but here I want to share how to install from source.

install from package

1
2
3
4
5
# Ubuntu18
$ apt-get install -y fwknop-server
$ apt-get install -y fwknop-client
# Centos7
yum install -y fwknop

install from source

1
2
3
# install dependencies
$ apt-get update
$ apt-get install -y build-essential autoconf autotools-dev libtool textinfo git

install server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ yes yes | git clone https://github.com/mrash/fwknop.git
$ cd fwknop/
$ ./autogen.sh
$ ./configure --disable-client --prefix=/usr
$ make
$ make install

# make sure install correctly
$ fwknopd -V
# enable systemd service, then you can check fwknopd by `service fwknopd status`
$ cp extras/systemd/fwknopd.service /lib/systemd/system/

# config location
# /usr/sbin/fwknopd
# /usr/etc/fwknop/fwknopd.conf
# /usr/etc/fwknop/access.conf

install client

1
2
3
4
5
6
7
8
9
$ yes yes | git clone https://github.com/mrash/fwknop.git
$ cd fwknop/
$ ./autogen.sh
$ ./configure --disable-server --prefix=/usr
$ make
$ make install
# make sure install correctly
$ fwknop -V
# /usr/bin/fwknop

Examples

After installation, you need to config both client and server together to make them work, but the config depends on network topology you’re using, here are some typical use cases.

Network topology no NAT(same network or public ip), SPA server and service on same machine

server side

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# create key for hmac and aes
$ fwknopd --key-gen
KEY_BASE64: +RCO0Gi2oTWbmBaylY4mVsDXzggQKDKwYU2FaLBL0Jo=
HMAC_KEY_BASE64: 729XvADuHzSs6I9vz9tVIOFITF/ckAAIZGWVU4Hy4c82kbAbsFzkZRfddNZPr10AJlUCVdtx9D6vNN2XQ6ribQ==

# edit /usr/etc/fwknop/access.conf
SOURCE ANY
KEY_BASE64 WO3yTj1oMCoFr3l8WlCLSJAGikvej2BqYgwEcFPwiHg=
HMAC_KEY_BASE64 06EL9sbYsYUm396U/H44BnEm/qIOi1iiWVPILv8jWJg3NMm52I4Whu/AyL0v4CnR1IcHV27QUjFJ8NFNllTatA==

# edit /usr/etc/fwknopd/fwknopd.conf
FWKNOP_RUN_DIR /var/run/fwknop;
FWKNOP_PID_FILE $FWKNOP_RUN_DIR/fwknopd.pid;
PCAP_INTF ens160

# start fwknopd service
$ service fwknopd start
$ service fwknopd status

# insert two rules at header, the second one before the first one in iptables
# hence for established tcp connection, keep it, others default to drop
$ iptables -I INPUT 1 -i ens160 -p tcp --dport 22 -j DROP
$ iptables -I INPUT 1 -i ens160 -p tcp --dport 22 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

client side

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# we use named config, the config file is at /user/.fwknoprc, create it if no

# edit /user/.fwknoprc
[default]
USE_HMAC Y

[spaserver-ssl]
ALLOW_IP 10.10.10.10
ACCESS tcp/22
SPA_SERVER 10.10.10.1
KEY_BASE64 WO3yTj1oMCoFr3l8WlCLSJAGikvej2BqYgwEcFPwiHg=
HMAC_KEY_BASE64 06EL9sbYsYUm396U/H44BnEm/qIOi1iiWVPILv8jWJg3NMm52I4Whu/AyL0v4CnR1IcHV27QUjFJ8NFNllTatA==

# default section is global setting
# each named section can has it own setting
# ALLOW_IP, ACCESS, request access for this IP and port

# request access for info in spaserver-ssl
$ fwknop -n spaserver-ssl

# then normal ssh
ssh root@10.10.10.1

Network topology with NAT, service(private address) behind SPA server on different machines

network topology

  • client ip: 192.168.1.2
  • SPA server ip: 10.10.10.3(public)
  • SSH server ip: 192.168.100.10

server side

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# edit /usr/etc/fwknopd/fwknopd.conf
ENABLE_IPT_FORWARDING Y;

# after client sent SPA request, check iptables rules
$ fwknopd --fw-list
Listing rules in fwknopd iptables chains...

Chain FWKNOP_INPUT (1 references)
num target prot opt source destination

Chain FWKNOP_FORWARD (1 references)
num target prot opt source destination
1 ACCEPT tcp -- 2.2.2.2 0.0.0.0/0 tcp dpt:2 /* _exp_1605161576 */

Chain FWKNOP_PREROUTING (1 references)
num target prot opt source destination
1 DNAT tcp -- 2.2.2.2 0.0.0.0/0 tcp dpt:22 /* _exp_1605161576 */ to:192.168.100.10:2

client side

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat /user/.fwknoprc
[default]
USE_HMAC Y

[spaserver-ssl]
ACCESS tcp/22
SPA_SERVER 10.10.10.3
KEY_BASE64 WO3yTj1oMCoFr3l8WlCLSJAGikvej2BqYgwEcFPwiHg=
HMAC_KEY_BASE64 06EL9sbYsYUm396U/H44BnEm/qIOi1iiWVPILv8jWJg3NMm52I4Whu/AyL0v4CnR1IcHV27QUjFJ8NFNllTatA==
RESOLVE_IP_HTTPS Y
NAT_ACCESS 192.168.100.10:22

# with RESOLVE_IP_HTTPS, the real ip in SPA packet, is the external ip, get by fwknop atomically.
# but if you know the external ip. use 'ALLOW_IP' remove 'RESOLVE_IP_HTTPS'

# the external ip for client is 2.2.2.2
$ fwknop -n spaserver-ssl
$ ssh root@10.10.10.3

Network topology with SNAT(at spa server), service behind SPA server on different machines

As you know SNAT is after POSTROUTING, that means when SPA server forwards packet, the SRC must be replaced, otherwise packet can not be routed to service server, it’s total SPA server config, client even not care!

1
2
3
4
# edit /usr/etc/fwknopd/fwknopd.conf
ENABLE_IPT_FORWARDING Y;
ENABLE_IPT_SNAT Y;
$ service fwknopd restart

Network topology with DNAT(port only)

DNAT is needed when spa server does NOT want to grant access to well-known port like ssh(22), but instead grants access to a temporary port which is only known to SPA client who triggers the request for safe.

server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# edit /usr/etc/fwknopd/fwknopd.conf
ENABLE_IPT_LOCAL_NAT Y;

$ service fwknopd restart
# after client sent SPA packet
$ fwknopd --fw-list
Listing rules in fwknopd iptables chains...

Chain FWKNOP_INPUT (1 references)
num target prot opt source destination
1 ACCEPT tcp -- 10.10.10.1 0.0.0.0/0 tcp dpt:22 /* _exp_1605156202 */

Chain FWKNOP_FORWARD (1 references)
num target prot opt source destination

# this the new added rule for DNAT
Chain FWKNOP_PREROUTING (1 references)
num target prot opt source destination
1 DNAT tcp -- 10.10.10.1 0.0.0.0/0 tcp dpt:29935 /* _exp_1605156202 */ to:10.10.10.3:22

client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat /user/.fwknoprc
[default]
USE_HMAC Y

[spaserver-ssl]
ALLOW_IP 10.10.10.1
ACCESS tcp/22
SPA_SERVER 10.10.10,3
KEY_BASE64 WO3yTj1oMCoFr3l8WlCLSJAGikvej2BqYgwEcFPwiHg=
HMAC_KEY_BASE64 06EL9sbYsYUm396U/H44BnEm/qIOi1iiWVPILv8jWJg3NMm52I4Whu/AyL0v4CnR1IcHV27QUjFJ8NFNllTatA==
NAT_LOCAL Y
NAT_RAND_PORT Y

$ fwknop -n spaserver-ssl
[+] Randomly assigned port '29935' on: '10.10.10.1,tcp/29935' will grant access to: '10.10.10.3,22'

# access by 29935, not port 22
$ ssh root@10.10.10.3 -p 29935

Grant access with limit scope(source ip, user, port)

By default, spa server allows ANY address with ANY user to request ANY port(on server) access, but we can limit the scope by several variables
server

1
2
3
4
5
6
7
# edit /usr/etc/fwknop/access.conf
SOURCE 1.1.1.0/24, 2.2.2.2
OPEN_PORTS tcp/22, tcp/993
REQUIRE_USERNAME bob
REQUIRE_SOURCE_ADDRESS Y
KEY_BASE64 WO3yTj1oMCoFr3l8WlCLSJAGikvej2BqYgwEcFPwiHg=
HMAC_KEY_BASE64 06EL9sbYsYUm396U/H44BnEm/qIOi1iiWVPILv8jWJg3NMm52I4Whu/AyL0v4CnR1IcHV27QUjFJ8NFNllTatA==

client with user name

1
2
3
4
5
6
7
8
9
10
11
$ cat /user/.fwknoprc
[default]
USE_HMAC Y

[spaserver-ssl]
ALLOW_IP 10.10.10.1
ACCESS tcp/22
SPA_SERVER 10.10.10.3
KEY_BASE64 WO3yTj1oMCoFr3l8WlCLSJAGikvej2BqYgwEcFPwiHg=
HMAC_KEY_BASE64 06EL9sbYsYUm396U/H44BnEm/qIOi1iiWVPILv8jWJg3NMm52I4Whu/AyL0v4CnR1IcHV27QUjFJ8NFNllTatA==
SPOOF_USER bob

troubleshooting

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# check service status
$ service fwknopd status
# check log if not working
$ grep fwknopd /var/log/syslog

# dump the config
$ fwknopd -D

# Listing rules in fwknopd iptables chains...
$ fwknopd --fw-list

# Flush all firewall rules created by fwknop.
$ fwknopd --fw-flush

# show more info for SPA packet when sending
$ fwknop -n spaserver-ssl -v

FAQ

if client behinds NAT what special setting needed

As SPA server uses iptables which only see external IP used by client after SNAT, hence we should sent this ip in SPA packet.

1
2
# edit /user/.fwknoprc at spa client, but never set ALLOW_IP which is the real ip in SPA message
RESOLVE_IP_HTTPS Y

REF