Skip to content

The ssoossh client

The client is what ssh invokes on your behalf. It generates a keypair, hands the public key to the server, waits for your approval in a browser, and loads the signed certificate into your ssh-agent – or writes key files when no agent is available. Private keys never leave the machine. This page is the command reference: what each subcommand does and what it accepts.

Release packages are on the releases page.

Platform Package Where it lands
Debian / Ubuntu ssoossh-client_*.deb /usr/bin/ssoossh, sample config at /etc/ssoossh/ssoossh.yaml, inert SSH drop-ins under /etc/ssh
RHEL / Fedora ssoossh-client_*.rpm same
Windows (amd64) ssoossh-client_*_windows_amd64.msi per machine into Program Files\ssoossh, added to the system PATH; installs silently with msiexec /i … /qn
Windows ssoossh-client_*.zip extract ssoossh.exe onto PATH (the only Windows package for arm64)
macOS ssoossh-client_*_darwin_<arch>.pkg /usr/local/bin/ssoossh, man pages under /usr/local/share/man, the annotated defaults at /usr/local/share/ssoossh/ssoossh.yaml
macOS ssoossh-client_*.zip the same files, unpacked by hand – extract ssoossh onto PATH

There is one macOS package per architecture, darwin_arm64 for Apple silicon and darwin_amd64 for Intel; the installer refuses the wrong one rather than leaving you with a binary that will not run. Both the binary and the package are Developer ID signed and notarized, so neither prompts Gatekeeper. Check a download before opening it:

Terminal window
spctl --assess --type install -v ssoossh-client_1.2.3_darwin_arm64.pkg

The package writes nothing under /etc. It installs the annotated defaults to /usr/local/share/ssoossh/ssoossh.yaml as a file to copy from – the client reads /etc/ssoossh/ssoossh.yaml and then ~/.config/ssoossh.yaml, and needs neither, since the same defaults are compiled in. To remove it:

Terminal window
sudo rm -rf /usr/local/bin/ssoossh /usr/local/share/ssoossh \
/usr/local/share/doc/ssoossh-client \
/usr/local/share/man/man1/ssoossh*.1 \
/usr/local/share/man/man5/ssoossh.yaml.5
sudo pkgutil --forget org.mikenestor.ssoossh-client

These are persistent flags: every subcommand accepts them.

Flag Default What it does
-c, --config <file> none Path to the ssoossh config file. Merged after every search-path location. A file named here that is missing or unparseable is a startup error for every command, ssh config and host principals included, unlike an absent search-path file. A search-path file that is there but will not parse is skipped with a warning on stderr.
--server <url> none Server address including scheme, for example https://example.com. https is assumed if the scheme is omitted. Overrides server in the config file.
-v, -vv, -vvv off Trace what the command is doing, to stderr. -v steps, -vv requests and files, -vvv bodies.
--debug off Print the resolved configuration, its sources, and key storage to stderr. Hidden from --help but supported; implies -v.
-h, --help Help for the command.

-v and --debug both have environment equivalents for invocations whose command line belongs to ssh or cron. See Diagnostics.

Status Meaning
0 Success, including the cases a command documents as succeeding without doing anything (a certificate still valid, nothing to remove).
1 The command ran and failed: the server was unreachable, the request was denied, a file could not be written.
2 The command was invoked wrongly: an unknown command or flag, a bad flag value, missing or extra arguments. The message ends with the --help command to run.

Match exec treats any non-zero status as “do not connect”, so the distinction matters only to scripts.

Command Talks to the server What it does
ssh login yes Authenticate via OIDC and load a signed certificate
ssh logout yes Remove ssoossh-managed keys and certificates
ssh config no Print the ssh_config recipes
ssh proxycommand yes Ensure a certificate, then relay stdio to the target
ssh inspect yes Print what the held certificates grant
ca yes Print the server’s CA public key
host principals no Answer sshd’s AuthorizedPrincipalsCommand
host mapping no Manage the local principal mapping file
host check only for the CA keys Check that this host’s sshd will accept ssoossh certificates
service enroll yes Enroll a keypair for unattended issuance
service retrieve yes Redeem an enrollment code for a certificate
version no Print version, commit, and build info

The four offline commands (ssh config, host principals, host mapping, version) make no network call at all. They still load configuration, because even a command that never talks to the server has to know where its own local files live.

Generates a fresh keypair, sends the public key to the server, prints the approval URL (and opens it in a browser when try_open_browser is set), and waits over SSE for the signed certificate. This is what an ssh_config Match exec line runs.

A certificate that is already loaded and still valid is reused rather than replaced, so one approval covers every connection until it expires.

Flag Default What it does
--force off Request a new certificate even if a valid one is already loaded
--key-type <type> ecdsa Key algorithm to generate: ed25519, ecdsa, or rsa
--key-size <n> 384 for ecdsa Bits for rsa, curve for ecdsa; ignored for ed25519
--no-pty off Do not request the permit-pty extension
--no-agent-forwarding off Do not request permit-agent-forwarding
--no-port-forwarding off Do not request permit-port-forwarding
--no-x11-forwarding off Do not request permit-X11-forwarding
--no-user-rc off Do not request permit-user-rc

