For the complete documentation index, see llms.txt. This page is also available as Markdown.

SSH Integration

k9-ssh integrates with OpenSSH through the AuthorizedKeysCommand directive introduced in OpenSSH 6.2. This page explains how the integration works and how to configure it.

How AuthorizedKeysCommand Works

When a user attempts to log in via SSH, sshd normally checks ~/.ssh/authorized_keys. If AuthorizedKeysCommand is configured, sshd additionally calls the specified program and treats its stdout as a supplemental list of authorized public keys. If the user's private key matches any key from either source, authentication succeeds.

k9-ssh implements this interface. sshd calls k9-ssh with the connecting username, k9-ssh fetches that user's registered keys from Key9, validates each key's format, and prints valid keys one per line to stdout.

sshd_config Directives

Basic Setup

AuthorizedKeysCommand /opt/k9/bin/k9-ssh --user=%u
AuthorizedKeysCommandUser key9

%u is an sshd token that is replaced with the username of the connecting user at runtime.

AuthorizedKeysCommandUser specifies the OS user that sshd uses to execute the command. This must match the run_as value in k9.yaml. Using a dedicated unprivileged user ensures k9-ssh cannot be exploited to gain elevated privileges.

With Client Address (OpenSSH 9.4+)

AuthorizedKeysCommand /opt/k9/bin/k9-ssh --user=%u --remote=%C
AuthorizedKeysCommandUser key9

The %C token expands to a string identifying the client connection (typically address:port:lport:rdomain). When provided, k9-ssh forwards this information to the Key9 API, enabling IP-based policy enforcement on the Key9 side.

To check your OpenSSH version:

Full sshd_config Example

Setting PasswordAuthentication no after verifying k9-ssh works ensures that only Key9-managed keys can be used to log in.

sshd Token Reference

The tokens below can be used in the AuthorizedKeysCommand value. k9-ssh uses %u and optionally %C.

Token
Expands to

%u

Username of the connecting user

%C

Client connection string (address:port:lport:rdomain) — OpenSSH 9.4+

%h

Home directory of the connecting user

%f

Fingerprint of the key being offered (not useful for k9-ssh)

API Request Flow

For each login attempt, k9-ssh makes one HTTPS POST request to the Key9 API:

The response is a newline-delimited stream of JSON objects, one per key:

Error responses use:

k9-ssh validates each returned key with Go's golang.org/x/crypto/ssh library before printing it. Malformed or unrecognized keys are silently dropped and logged to syslog.

Username Validation

Before making any API call, k9-ssh validates the username against the pattern:

This accepts standard Unix usernames (lowercase letters, digits, underscores, hyphens, up to 32 characters). Any username that does not match is rejected with a syslog warning and k9-ssh exits without contacting the API. This prevents path traversal and injection attacks via the username field.

Coexistence with authorized_keys

k9-ssh and local authorized_keys files are not mutually exclusive — sshd evaluates both. If you want Key9 to be the sole source of truth for SSH keys, set the following in sshd_config:

This disables local authorized_keys lookup entirely and forces all authentication through AuthorizedKeysCommand.

Testing Without Restarting sshd

You can test k9-ssh output directly without touching sshd configuration:

A successful response looks like:

No output (but exit code 0) means the user exists but has no keys registered for this machine group. Check Key9 dashboard for the user's group assignments.

Last updated