Skip to main content

Using native SSH tools through pc

This guide shows how to connect to managed hosts with native OpenSSH toolsssh, one-shot remote commands, ansible, and (in later phases) scp/rsync and VS Code / Cursor Remote-SSH — routed through pc with the same guarantees as pc ssh: no host sshd, no host SSH credentials, RBAC-gated, session-recorded.

For how it works under the hood (the SSH CA, the transparent relay, why the agent terminates SSH), see OpenSSH Integration — Architecture.

TL;DR

Run pc login then pc config once. After that, ssh <login>@<host>.<proxy> (and ansible, remote commands) Just Work — gated by your terminal RBAC and recorded for replay with pc play. Nothing is installed or exposed on the target.

One-time setup

# 1. Authenticate (Google SSO, local, or a service-account API key)
pc login --auth google

# 2. Emit the OpenSSH config + trust + a short-lived user certificate
pc config --write

pc config --write does three things:

It writesPurpose
~/.ssh/config.d/pc (a Match exec hook + a Host *.<proxy> block)refreshes your short-lived cert before each connection, routes matching hosts through pc proxy ssh as an OpenSSH ProxyCommand, and points ssh at your user cert
~/.config/pc/known_hosts (@cert-authority *.<proxy>)trusts the Proxima Host CA, so there are no host-key prompts and no per-host known_hosts churn
~/.config/pc/keys/id_pc-cert.pubyour short-lived user certificate (principals = your allowed logins; embeds your per-host RBAC)

The user cert is short-lived (1 hour) and auto-refreshed — you don't manage it. The emitted config begins with a line like:

Match host *.<proxy> exec "pc proxy refresh-cert"

OpenSSH runs that hook before it loads your certificate for a connection, so pc re-issues the cert just-in-time and the fresh one is what's offered to the agent. (It must run there: a refresh inside the ProxyCommand happens after OpenSSH has already loaded the cert, so it can't help the current connection.) The hook is a quiet no-op — no network call — when the cert is still fresh.

<proxy> is your Console host (e.g. api-console.prxm.uz); ensure your OpenSSH ~/.ssh/config includes the config.d directory (Include ~/.ssh/config.d/*), which pc config sets up.

Upgrading

If you set up native SSH before this auto-refresh hook existed, your cert will expire after an hour and ssh will fail with Permission denied (publickey). Re-run pc config --write (or pc config >> ~/.ssh/config) once to install the Match exec line — after that, refresh is automatic.

What happens on connect

Use cases

✅ Interactive shell — built

You get a full PTY as deploy on web01, recorded end-to-end. The login (deploy) must be in your cert's principals and permitted on that host by your terminal RBAC (see Who can log in where).

✅ One-shot remote command — built

ssh [email protected] 'systemctl status nginx'
ssh [email protected] 'pg_isready'

Non-interactive exec — ideal for scripts and health probes. Output and exit code propagate normally; the command is recorded too.

✅ Ansible (raw / command / shell modules) — built

Point Ansible at the proxied hosts and it uses your pc-issued cert via the ProxyCommand automatically:

# inventory.ini
[web]
web01.api-console.prxm.uz ansible_user=deploy
ansible web -i inventory.ini -m raw     -a 'uptime'
ansible web -i inventory.ini -m command -a 'systemctl is-active nginx'

Module types that run a command over an exec channel work today. Modules that copy files (copy, template, synchronize, fetch) need the SFTP subsystem — see below.

scp / rsync (file copy) — Phase 3 (SFTP subsystem)

scp ./app.tar.gz [email protected]:/tmp/   # planned
rsync -az ./site/ [email protected]:/var/www/ # planned

These need the agent's SSH SFTP subsystem, which lands in Phase 3. The recorded, RBAC-gated model is identical — only the channel type is new.

⏳ VS Code / Cursor Remote-SSH, DB GUIs — Phase 4 (direct-tcpip)

Remote-SSH and TCP port-forwarding (e.g. a DB client tunnelled over SSH) need direct-tcpip channels, which land in Phase 4. After that, "Connect to Host → web01.api-console.prxm.uz" works with no extra setup.

Who can log in where

Access is decided in two places, both from your terminal RBAC (the terminal_spec on your roles):

  1. Cert principals = your role-wide allowed logins (e.g. deploy, readonly). You can only request ssh <login>@… for a login in this set.
  2. Per-host check (at the agent): the agent re-evaluates the spec embedded in your cert against the target host's tags — so a role can allow root only on env=staging hosts, deploy everywhere, etc. This is the authoritative check and exactly matches pc ssh.

An unauthorized login or host is denied at the agent, even if the cert is otherwise valid. Cert issuance itself requires terminal:write (super admins and wildcard service accounts included).

Recordings

Every shell and command session is recorded as an asciicast and uploaded, just like pc ssh. Replay with:

pc play <session-id>

Recording is fail-closed: if your role requires recording but the agent can't record, the session is refused rather than run unrecorded.

Replay (pc play) — in progress

SSH-CA sessions are captured on the agent today, but surfacing them in the console for pc play replay is still being wired up (the recording pipeline is shared with pc ssh, which pre-creates a session record the native-SSH path does not yet). Until then, native-SSH sessions are recorded but not yet replayable from the console.

Automation with a service account

Use a service-account API key (with a role that grants terminal:write + a terminal spec) for non-interactive automation:

PC_API_KEY=… pc login --auth apikey
pc config --write
ansible all -i inventory.ini -m raw -a 'uptime'

Troubleshooting

SymptomCause / fix
you do not have terminal access on pc configYour account/role lacks terminal:write, or its terminal spec resolves no logins. Grant terminal access on the relevant client.
Permission denied (publickey)Either the login you used isn't in your cert principals / isn't allowed on that host by your spec (check ssh-keygen -L -f ~/.config/pc/keys/id_pc-cert.pub), or your cert expired and your config predates the auto-refresh hook — re-run pc config --write once to install the Match exec line (see Upgrading above).
proxima: failed to start session (unknown user …)The login you connected as isn't an OS user on that host. Native SSH does not auto-create users — use a login that exists there (e.g. root, or a provisioned account).
Host-key / certificate warningRe-run pc config to refresh the @cert-authority line; ensure you connect via the *.<proxy> name, not a raw IP.
agent did not respond / host offlineThe target host's agent isn't connected. Check pc ls.
server certificate has changed on any pc commandThe Console's TLS cert rotated. Remove the stale pin (~/.config/pc/trusted-certs/<host>.pem) and pc login again to re-verify.

What's built today

CapabilityState
Interactive shell · one-shot command · ansible (raw/command/shell)✅ built
Per-host RBAC + session recording (replay with pc play)✅ built
scp / rsync (SFTP subsystem)⏳ Phase 3
VS Code Remote-SSH · DB-GUI tunnels (direct-tcpip)⏳ Phase 4