--key-type and --key-size override sshkey.type and sshkey.size; the --no-* flags override the matching certificate_extensions keys.

Terminal window
# what ssh runs for you
ssoossh ssh login
# replace the loaded certificate with a fresh one
ssoossh ssh login --force
# a session that needs no forwarding of any kind
ssoossh ssh login --no-agent-forwarding --no-port-forwarding --no-x11-forwarding

By default the client asks for the full interactive extension set: permit-pty, permit-agent-forwarding, permit-port-forwarding, permit-X11-forwarding, and permit-user-rc. Asking for the full set is always safe – the server narrows the request against its own configuration before signing, and the approval page shows what survived. Asking for nothing is not useful: narrowing is an intersection, so an empty request yields a certificate that cannot open an interactive session.

Before requesting anything, ssh login verifies that the resolved key storage will actually accept and release a key, using a throwaway keypair. That check exists so a storage failure surfaces before you approve a certificate rather than after.

Removes the certificates ssoossh put in your ssh-agent – those signed by the configured CA – and nothing else. Your own keys are left alone. When key files are used instead of an agent, the files ssoossh wrote are deleted.

No flags beyond the global ones.

Terminal window
ssoossh ssh logout

Prints the ssh_config recipes that make ssh invoke ssoossh, with the rules that decide which one you want. It contacts nothing and reads nothing but that text, so it answers before a server is configured and keeps answering after one stops responding – which is exactly when you go looking for it.

No flags beyond the global ones.

Terminal window
ssoossh ssh config

It does not report resolved settings. --debug is the one place those are printed, so there is no second version of the truth to keep in step. See ssh_config integration for the long form.

For use as ssh_config’s ProxyCommand. It ensures a valid certificate, then relays stdio to the target host. The arguments after it mirror exactly what you would have written without ssoossh.

No flags beyond the global ones; everything after the command name is the relay command and its arguments. The relay is found on PATH, as ssh would find it, so nc works as well as /usr/bin/nc.

On Linux and macOS ssoossh replaces itself with the relay once the certificate is in place. Windows cannot do that, so there ssoossh starts the relay with its own stdin and stdout and stays running as its parent until the connection ends.

# before
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
# after
ProxyCommand ssoossh ssh proxycommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p

Shows what each certificate ssoossh is holding actually grants, rather than the certificate blob, which tells a human nothing.

No flags beyond the global ones.

Terminal window
ssoossh ssh inspect

The report opens with Storage, naming where the certificates are kept: an ssh-agent holds them in a process, and a file backend adds a Key files list of the paths on disk (private key, public key, certificate) so you know which files the certificates below came out of.

Each certificate then prints as Principals, Key ID, Type, Expires, Serial, Extensions, and Critical options. With none loaded it says so, naming the storage backend it looked in.

Retrieves the CA public key of the configured server. This is what target hosts must trust.

No flags beyond the global ones.

Terminal window
ssoossh --server https://ssh.example.com ca > /etc/ssh/ssoossh_ca.pub

Then on each target host:

/etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ssoossh_ca.pub

Fetching the key from the running server confirms the deployed key rather than trusting a local copy blindly. Trusting the CA in sshd covers the host side.

Configures the principal mapping used when sshd asks for authorized principals via AuthorizedPrincipalsCommand, and checks that sshd will accept ssoossh certificates. Only host check talks to the server, and only to fetch the CA keys it compares the host’s against.

Flag Default What it does
--file <path> /etc/ssoossh/principals.yaml The local principal mapping file: YAML listing, per local account, the principals allowed to assume it

--file is inherited by every host subcommand.

Implements AuthorizedPrincipalsCommand. It is called on every login attempt and never touches the network – it answers only from the local mapping file. It expects one argument, the local username to look up, and prints one principal per line.

The looked-up name is always among them. The mapping file is additive: it enriches the set of names allowed to assume an account, and it can never take the account’s own name away – not by omission, and not by listing the account with no principals. That is also what sshd accepts unaided, since with no AuthorizedPrincipalsCommand configured it admits a certificate carrying the target account name.

Situation Behavior
Account found Prints its principals in file order, then the account name if the file did not already list it, exit 0
Unknown account, or missing file Prints the account name alone, exit 0
Unreadable or malformed file Prints the account name alone, exit 0, and logs the failure to stderr
Client configuration fails to load Answers as above and warns on stderr, since it reads no setting; a --config file that is missing or malformed still fails it, exit 1

A file that will not load is reported rather than refused. pam_ssoossh treats a map it cannot read as no map at all and falls back to the same rule, and one file must not mean two policies – so this host stays consistent, and the broken file is made loud in the log rather than in a denied login. The diagnostic goes to stderr because sshd parses stdout as the principal list.

It needs no privilege beyond read access to the mapping file, so run it as a dedicated unprivileged account rather than as root:

/etc/ssh/sshd_config
AuthorizedPrincipalsCommand /usr/bin/ssoossh host principals %u
AuthorizedPrincipalsCommandUser ssoossh-principals

