What is it?
Single-Packet Authorization (or SPA) is a variation of common port-knocking techniques which allows a remote client to send a single, one-way UDP packet to a SPA server to traditionally open access to one or more network services.
CSPAuthD extends port-knocking through the use of public-key infrastructure and authorization lists, to allow execution of registered command sequences available on the SPA server. These command sequences are exposed through a variety of action and option identifiers, in combination termed Functions in this document.
This software repository (see URL above) includes both the server and the client application. The combination of these two tools at both network endpoints unlocks the powerful ability to securely execute Functions from any network location.
The Most Common Use-Case
Single-Packet Authorization is mainly useful as a substitution for port-knocking in most secure environments. Rather than using a complex, timed sequence of “knocks” (basic UDP packets) which can be sniffed and replayed by attackers, SPA uses cryptographic mechanisms to enforce access controls on clients attempting to authorize Functions.
In this manner, the tool is a step above port-knocking since it validates incoming requests against a predefined list of authorizations and keys.
Terminology
It’s crucial to understand some quick terms in this document in order to understand more technical details about the project:
-
Action
- A command-string that the underlying system shell runs as the service user when a valid SPA packet is received by the server daemon. This string has the ability to dynamically expand some predefined tokens before handing off the command to the shell for execution. -
Function
- A combination ofaction:option
, where Action is the ID of the command-string to run, and Option is a specific ID to give to that Action. These two items put together represent a single “function”. -
User
- A simple string, not associated with any system user accounts (though they “can” be), which is associated to a public-key file and an authorization list. -
Public Key
- A cryptographic key file that’s one side of an asymmetric key pair, used by Users to sign outgoing SPA packets. The SPA server holds the Public Key, while the requestor must use the matching Private Key only. -
Authorization List
- Also calledAUTLs
here and there, these are per-user lists which grant access to certain Functions as specified. All users are denied all functions unless otherwise specified by an AUTL definition.
How it Works
The sample server configuration, as verbose and complex as it looks, really boils down to four critically-important values for getting SPA packets through the daemon:
-
users
- A comma-separated list (which can be specified multiple times) that denotes “user” objects who will have their own unique cryptographic keys and Function authorizations. -
pubkey:[user]
- Associates the full-path of the public key file to the username. -
autl:[user]
- Associates the Authorization List to the username. These can be specified multiple times in an additive fashion, to make human-parsing AUTLs easier to do. -
action:[ID]
- Defines a command to pass to the underlying system shell for the given ID. The ID portion is the action ID that’s referenced in a requested Function.
When a packet is received by the server, it follows the following procedure, failing at any point if something does not look valid or correct about the incoming packet along the way:
- Check the timestamp against the server time, according to the
validity_window
setting. - Check the username and fetch her details.
- Verify the packet hash is expected, and isn’t a replay (if monitoring is enabled).
- Validate the requested function exists and is actively loaded.
- Get the user’s public key and verify the packet signature.
- Check the user’s authorization lists to perform the requested Function.
- Record the packet hash in the replay monitor, if enabled.
- Grant authorization and perform the requested function.
- If set, send a response packet back to the issuing client.
With this in mind, setting up x509 certificates for use with the service and then delegating authorized functions to certain users, who hold their respective key files, shouldn’t seem much of a hassle.
Similarly, certificates aren’t necessary if public/private pairs are to be used instead. This is elective and really up to the implemented of CSPauthD.
Once the user has a compatible client and their key, and they know their permitted Functions, they should be able to call them on the SPA server whenever they like. The configuration does include a few possibly-useful example actions that server administrators may be interested in.
Why Use IDs or Indexes?
As a side-note, some might ask, “Why would you use ID numbers for calling these actions, rather than allowing remote commands to be passed?”
The response would be that a server administrator defining rigid “instructions” which are directly granted to selected users, is so much simpler to manage, secure, and authorize than directly allowing arbitrary commands to be passed to the underlying system shell.
Again, this is in the “Crude” part of the name since the software itself is bare and minimal.
The SPA Protocol - “Crude”-style
CSPAuthD accepts its own (non-standard) UDP packets on its (also-non-standard) default bind
port of 41937. The way it responds – if at all – to client UDP packets is handled by
the
mode
setting within the daemon configuration.
The protocol is loosely based on a similar implementation from the well-known
fwknop
port-
knocking application, which has its own SPA functionality. Here’s a breakdown of the raw
packet formatting and order:
Field Name | Starting Position (byte) | Width (bytes) | Description |
---|---|---|---|
packet_data | 0 | 32 | Intended to be junk/random data, but could be used in
[[UNSAFE_DATA]]
action token expansions. |
username | 32 | 16 | String representing the request’s username, which associates to a local public key. |
client_timestamp | 48 | QWORD | Epoch timestamp according to the client application/workstation. |
request_action | 56 | WORD | The 16-bit Action portion of the requested Function. |
request_option | 58 | WORD | The 16-bit Option portion of the requested Function. |
__reserved | 60 | DWORD | Reserved space. Used to round packet fields to clean 2^x boundaries. |
packet_hash | 64 | 32 | SHA256 packet digest of all the above fields. This digest is then signed (by another crypto digest function). |
signature_length | 96 | DWORD | The length of this SPA packet’s trailing cryptographic signature. |
packet_signature | 100 | 1 to 2,048 | The cryptographic SHA256 signature using the private cryptographic key associated with the
username
above. |
Other Details
Many of the other operational application details can be found in the project’s sample configuration file, which will need to be fully reviewed and understood before using the server daemon.
SPA Server Daemon
The SPA server is designed to operate as a system service which logs key details to the local
syslog server/application, based on the
log_level
setting per the loaded configuration. It’s
made to run with the lowest memory footprint possible, and keeps a best-effort policy to collect
heap garbage as it can.
Each incoming packet that’s being tracked is associated with a randomly-generated 64-bit identifier in its syslog details. The ID allows the full activity of that specific packet to be closely tracked, monitored, and analyzed.
Users can choose to let the daemon run as root or restrict it with a sudo-privileged user (if that’s desired at all).
By default, the RPM for Fedora systems installs the daemon as the
root
user. As such, it’s
very important to read the configuration closely and not to leave any potential for the root user
to perform malicious functions. This is intended to change in the future, but for now the
root
user is the default run-level on installation.
Installing the Server
To install the server on Fedora-based Linux systems (where it’s been primarily tested), simply
download the available RPM version (not yet available) and install it as
root
or with sudo per the guide below.
# Install the package
[root@server1 ~]# rpm -ivh cspauth.rpm
. . .
. . .
# Enable the service and boot-time and start it now
[root@server1 ~]# systemctl enable --now cspauthd.service
. . .
# View SPA server daemon logs
[root@server1 ~]# journalctl -rt cspauthd
. . .
. . .
CSPAuth Client
Usage information for the client application can be found by executing the program without any parameters. Its usage details are not here statically since it will change as the application evolves. Rest assured, the client is fairly quick to get working for most Linux users.
Building from Source
The whole project can easily be built with gcc in a few different ways, using the convenient Makefile build directives.
Build the Optimized Release Version:
make release
Build the Debugging Version:
make clean ; make all
When using the debugging version (if debugging is your specific goal), don’t forget to
always initialize the CLI application with the
debug
flag, like so:
[root@server1 cspauth]# make clean ; make all
. . .
. . .
[root@server1 cspauth]# ./bin/cspauthd -x
. . .
. . .
To build the client and server applications independently:
make clean ; make client/server
If you have any questions, suggestions, or other comments, please email me directly or contact me via GitHub.
Thank you for reading, and enjoy!