Skip to main content

OpenSSH Integration via a Proxima SSH CA

This page explains how Proxima Console lets native OpenSSH toolsssh, scp, sftp, rsync, ansible, and VS Code / Cursor Remote-SSH — connect to managed hosts through pc, while keeping the same guarantees as pc ssh: no host sshd, no host SSH credentials, RBAC-gated, session-recorded.

The one principle

Whoever terminates the SSH protocol is the only party that can authenticate, authorize, and record it. Proxima makes itself an SSH certificate authority and has the agent terminate SSH — so native SSH gets the same auth + recording as pc ssh. The host's own sshd is never involved.

Components

ComponentRole
pc CLIHolds a short-lived SSH user cert; runs as OpenSSH ProxyCommand; emits ~/.ssh/config
Backend (REST)/api/v1/ssh/* — issues user certs (RBAC-gated), serves the Host CA public key
Backend (gRPC)ProxySSH — a transparent byte relay; authorizes the dial, never parses SSH
VaultCustodies the User CA + Host CA; signs every cert (CA keys never leave Vault)
NATSBackend ↔ agent transport (control commands + the relayed SSH byte stream)
AgentRuns the SSH server that terminates SSH, enforces per-host RBAC, and records

Trust model — two CAs, mutual short-lived certs

There are no authorized_keys files and no long-lived host keys. The agent trusts the User CA; the client trusts the Host CA (via one @cert-authority line).

Flow A — Setup & certificate issuance  ✅ built

pc config (or pc login) obtains a short-lived user cert and writes the OpenSSH config.

The emitted ~/.ssh/config:

Match host *.<proxy> exec "pc proxy refresh-cert"
Host *.<proxy>
UserKnownHostsFile ~/.config/pc/known_hosts
IdentityFile ~/.config/pc/keys/id_pc
CertificateFile ~/.config/pc/keys/id_pc-cert.pub
Host *.<proxy> !<proxy>
ProxyCommand pc proxy ssh %r@%h:%p

The cert is re-issued automatically by pc when it nears expiry. The Match exec runs pc proxy refresh-cert before OpenSSH loads CertificateFile, so the just-in-time cert is the one offered to the agent — a ProxyCommand-side refresh would run too late (OpenSSH loads the cert first). The hook is a silent no-op (no network call) when the cert is still fresh.

Flow B — Connecting with a native tool  ✅ built (shell + exec)

Why the agent — not the backend — terminates SSH

The backend relay is a blind ciphertext pipe, so it can stay out of the SSH crypto path while still RBAC-gating the dial. The agent holds the plaintext stream — which is exactly what lets it check the cert, authorize the login per host (using the spec embedded in the cert + the host's tags), and record every keystroke into the same pipeline pc ssh uses (replayable with pc play). A transparent tunnel to a host's own sshd could do none of that.

Where Vault fits

Both CAs live in Vault's SSH secrets enginessh-user-ca (signs user certs) and ssh-host-ca (signs agent host certs). The backend calls <mount>/sign/<role>; the private CA keys never leave Vault. In dev (no Vault) the backend falls back to an in-process ephemeral CA so the issuance endpoints work for local testing.

Build status

PieceState
SSH CA service + Vault/local signers✅ built
POST /ssh/certs + GET /ssh/host-ca (RBAC, embedded spec, no-store, audited)✅ built
pc user-cert management (issue / store / auto-refresh)✅ built
pc config (ProxyCommand config + @cert-authority known_hosts)✅ built
Agent SSH host key + Host-CA cert + User CA (enroll/renew)✅ built
gRPC ProxySSH relay (transparent, RBAC-gated dial)✅ built
Agent SSH server — cert auth + per-host RBAC + recorded shell/exec✅ built
pc proxy ssh (ProxyCommand transport)✅ built
SFTP (scp/rsync) · direct-tcpip (VS Code, DB GUIs)⏳ Phase 3–4

Both the issuance half (CLI ↔ backend ↔ Vault) and the connection half (pc proxy ssh ↔ relay ↔ agent SSH server) are built and tested end-to-end: native ssh runs an interactive shell or a one-shot command through pc, the agent enforces per-host login RBAC and records the session (replayable with pc play). SFTP (for scp/rsync) and direct-tcpip port forwarding (VS Code Remote-SSH, DB GUIs) follow in Phases 3–4. See the engineering design in docs/superpowers/specs/2026-06-09-pc-ssh-ca-openssh-integration-design.md.