See trusting the CA in sshd for creating that account and the file permissions it needs.

Manages that same file.

Command Arguments What it does
host mapping list none Print the current mapping
host mapping add <account> <principal> Add a principal to the account, deduplicating; the principal’s syntax is validated before anything is written
host mapping remove <account> <principal> Remove that principal from the account (a no-op if it is not present)
host mapping remove <account> Remove the entire account mapping
Terminal window
sudo ssoossh host mapping add deploy alice@example.com
sudo ssoossh host mapping list
sudo ssoossh host mapping remove deploy alice@example.com

Reports whether this host’s sshd will accept ssoossh certificates. Run it as root after setting a host up, and from configuration management after every change: it exits non-zero when any check fails.

Terminal window
sudo ssoossh host check
sudo ssoossh host check --user deploy --addr 10.0.0.5

It reads sshd’s own effective configuration (sshd -T), so Include order, built-in defaults and, with --user, Match blocks are resolved by sshd itself rather than by a parser that could disagree with it. It is read-only: it changes no file and reloads nothing.

Flag Default What it does
--user <account> none Apply sshd’s Match blocks for this account, and list the principals that may log in as it
--addr <address> none Apply Match blocks for this source address
--sshd <path> sshd on PATH, then /usr/sbin/sshd The sshd to ask
Check Fails when
pubkey-auth PubkeyAuthentication is off. A certificate login is public key authentication.
trusted-ca TrustedUserCAKeys is none, unreadable, or holds no key. sshd then refuses every certificate and logs only Failed publickey.
ca-match The host trusts none of the CA keys the server signs with. Missing only some of them is a warning: a rotation in progress.
ca-signature CASignatureAlgorithms does not allow the algorithm the CA signs with, as under a FIPS policy that drops ssh-ed25519
cert-types PubkeyAcceptedAlgorithms allows no certificate type the client generates. Refusing only some is a warning.
principals-command AuthorizedPrincipalsCommand is relative, or its resolved file or any directory above it is not root-owned or is group- or world-writable, so sshd refuses to run it
principals-user AuthorizedPrincipalsCommandUser is unset or does not exist
principals The command line passes no %u
principals-mapping The mapping file exists but will not load
mapping-access The command’s account cannot read the mapping file

The rest are notes or warnings and never fail the run: TrustedUserCAKeys writable by someone other than root; an AuthorizedPrincipalsCommand naming the /usr/local/bin/ssoossh compatibility link, which sshd follows to /usr/bin/ssoossh and runs until the link is removed; plain public keys still accepted beside certificates (plain-keys asks whether that is intended; it is how the docs suggest adopting ssoossh); and a clock that is not synchronized.

The CA keys to compare with come from a pinned capubkey when there is one, otherwise from the server, never from the CA cache. When neither is available ca-match is a warning and every other check still runs: the local findings do not depend on reaching the server, or on an ssh-agent.

Enrolls a keypair, bound by the server to an enrollment code, for later unattended certificate retrieval. The keypair is either generated here or already present on disk.

Flag Default What it does
--key <path> none, required Keypair path, relative or absolute. Generates both files if neither <path> nor <path>.pub exists; enrolls the existing pair if both do; refuses if only one does
--retrieve off Immediately redeem the code once and write the certificate to <path>-cert.pub
--extensions <list> none Certificate extensions to request, comma-separated. The approver sees them and can change the set
Terminal window
ssoossh service enroll --key /etc/backup/id --retrieve
ssoossh service enroll --key /etc/backup/id --extensions permit-pty

Nothing is requested by default, which is the right posture for an unattended account: a job that needs no agent forwarding should not hold the permission to do it. What this flag sends is a request – the approver sees it, may change it, and the server bounds the result by cert_options.service.extensions either way, so it cannot obtain anything the deployment has not permitted.

Redeems an enrollment code, writing the certificate to <path>-cert.pub and checking local disk first to avoid unnecessary server calls.

Flag Default What it does
--code <code> none, required The enrollment code to redeem
--key <path> none, required Keypair path; the certificate lands at <path>-cert.pub
--grace <duration> 1m How much validity a certificate on disk must still have before it counts as fresh, for example 30s, 5m, 1h
--force off Retrieve a new certificate even if a valid one exists on disk
Terminal window
ssoossh service retrieve --code K7M4QP2X --key /etc/backup/id

Both service commands are covered in full, with worked examples, on Service accounts.

Prints version, commit, build info, and the platform (linux/amd64). Offline: it makes no network call. ssoossh --version prints the same line.

Terminal window
ssoossh version
ssoossh --version
ssoossh version --json

With --json it prints the same values as an object (including os and arch), plus the list of command paths this build implements. That list is the supported way for a deployment tool to tell releases apart: probing --help output breaks on wording no release promises to keep.

ssoossh completion <shell> prints a completion script for bash, zsh, fish, or powershell. ssoossh completion <shell> --help says where to put it. For example, for bash:

Terminal window
ssoossh completion bash | sudo tee /etc/bash_completion.d/ssoossh >/dev/null

The packages do not install a completion script, so this is a one-time step per machine.