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>
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 scopesat-hash@guildhouse.dev— SHA-256 of the SATtenant-id@guildhouse.dev— Tenant UUIDroles@guildhouse.dev— Assigned rolesmerkle-root@guildhouse.dev— Governance tree root at issuancegovernance-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:
- Validates the certificate signature against
TrustedUserCAKeys(from SPIRE trust bundle) - Checks the certificate validity period
- Matches principals against
AuthorizedPrincipalsFile - Reads Shellstream extensions for authorization decisions (tenant, roles, SAT scope)
- Optionally verifies the merkle proof against the NotaryService for audit