SSH authorization using biscuit tokens embedded in SSH certificates.
biscuit-ssh is an OpenSSH AuthorizedKeysCommand program that validates SSH certificates containing embedded biscuit tokens. It's inspired by opkssh but uses biscuit tokens instead of PK tokens for service to service authorization.
Have a look at the example folder for a demonstration of how this works.
This crate is experimental and has not been tested in production. Use it at your own risk.
For example:
cargo build --release
sudo install -m 0755 target/release/biscuit-ssh /usr/local/bin/Store the public key file to validate biscuits in /etc/biscuit-ssh/keys/default.key:
Create /etc/biscuit-ssh/config.toml:
# Biscuit public key for token verification
default_public_key = "/etc/biscuit-ssh/keys/default.key"
log_level = "info"Set the following parameters in /etc/ssh/sshd_config:
# Use biscuit-ssh for certificate authorization
AuthorizedKeysCommand /usr/local/bin/biscuit-ssh verify %u %k %t
# User to run the command as: this should be a dedicated user
AuthorizedKeysCommandUser biscuit
# Enable certificate authentication
PubkeyAuthentication yes
Restart SSH: sudo systemctl restart sshd
# Generate SSH key pair if you don't have one
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
# You should have a biscuit with the required facts
# One could be generated with:
echo 'user("alice"); ssh:authorized_key("ssh-ed25519", "AAAAC3NzaC1lZDI1NTE5AAAAIKzPvv...", "alice@demo");' > authority.datalog
biscuit-cli generate --private-key $BISCUIT_PRIVATE_KEY authority.datalog > token.biscuit
# Create SSH certificate with embedded biscuit
biscuit-ssh generate \
--identity ~/.ssh/id_ed25519 \
--biscuit token.biscuitssh -i ~/.ssh/id_ed25519 alice@serverThe biscuit token must provide these facts for authorization to succeed:
-
user: SSH username allowed to connect
user("alice") -
ssh:authorized_key: SSH public keys authorized to connect as the specified username
ssh:authorized_key("ssh-ed25519", "AAAAC3NzaC1lZDI1NTE5AAAAIKzPvv...", "comment")
The biscuit-ssh authorizer provides facts that can be used by checks in biscuit blocks:
-
service: Set to
"ssh"service("ssh") -
ssh:public_key: The SSH public key from the certificate attempting to connect
ssh:public_key("ssh-ed25519", "AAAAC3NzaC1lZDI1NTE5AAAAIKzPvv...") -
time: Connection timestamp
time(2025-07-22T22:39:12Z)
The embedded biscuit should be attenuated so that it may only be used for SSH connections with the right key pair:
// Original token authority
user("alice");
ssh:authorized_key("ssh-ed25519", "AAAAC3NzaC1JxsZ0IjS08pCXv...", "alice@laptop");
ssh:authorized_key("ssh-ed25519", "AAAAC3NzaC1lIMRHvjcneAKU3...", "alice@desktop");
// Attenuation block
// Restrict to SSH service
check if service("ssh");
// Limit validity
check if time($time), $time < 2025-07-22T22:41:12Z;
// Restrict to a specific public key
check if ssh:public_key("ssh-ed25519", "AAAAC3NzaC1lIMRHvjcneAKU3...");
biscuit-ssh can choose between multiple biscuit public keys depending on the biscuit root key ID to facilitate key rotation:
# Directory containing key files named <id>.key
public_keys = "/etc/biscuit-ssh/keys"
# Optional: default key for tokens without a root key ID
default_public_key = "/etc/biscuit-ssh/keys/default.key"
log_level = "info"/etc/biscuit-ssh/keys/
├── default.key # Default key (no key ID)
├── 1.key # Key ID 1
├── 2.key # Key ID 2
└── 3.key # Key ID 3
When creating biscuits, specify a key ID to use a specific verification key:
# Create biscuit with key ID 2
biscuit-cli generate --private-key $BISCUIT_PRIVATE_KEY_2 --root-key-id 2 authority.datalog > token.biscuit