4 releases (2 breaking)
0.3.0 | Feb 29, 2024 |
---|---|
0.2.1 | Feb 10, 2024 |
0.2.0 | Feb 10, 2024 |
0.1.0 | Jan 19, 2024 |
#3 in #primary-key
66KB
1K
SLoC
sshd-openpgp-auth
This tool provides server-side functionality to create and manage OpenPGP certificates that serve as trust anchors for SSH host keys.
More specifically, sshd-openpgp-auth
transparently manages the lifecycle of an OpenPGP certificate and the validity of SSH host keys as its authentication subkeys.
Its featureful commandline interface allows for import of host keys from SSH public key files as well as known_hosts file format formatted strings, extension of expiry period of the primary key, revocation of any of the subkeys and deployment to a Web Key Directory (WKD).
As complementary client-side tool ssh-openpgp-auth
is used to validate the trust anchors and OpenPGP subkeys created with sshd-openpgp-auth
.
Installation
To install this tool use cargo:
cargo install sshd-openpgp-auth
Dependencies
This tool is able to add subkeys from existing SSH host keys on a system. For this only access to the SSH public keys is required.
When importing the public SSH host keys of remote machines (in known_hosts file format), the output of ssh-keyscan
(usually part of an OpenSSH installation) can be used directly.
Using sshd-openpgp-auth
This tool does not require a configuration file and relies on defaults which can be overridden on the command-line and using dedicated environment variables.
By default SSH public keys are searched for in /etc/ssh/
and OpenPGP certificates are stored in /var/lib/sshd-openpgp-auth/
.
As such, the tool should be run as a separate system user when using the default OpenPGP certificate location!
This repository offers a sysusers.d and tmpfiles.d integration in the contrib dir for this scenario.
However, it is entirely possible to manage the trust anchors of other hosts and rely on one's own user for this with the help of the --openpgp-dir
and --fingerprint
options to define the directory for storing OpenPGP certificates and identifying specific OpenPGP certificates with the help of an OpenPGP fingerprint.
The following subsections provide a broad overview of the various commands sshd-openpgp-auth
offers.
For a more detailed overview refer to the command's --help
output.
Initializing a trust anchor
To start offering OpenPGP based authentication for the SSH setup of a host, one needs to create an OpenPGP certificate, which serves as trust anchor.
For demonstration purposes let us assume, that we are working with a custom temporary storage location for our OpenPGP certificates, are not using the system's SSH host keys (generating the host keys requires ssh-keygen
, usually part of OpenSSH) and want to work on a host named example.com
.
export SSH_DIR="$(mktemp -d)"
export SOA_SSH_DIR="$SSH_DIR/etc/ssh/"
export LOCAL_SSH_DIR="$SOA_SSH_DIR"
export SOA_OPENPGP_DIR="$(mktemp -d)"
export LOCAL_OPENPGP_DIR="$SOA_OPENPGP_DIR"
mkdir -vp "$SOA_SSH_DIR"
ssh-keygen -A -f "$SSH_DIR"
sleep 2
sshd-openpgp-auth init "example.com"
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
Adding SSH host keys
The SSH host keys of a system can be added to an OpenPGP certificate in two ways: Locally and remotely.
Local host keys
To add the local SSH host keys the add
subcommand is used.
sshd-openpgp-auth add
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
unset SOA_SSH_DIR
Remote host keys
Let us assume we are codeberg.org and want to use sshd-openpgp-auth
to add the service's SSH public keys to a trust anchor on a different host.
This example requires ssh-keyscan
.
export PREV_SOA_OPENPGP_DIR="$SOA_OPENPGP_DIR"
export SOA_OPENPGP_DIR="$(mktemp -d)"
sshd-openpgp-auth init "codeberg.org"
sshd-openpgp-auth list
set +o pipefail
ssh-keyscan -t ecdsa,ed25519,rsa codeberg.org | sshd-openpgp-auth add --known-hosts
set -o pipefail
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
export REMOTE_OPENPGP_DIR="$SOA_OPENPGP_DIR"
export SOA_OPENPGP_DIR="$PREV_SOA_OPENPGP_DIR"
Adding thirdparty certifications
The client-side tool ssh-openpgp-auth
can validate the authenticity of a host's OpenPGP certificate based on PGPKI (aka the Web of Trust).
In this scenario the user of the client tool usually trusts a central certificate authority (CA): Another OpenPGP certificate holder that certifies the host's OpenPGP certificate.
Let us assume that the host example.com
will be certified by an OpenPGP certificate with the User ID admin@central-ca.com
.
export CA_TMPDIR="$(mktemp -d)"
# create a temporary CA key
sq key generate --userid 'SSH CA <admin@central-ca.com>' --output "$CA_TMPDIR/ca_key.tsk"
sq inspect --certifications "$CA_TMPDIR/ca_key.tsk"
# certify the host's key using the CA key
sq pki certify --output "$CA_TMPDIR/example_certification.pgp" "$CA_TMPDIR/ca_key.tsk" "$SOA_OPENPGP_DIR/"*.tsk "<ssh-openpgp-auth@example.com>"
sq inspect --certifications "$CA_TMPDIR/example_certification.pgp"
It is now possible to directly import the created certification by merging it with the host's Transferable Secret Key (TSK).
sshd-openpgp-auth merge "$CA_TMPDIR/example_certification.pgp"
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
Managing thirdparty certifications such as the one added above in the host's TSK has the upside, that certifications are directly available to clients upon exporting the host key to WKD.
Exporting to Web Key Directory
One of the upsides of sshd-openpgp-auth
is, that it can be used in the context of the already existing OpenPGP based ecosystem for certificate retrieval: WKD.
Using the export
subcommand, certificates can be exported to a local directory, which can directly be served by a web server.
export SOA_WKD_OUTPUT_DIR="$(mktemp -d)"
sshd-openpgp-auth export "example.com"
export SOA_WKD_OUTPUT_DIR="$(mktemp -d)"
sshd-openpgp-auth export "example.com" --wkd-type "direct"
Extend the expiry period
When using this tool all added subkeys depend on the expiration time of the OpenPGP primary key.
Using the extend
subcommand the primary key can be extended.
Let us assume, the administrator wants to extend the OpenPGP certificate's expiry period to a duration longer than the default.
sshd-openpgp-auth extend --threshold 365 --expiry 730
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
Revoking authentication subkeys
Sometimes it is necessary to revoke one or all of the authentication subkeys. Reasons for this may be, that the administrator wants to create new SSH host keys with stronger cryptographic algorithms, deprecate old ones or (worst case) has to replace compromised ones.
Let us have a look at the different scenarios in the following subsections.
The key has been superseded
This is the default revocation action and used in scenarios where new OpenPGP authentication subkeys replace old ones.
Let us again imagine we are codeberg.org and want to replace our current SSH host keys with new ones. We will add newly created SSH host keys and then revoke the old ones while appending a message that points at the new subkeys.
export SOA_OPENPGP_DIR="$REMOTE_OPENPGP_DIR"
export SOA_SSH_DIR="$LOCAL_SSH_DIR"
sshd-openpgp-auth list
sshd-openpgp-auth add
sshd-openpgp-auth list
export REMOTE_SUBKEYS=( $(sshd-openpgp-auth list | grep '✅' | cut -f 2 -d ' ') )
sshd-openpgp-auth revoke --subkey-fingerprint "${REMOTE_SUBKEYS[0]}" --message "Superseded by ${REMOTE_SUBKEYS[1]}"
sshd-openpgp-auth revoke --subkey-fingerprint "${REMOTE_SUBKEYS[2]}" --message "Superseded by ${REMOTE_SUBKEYS[3]}"
sshd-openpgp-auth revoke --subkey-fingerprint "${REMOTE_SUBKEYS[4]}" --message "Superseded by ${REMOTE_SUBKEYS[5]}"
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
The key is retired
For this example let us assume that we want to retire only a single SSH host key (e.g. because we do not support the algorithm in question anymore).
export SOA_OPENPGP_DIR="$LOCAL_OPENPGP_DIR"
sshd-openpgp-auth list
export REMOTE_SUBKEYS=( $(sshd-openpgp-auth list | grep '✅' | cut -f 2 -d ' ') )
sshd-openpgp-auth revoke --subkey-fingerprint "${REMOTE_SUBKEYS[0]}" --reason retired --message "We stopped supporting RSA"
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
The key is compromised
Let us also have a look at our worst-case scenario: Our host has been compromised and an attacker stole our SSH host keys to be able to impersonate our host.
sshd-openpgp-auth revoke --all --reason compromised --message "This host has been compromised today!"
sshd-openpgp-auth list
sq inspect --certifications "$SOA_OPENPGP_DIR/"*.tsk
Adding Keyoxide DNS proof
To increase trust in the host certificate it's also possible to insert Keyoxide proof of authenticity:
sshd-openpgp-auth proof dns add
The above will add a notation to the certificate, which represents a claim about the ownership of the domain the certificate is used for. Clients can retrieve the certificate via WKD or OpenPGP keyservers and attempt to validate this claim.
To allow clients to validate the identity claim added with the notation, specific proof must be added to the DNS zone file of the host as a TXT
record in the following format:
openpgp4fpr:FINGERPRINT
Where FINGERPRINT
is a lower-cased hexadecimal representation of the key's fingerprint.
An example of several authorized keys:
$ dig +short TXT metacode.biz
"openpgp4fpr:0e3bb828432962f4e33c9a74d1f809bb3f02ede9"
"openpgp4fpr:198c722a4bac336e9daaae44579d01b3abe1540e"
"openpgp4fpr:653909a2f0e37c106f5faf546c8857e0d8e8f074"
For OpenPGP CA installations the fingerprint of the OpenPGP CA certificate should also be present in the TXT
records of the DNS zone.
For more technical details see Keyoxide DNS proof page.
Funding
This project is funded through NGI Assure, a fund established by NLnet with financial support from the European Commission's Next Generation Internet program. Learn more at the NLnet project page.
License
This project is licensed under either of:
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~18–27MB
~377K SLoC