guildhouse-spire-plugins/docs/ssh-certificate-flow.md
Tyler King 420a4e2ea0 Remediate all 17 audit findings from AUDIT.md
Critical fixes:
- F-01: SatScope array form support (single pointer → slice with polymorphic JSON)
- F-02: Add governance-intent@guildhouse.dev as 10th Shellstream extension
- F-06: Replace os.Exit(1) stubs with go-plugin Serve() boilerplate in all cmd/
- F-13: Validate SatScope.ResourcePattern is non-empty

High priority:
- F-03: Add normative Accord policy syntax note to credential-governance.md §8.2
- F-04: Replace OID XXXXX placeholder with explicit PEN reference and IANA TODO
- F-05: Document CredentialComposer hook mapping in spec and plugin-types.md
- F-07/F-08: Commit CI pipeline (.github/workflows/ci.yaml)
- F-09: Add hashicorp/go-plugin v1.6.3 to go.mod

Medium priority:
- F-10: Wire sample-ssh-cert-extensions.json fixture into shellstream tests
- F-11: Cross-reference merkle proof depth limit (256 leaves) in governance spec
- F-12: Add YAML format clarification headers to deploy configs
- F-14: Expand README with project status, docs links, and quick-start

Low priority:
- F-15: Standardize "SSH SVID" → "SSH-SVID" terminology across docs
- F-16: Add GovernanceEpochSeconds to PluginConfig and deploy configs
- F-17: Add troubleshooting section to deployment.md, error handling to OIDC docs

Global: Rename all extension keys from @guildhouse.io to @guildhouse.dev

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:45:33 -05:00

6.1 KiB

SSH Certificate Issuance Flow

End-to-end flow from workload request to governed SSH session.

Sequence

Workload      SPIRE Agent    SPIRE Server    ssh-credential-    Governance     Notary
                                              composer           Service        Service
  |               |               |               |               |              |
  | FetchSSHSVID  |               |               |               |              |
  |-------------->|               |               |               |              |
  |               | Attest(pid)   |               |               |              |
  |               |--+            |               |               |              |
  |               |  | oidc-attestor              |               |              |
  |               |<-+            |               |               |              |
  |               |               |               |               |              |
  |               | MintSSHSVID   |               |               |              |
  |               |-------------->|               |               |              |
  |               |               | ComposeWorkloadCred            |              |
  |               |               |-------------->|               |              |
  |               |               |               |               |              |
  |               |               |               | CreateIntent  |              |
  |               |               |               |-------------->|              |
  |               |               |               |   intent_id   |              |
  |               |               |               |<--------------|              |
  |               |               |               |               |              |
  |               |               |               | RedeemIntent  |              |
  |               |               |               |-------------->|              |
  |               |               |               |   SAT         |              |
  |               |               |               |<--------------|              |
  |               |               |               |               |              |
  |               |               |               | Build SSH cert with          |
  |               |               |               | Shellstream extensions        |
  |               |               |               |               |              |
  |               |               |               | CreateAnchor  |              |
  |               |               |               |------------------------------>|
  |               |               |               |   merkle_root |              |
  |               |               |               |<------------------------------|
  |               |               |               |               |              |
  |               |               |  SSH cert     |               |              |
  |               |               |<--------------|               |              |
  |               |  SSH cert     |               |               |              |
  |               |<--------------|               |               |              |
  | SSH cert      |               |               |               |              |
  |<--------------|               |               |               |              |

Step-by-Step

1. Workload Requests SSH-SVID

The workload calls the SPIRE Workload API via Unix domain socket, requesting an SSH-SVID. It provides its SSH public key (Ed25519).

2. Agent Attests Workload

The SPIRE Agent identifies the calling process via kernel-level attestation. The oidc-attestor plugin verifies the workload's OIDC token and returns selectors. The agent matches selectors against registration entries.

3. Agent Forwards to Server

The agent sends a MintSSHSVID request to the SPIRE Server over the Agent-Server mTLS channel, including the workload's SPIFFE ID, public key, and requested principals.

4. CredentialComposer Pipeline

The SPIRE Server invokes the ssh-credential-composer plugin during credential minting.

5. Governance Intent

The composer calls GovernanceService.CreateIntent with:

  • registry_type: "credential"
  • verb: "issue"
  • artifact_scope: JSON describing the SSH certificate parameters
  • Identity from SPIRE attestation

If the Accord policy requires a ceremony, the flow blocks until approval.

6. SAT Issuance

The composer calls GovernanceService.RedeemIntent to obtain a SAT (Substrate Attestation Token) authorizing the credential issuance.

7. SSH Certificate Construction

The composer builds the SSH certificate:

  • Key ID: SPIFFE ID
  • Principals: SPIFFE ID + additional principals from registration
  • TTL: Per-workload configuration (default 5 minutes)
  • Extensions: Standard SSH extensions + Shellstream governance extensions

Shellstream extensions embedded:

  • sat-scope@guildhouse.dev — SAT authorization scope
  • sat-hash@guildhouse.dev — SHA-256 of the SAT
  • tenant-id@guildhouse.dev — Tenant UUID
  • roles@guildhouse.dev — Assigned roles
  • merkle-root@guildhouse.dev — Governance tree root at issuance
  • governance-epoch@guildhouse.dev — Current epoch counter

8. Merkle Anchoring

The composer constructs a MutationEnvelope (RFC 8785 JCS + domain-separated SHA-256) and submits the leaf hash to NotaryService.CreateAnchor.

9. Certificate Delivery

The signed SSH certificate flows back through the server → agent → workload chain. The workload receives the certificate, private key (if agent-generated), and SSH CA trust bundle.

Using the Certificate

The workload uses the SSH-SVID to connect to governed hosts:

ssh -o CertificateFile=/tmp/ssh-svid-cert.pub \
    -i /tmp/ssh-svid-key \
    target-host.example.org

Server-Side Validation

The SSH server:

  1. Validates the certificate signature against TrustedUserCAKeys (from SPIRE trust bundle)
  2. Checks the certificate validity period
  3. Matches principals against AuthorizedPrincipalsFile
  4. Reads Shellstream extensions for authorization decisions (tenant, roles, SAT scope)
  5. Optionally verifies the merkle proof against the NotaryService for audit