How ssoossh works
What ssoossh is made of, what a certificate is here, and which flow applies to which kind of login. Read this first if you are deciding whether ssoossh fits your deployment, then Keys and certificates compared for what changes against plain SSH keys; the pages after those walk each flow end to end.
The components
Section titled “The components”ssoosshd– the server. Authenticates people through OIDC, optionally enriches the identity from LDAP, decides what a certificate may carry, signs public keys, and serves the web UI for approval, confirmation, and per-user certificate history. Go, on top of gin.ssoossh– the client. macOS, Linux, and Windows. Invoked fromssh_configas aProxyCommandor aMatch exec, or run by hand. It talks to the server over HTTPS and waits for issuance over a server-sent-events stream. It manages its own keypair and loads the result into your ssh-agent, or writes key files when no agent is available.pam_ssoossh– a PAM module in theauthmanagement group. It generates an ephemeral keypair, requests a certificate, validates it, and discards everything. It backssudo,su, a password-lesssshdstack, and consolelogin.
The first two are built and released together. pam_ssoossh is a separate
project, written in C and released from
github.com/mnestor/ssoossh-pam; it
shares no code with the server and is held to it by a versioned
wire contract instead. Its documentation
lives here, on this site, starting at
installing pam_ssoossh.
Two constraints shape all three:
- The server never receives a private key. The client sends private keys nowhere except the local ssh-agent or a local file.
- The client never opens a listening port. There is no loopback redirect: the browser lands on the server, and the client learns the outcome only over its own stream.
What a certificate is here
Section titled “What a certificate is here”An SSH certificate is a signed statement that a particular public key may log
in as a particular set of login names, for a particular window of time, with a
particular set of capabilities. Target hosts hold no per-person keys; they
trust one CA public key in TrustedUserCAKeys and check every certificate
against it.
That is the whole trick, and it is what makes the rest follow: removing
someone is a change at the identity provider, not a sweep of
authorized_keys files, and a leaked certificate stops working on its own
when its window closes rather than when somebody remembers to revoke it.
The CA private key comes from exactly one of four places, and one of them
must be set or the server does not start: an inline PEM in
ssh_key, a key file named by
ssh_key_file, an
ssh-agent named by ssh_key_agent, where
the server never holds the key, or a PKCS#11 token under
hsm, where the private half never leaves
the hardware.
Certificate types and status
Section titled “Certificate types and status”| Type | Purpose | Status |
|---|---|---|
| User | interactive SSH | shipped end to end |
| PAM | sudo/su via pam_ssoossh |
shipped end to end |
| Console | interactive login at a machine with no browser, approved by a typed code | server and web UI shipped; pam_ssoossh implements console mode, but has been run only against a stub of these endpoints, never the real ones |
| Service | non-interactive: enroll once, retrieve unattended, every retrieval logged | shipped end to end |
The status vocabulary used across this site:
| Status | What it means |
|---|---|
| shipped end to end | every half exists and is released: the server, the client or PAM module that drives it, and the configuration keys named on this site. For the PAM types that release is ssoossh-pam’s own, on its own cadence |
| server shipped | the server and web UI exist; the piece that runs on the host is separate and may be at a different stage |
| not built | a design exists under docs/proposals/ in the source repository and nothing else. Nothing on this site describes it as configurable |
Each type is its own configuration block –
cert_options.user,
cert_options.service,
cert_options.pam, and
cert_options.console –
with its own lifetime ceiling, its own extension ceiling, and its own key ID
template, so a sudo and an SSH login by the same person stay
distinguishable in an audit log.
ssoosshd issues no host certificates. Without a secure way for a host to prove
its claim to a hostname, host identity would be a hole rather than a feature.
The client keeps local principal-mapping tooling (ssoossh host mapping,
ssoossh host principals) for sshd’s AuthorizedPrincipalsCommand; it has no
server side.
Certificate types at a glance
Section titled “Certificate types at a glance”flowchart LR
accTitle: The four certificate types and what trusts them
accDescr {
One CA, held by ssoosshd as a PEM in configuration or a key file, or
kept in an ssh-agent or on a PKCS#11 token, issues four kinds of
certificate: user certificates for
interactive SSH, service certificates for non-interactive jobs, PAM
certificates for sudo and su, and console certificates for logging in at
a machine with no browser. User and service certificates are presented
to target hosts, which trust the same CA.
}
CA["ssoossh CA<br/>PEM, key file, ssh-agent<br/>or PKCS#11 token"]
CA --> U["User certificate<br/>interactive SSH<br/>shipped"]
CA --> S["Service certificate<br/>non-interactive<br/>shipped"]
CA --> P["PAM certificate<br/>sudo/su<br/>shipped"]
CA --> C["Console certificate<br/>login at a console<br/>server shipped"]
U --> T["Target hosts trust the CA"]
S --> T
The shape of every issuance
Section titled “The shape of every issuance”Whatever the type, issuance has the same five beats:
- Create. Something asks: the client for a person at a terminal, the PAM
module for a
sudoor a console login, or an enrollment code for an unattended job. - Approve. A human authenticates through the identity provider and approves in the browser. The approval page shows what will be issued, with anything policy trimmed struck through, before anyone approves. Nothing reachable over HTTP can exceed the config file.
- Sign. Signing happens asynchronously off a queue. The signer holds the CA key and has no database access, so it can run as a separate, minimally privileged process.
- Deliver. The certificate goes straight to the waiting caller. Issued certificates are never stored server-side, so there is no certificate store to steal, and a caller that misses the window re-requests.
- Record. Every decision is recorded append-only: who approved or denied,
from where, when, and what was actually granted.
sshdlogs the key ID on every login, so the trail reaches the target hosts themselves.
Denial resolves the caller cleanly, and a request nobody answers expires on its own within the type’s budget.
The service path is the one exception to “a human every time”: a person approves exactly once, at enrollment, and the enrollment code redeems certificates unattended after that.
Where each flow is documented
Section titled “Where each flow is documented”| Flow | Page |
|---|---|
How this differs from authorized_keys, situation by situation |
Keys and certificates compared |
A person runs ssh host |
Interactive user certificates |
| The same flow, narrated for a newcomer | Illustrated walkthrough |
| What a certificate may carry, and for how long | Options and lifetime resolution |
| A backup job or CI runner with no human present | Service certificates |
sudo and su on a host |
sudo and su through PAM |
| A login at a serial console, BMC viewer, or VM console | Console login |
| How the PAM flows compare with passwords and hardware tokens | Passwords, tokens, and pam_ssoossh |
| What holds all of it together | Security model |
Related
Section titled “Related”- Getting started – the components and how the server is configured.
- Deployment overview – standing a server up.
- Hosts overview – what a target host needs.
- Configuration reference – every key, its type, and its default.
- Decisions – what ssoossh deliberately does not do, including host certificates.