Skip to main content
An ssh lane is an SSH server with the Sidecar’s enforcement built into it. People reach a host with the clients they already use — ssh, sftp, scp, rsync — and what they do arrives as statements carrying a verified identity: a one-shot command in full, each file operation with its path. Guardrails allow or deny them, masking rewrites what comes back, and the audit trail records who did what. Use it to put policy in front of the hosts people still need a shell on — a production box, a jump host, a bastion — without replacing the tooling they reach it with. Nothing changes on the client side; the credential does, because this lane accepts certificates and nothing else. There is no password to guess and no authorized_keys to manage. It is also the one lane that does not relay. SSH is encrypted end to end, so nothing in a middle position can read it; to see a command at all, a component has to be one end of the connection. So an ssh lane terminates the handshake itself: it verifies the client’s certificate against a CA it trusts, resolves the requested login name to an account on the host, and spawns the shell or the command locally. There is no upstream to proxy to and no sshd behind it. The one exception proves the rule. A listener carrying an ssh.relay block terminates the client’s session too — it just terminates it in the middle, then opens its own connection to a stock sshd. It still has to be one end of the client’s connection to read a command; what changes is that it is also one end of a second connection the client never makes.
config.yaml
That is a working end-hop. A client reaches it with ssh -p 2222 devuser@host, and the certificate, the account, the guardrail, the mask and the audit record all happen in that one process.

How it differs

The last two rows are the ones that surprise people. An ssh lane runs processes, so the host it sits on needs accounts, groups and login shells lined up with the certificates your CA issues — see Host Configuration. And a masked byte stream cannot change length, so strategy: mask is the only strategy this lane accepts.
A lane that terminates the protocol also means there is no authorized_keys, no password authentication and no PAM. Certificates are the only credential. That is what makes a listener on a public address defensible: there is nothing to brute-force.

Topologies

The same end-hop configuration serves the first three. What changes is what sits in front of it, and the answer to “what is enforced” does not change with it. Mode 4 is the exception to everything above: the endpoint moves to the middle, the bastion decrypts every session behind it, and file transfer is not available. It is the right answer for an appliance, a vendor-managed host, or an evaluation with no install budget — and the wrong one anywhere you could put the endpoint on the target. Bastion SSH Termination states the trade in full. In modes 2 and 3, the client’s own ssh -J runs two independent handshakes over one TCP path, presenting the same certificate to both. Nothing is re-signed in the middle, and no Sidecar anywhere holds a private signing key. Mode 4 is different: the bastion terminates the inner session and authenticates to the target with a credential it holds (or the client’s forwarded agent). Topologies has the sequence for each, and what config makes a listener a bastion instead of an end-hop.

Enforcement

In modes 1–3 every row above is enforced at the end-hop. On a listener with ssh.relay, the same controls are enforced at the bastion for every destination the relay map covers, and the target’s stock sshd enforces only its own authentication. See Bastion SSH Termination. And the honest other half: an interactive shell carries no guardrails. A keystroke stream has no statement boundary a rule could act on, and reconstructing one is unsound. A shell is admitted, its output is masked, and it is recorded as events — never as content. A deployment that needs every action to be a rule-readable statement drops shell from capabilities_allowed. Configuration states this in full.

Operations

An SSH statement is text, and what the text is depends on the operation — a command line for exec_line, a variable name for env_set, a path for every sftp_*. Scope every rule with operations: Four rule types are refused at load on an ssh lane, because nothing here produces what they read: table, http_resource, http_status and grpc_status. The full vocabulary, with what each operation matches, is in Guardrail Rules.

Try it locally

The repository carries a complete local stack — three topologies, six lanes, a minted CA, and a script that asserts every claim on these pages:

ssh-stack on GitHub

Direct, hoop-bastion and stock-sshd-bastion topologies against one end-hop, plus lanes for multi-account login, an exec-only listener and certificate-extension identity.

Next

Topologies

The four topologies, what makes a listener a bastion, and why the end-hop enforces the same thing in three of them.

Bastion SSH Termination

Mode 4: the ssh.relay block, upstream credentials, host-key checking, and inspecting a host that runs nothing.

Configuration

Every attribute: host_key, trusted_ca, the tri-state capabilities_allowed, destinations_allowed and identity.

Certificates and Identity

What your CA must put in a certificate, which field decides what, and what refuses the whole certificate.

Host Configuration

Accounts, groups, login shells, home directories, and the root vs non-root trade.

OpenSSH Differences

The sshd_config keyword mapping, every assumption to drop, and what is not implemented.

File Transfer

sftp, scp both ways, rsync, and why masking and rsync cannot coexist.

Known Limitations

What the lane does not do: guardrails on a shell, what the trail holds, and the boundary masking is applied on.