spec: runbook-pack/v0.2 id: nk.ssh-certificates title: Short-lived SSH credentials for admins, agents and automations owner: net-kingdom outcome: An actor obtains a short-lived CA-signed SSH certificate and uses it through an ops-bridge tunnel, with no static key doing the work. engine: native framing: - Certificate files must be mode 600 and are never reused across reconnects. - A non-zero cert_command exit is a failure and must trigger backoff. - ops-warden never vends API keys or passwords; route them with warden route find. actors: - id: operator role: Operator description: Signs and inspects the certificate and brings the tunnel up, using their own identity. privileges: [sign-certificate, open-tunnel] datapoints: - id: actor_name label: Actor name type: string default: agt-rehearsal pattern: "(adm|agt|atm)-[a-z0-9-]+" help: "Actor type prefix decides the maximum TTL: adm 48h, agt 24h, atm 8h. agt-rehearsal is an inert test actor (2h, a principal no host trusts); use your own actor for real access." dimensions: {actor: operator, kind: identity, subsystem: ops-warden} ask_in: ready - id: warden_config label: warden config file type: path default: ~/.config/warden/rehearsal/warden.yaml help: The rehearsal config uses a throwaway local CA that nothing trusts and has no flex-auth gate, so it proves the signing mechanics, not the policy gate. For real access use your production config, ~/.config/warden/warden.yaml. dimensions: {actor: operator, kind: location, subsystem: ops-warden} ask_in: ready - id: pubkey label: Public key path type: path default: ~/.ssh/agt-rehearsal_ed25519.pub dimensions: {actor: operator, kind: location, subsystem: ops-warden} ask_in: ready - id: tunnel label: Tunnel name type: string default: k3s-api-railiance01 pattern: "[a-z0-9-]+" dimensions: {kind: target, subsystem: ops-bridge} ask_in: ready - id: test_target label: Is there a target that trusts your actor's principal? type: enum values: [available, none-yet] default: none-yet help: With the inert rehearsal actor no host trusts the certificate, so the tunnel cannot be proven. Choose available only with a real actor and a tunnel that uses it. dimensions: {kind: state, subsystem: ops-bridge} ask_in: connect stages: - id: ready title: Before you start goal: You know what is in place and which certificates exist already. steps: - id: prerequisites title: Confirm the prerequisites actor: operator owner: workstation description: "In place before you start: the warden CLI is installed and your actor is in the principals inventory (ops-warden); the bridge CLI and a tunnel definition exist (ops-bridge); the target hosts trust the SSH CA and carry the actor principal (railiance-infra)." idempotent: idempotent verify: done_when: All three prerequisites hold expect: manual - id: status-before title: Look at current certificates actor: operator owner: ops-warden requires: [prerequisites] uses: [warden_config] command: WARDEN_CONFIG={{warden_config}} warden status idempotent: idempotent verify: done_when: You know which certificates are current and which are expired expect: manual - id: get-certificate title: Get a certificate goal: A short-lived certificate for the actor exists and its lifetime is within the limit for the actor type. requires: [ready] steps: - id: sign title: Sign a public key for the actor actor: operator owner: ops-warden uses: [actor_name, pubkey, warden_config] command: WARDEN_CONFIG={{warden_config}} warden sign {{actor_name}} --pubkey {{pubkey}} > /tmp/{{actor_name}}-cert.pub idempotent: idempotent idempotent_note: Each run issues a new certificate and overwrites the file; the old one expires on its own. rollback: Delete /tmp/{{actor_name}}-cert.pub; the certificate expires on its own. evidence: [certificate_valid_before] verify: done_when: A certificate file exists and is readable as a certificate command: ssh-keygen -L -f /tmp/{{actor_name}}-cert.pub expect: exit-0 - id: inspect-ttl title: Check the certificate lifetime actor: operator owner: ops-warden requires: [sign] uses: [actor_name] command: ssh-keygen -L -f /tmp/{{actor_name}}-cert.pub | grep -E "Key ID|Principals|Valid" idempotent: idempotent verify: done_when: "Valid before is within the actor-type TTL (adm 48h, agt 24h, atm 8h)" expect: manual gates: - id: certificate-valid title: The certificate is valid and short-lived goal: short-lived-credentials blocking: true downstream_risk: A tunnel opened with a certificate that outlives its limit defeats the point of short-lived credentials. checks: - done_when: The lifetime is within the limit for the actor type expect: manual - done_when: The certificate file can be read command: ssh-keygen -L -f /tmp/{{actor_name}}-cert.pub expect: exit-0 - id: connect title: Use it through a tunnel goal: The tunnel that uses the certificate is up and the signing is on record. requires: ["gate:certificate-valid"] steps: - id: tunnel-up title: Bring up the tunnel that uses cert_command actor: operator owner: ops-bridge uses: [tunnel, test_target] description: A tunnel only proves the certificate if a host trusts its principal. With the inert rehearsal actor none does, so record that no target exists yet; the stage is then not proven. idempotent: idempotent one_of: - id: bring-up title: Bring up the tunnel that uses the certificate recommended_when: {test_target: [available]} command: bridge up {{tunnel}} rollback: bridge down {{tunnel}} verify: done_when: The tunnel shows connected command: bridge status expect: output-contains contains: "{{tunnel}}" - id: no-target-yet title: No target trusts this actor yet; tunnel not proven recommended_when: {test_target: [none-yet]} verify: done_when: You have recorded that the tunnel stage was not proven expect: manual - id: audit title: Confirm the signing was audited actor: operator owner: ops-warden requires: [tunnel-up] uses: [warden_config] command: WARDEN_CONFIG={{warden_config}} warden log | tail -5 idempotent: idempotent verify: done_when: Your signing appears in the history expect: manual gates: - id: tunnel-connected title: The tunnel is connected, or its absence is recorded goal: private-access blocking: true downstream_risk: A pass here could be read as proof that private access works. checks: - done_when: bridge reports the tunnel as connected, or "tunnel not proven" is recorded because no target exists expect: manual ownership: - {concern: Certificate issuance and TTL policy, owner: ops-warden} - {concern: Tunnel lifecycle and refresh, owner: ops-bridge} - {concern: Host CA trust and principals, owner: railiance-infra}