# Shellstream SSH Certificate Extensions ## 1. Abstract Shellstream extensions are a set of SSH certificate extensions using the `@guildhouse.dev` vendor suffix that carry structured governance metadata within SSH certificates issued by SPIRE. These extensions encode authorization scope, tenant context, governance ceremony references, and merkle audit proofs, enabling SSH servers to make fine-grained authorization decisions based on Guildhouse platform state without requiring separate API calls at connection time. ## 2. Status **Draft Specification** -- This document is a working draft and subject to change. It defines the normative behavior that conforming implementations MUST follow once finalized. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. ## 3. Terminology **Shellstream Extension** : An SSH certificate extension whose name uses the `@guildhouse.dev` vendor suffix and whose value carries Guildhouse governance metadata as defined in this specification. **SSH Certificate Extension** : A key-value string pair embedded in an OpenSSH certificate as defined in the OpenSSH PROTOCOL.certkeys document. Extensions are advisory and do not restrict the certificate holder; they convey additional information to the server. **Vendor Suffix** : The `@domain` portion of an extension name that designates the namespace owner, following the OpenSSH convention for avoiding collisions between independently defined extensions. **SAT (Substrate Attestation Token)** : A signed token issued by the Quartermaster credential service that binds a SPIFFE identity to a set of permitted operations on a specific registry type. The SAT is the primary authorization artifact in the Guildhouse platform. **SatScope** : A structured object within a SAT that defines the registry type, permitted verbs, and resource pattern for which the token grants access. **Governance Ceremony** : A structured approval workflow managed by the Bascule CeremonyService that authorizes privilege elevation. Ceremony types range from self-granted to quorum-based approval. **Merkle Anchor** : A cryptographic commitment (merkle tree root hash) representing the complete governance state at a point in time. Each governance mutation is recorded as a leaf in the tree. **MutationEnvelope** : A signed wrapper around a governance state change that is recorded as a leaf in the governance merkle tree. **Accord Policy** : A tenant-scoped authorization policy evaluated by the Accord policy engine (backed by OPA) that defines roles, permissions, and ceremony requirements for a tenant. **Trust Domain** : A SPIFFE trust domain (e.g., `guildhouse.dev`) that defines the boundary within which SPIFFE identities and their associated attestations are valid. ## 4. Introduction SSH certificates, as defined by OpenSSH's PROTOCOL.certkeys, support arbitrary extensions as key-value string pairs. By convention, vendor- specific extensions use the `name@domain` format to avoid collisions with extensions defined by other parties or by future OpenSSH releases. Shellstream extensions embed Guildhouse governance metadata into SSH certificates so that SSH servers can make authorization decisions based on platform state without issuing separate API calls. When SPIRE issues an SSH certificate for a Guildhouse workload or user, the certificate may include Shellstream extensions that describe: - **What** the holder is authorized to do (SAT scope). - **Who** the holder is acting as (tenant identity, roles). - **Why** elevated access was granted (ceremony reference). - **When** the governance state was captured (merkle root, epoch). This decoupling of authorization metadata from runtime API lookups enables offline authorization decisions, improves latency, and creates a cryptographically verifiable audit trail linking SSH sessions to governance state. ## 5. Extension Format ### 5.1 Naming Convention All Shellstream extensions use the `@guildhouse.dev` vendor suffix. Extension names MUST be lowercase, hyphen-separated identifiers followed by the suffix: ``` @guildhouse.dev ``` where `` matches the regular expression `[a-z][a-z0-9]*(-[a-z0-9]+)*`. ### 5.2 Value Encoding Extension values are UTF-8 strings, as constrained by the SSH certificate extension format (RFC 4251 string type). All values MUST be valid UTF-8. Binary data MUST be encoded as follows: - Cryptographic hashes: lowercase hexadecimal encoding. - Proofs and opaque binary payloads: base64 encoding using the standard alphabet with padding (RFC 4648 Section 4). JSON-structured values MUST use compact encoding with no unnecessary whitespace (no spaces after colons or commas, no newlines or indentation). ## 6. Extension Registry This section defines each Shellstream extension. Extensions marked REQUIRED MUST be present in every Shellstream-bearing SSH certificate. Extensions marked OPTIONAL MAY be omitted. ### 6.1 `sat-scope@guildhouse.dev` **Presence:** REQUIRED when a SAT is associated with the certificate. **Value:** A JSON object (or JSON array of objects when multiple scopes exist) with the following structure: ```json {"registry_type":"","verbs":["",...],"resource_pattern":""} ``` **Fields:** | Field | Type | Description | |--------------------|-----------------|-----------------------------------------------------------------------------| | `registry_type` | string | Identifies the registry kind. Values include `"oci"`, `"helm"`, `"git"`, `"database"`. | | `verbs` | array of string | Permitted operations. Examples: `["read","write"]`, `["push","pull"]`. | | `resource_pattern` | string | Glob pattern for resource matching. Examples: `"tenant-a/*"`, `"ns/repo:*"`. | When a single SAT scope exists, the value MUST be a single JSON object. When multiple SAT scopes exist, the value MUST be a JSON array of scope objects. Implementations MUST accept both forms. **Example (single scope):** ``` sat-scope@guildhouse.dev = {"registry_type":"oci","verbs":["push","pull"],"resource_pattern":"acme-corp/*"} ``` **Example (multiple scopes):** ``` sat-scope@guildhouse.dev = [{"registry_type":"oci","verbs":["pull"],"resource_pattern":"acme-corp/*"},{"registry_type":"helm","verbs":["read"],"resource_pattern":"charts/*"}] ``` ### 6.2 `sat-hash@guildhouse.dev` **Presence:** REQUIRED when a SAT is associated with the certificate. **Value:** Lowercase hex-encoded SHA-256 hash of the raw SAT bytes. The value MUST be exactly 64 hexadecimal characters (`[0-9a-f]{64}`). This hash is used for audit correlation -- it links the SSH session to the SAT without embedding the SAT itself in the certificate. **Example:** ``` sat-hash@guildhouse.dev = a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 ``` ### 6.3 `tenant-id@guildhouse.dev` **Presence:** REQUIRED. **Value:** UUID string formatted per RFC 4122, using lowercase hexadecimal digits with hyphens in the 8-4-4-4-12 grouping. The value MUST match the regular expression: ``` [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} ``` This extension identifies the tenant context for the SSH session. All authorization decisions MUST be scoped to this tenant. **Example:** ``` tenant-id@guildhouse.dev = 7b2a91c4-3f8e-4d12-b5a6-9c0e1d2f3a4b ``` ### 6.4 `roles@guildhouse.dev` **Presence:** REQUIRED. **Value:** Comma-separated list of role names with no whitespace. Each role name MUST match `[a-z][a-z0-9_]*`. Roles are defined by the tenant's Accord policy and represent the set of permissions the certificate holder has been granted for this session. **Example:** ``` roles@guildhouse.dev = analyst,viewer ``` ``` roles@guildhouse.dev = administrator ``` ### 6.5 `ceremony-id@guildhouse.dev` **Presence:** OPTIONAL -- present only for elevated sessions that were authorized through a governance ceremony. **Value:** UUID string formatted per RFC 4122, using the same format specified in Section 6.3. This extension references the governance ceremony that authorized the privilege elevation for this session. **Example:** ``` ceremony-id@guildhouse.dev = e4f5a6b7-8c9d-0e1f-2a3b-4c5d6e7f8a9b ``` ### 6.6 `ceremony-type@guildhouse.dev` **Presence:** OPTIONAL -- MUST be present when `ceremony-id@guildhouse.dev` is present. MUST NOT be present when `ceremony-id@guildhouse.dev` is absent. **Value:** One of the following string literals, corresponding to the `CeremonyType` enum from the Bascule CeremonyService: | Value | Description | |-------------------------|---------------------------------------------------------------------| | `self_grant` | The holder approved their own elevation (permitted by policy). | | `single_approval` | A single designated approver authorized the elevation. | | `quorum_approval` | A quorum of approvers collectively authorized the elevation. | | `emergency_break_glass` | Emergency access granted outside normal approval flow, with enhanced audit. | **Example:** ``` ceremony-type@guildhouse.dev = quorum_approval ``` ### 6.7 `merkle-root@guildhouse.dev` **Presence:** OPTIONAL. **Value:** Lowercase hex-encoded SHA-256 merkle root hash. The value MUST be exactly 64 hexadecimal characters (`[0-9a-f]{64}`). This is the root of the governance merkle tree at the time the certificate was issued. It allows offline verification that the certificate was issued during a known governance state. **Example:** ``` merkle-root@guildhouse.dev = 4d7a9c2e1f3b5a8d0e6c4b2a9f7e5d3c1b0a8f6e4d2c0b9a7f5e3d1c0b8a7f ``` ### 6.8 `merkle-proof@guildhouse.dev` **Presence:** OPTIONAL -- MUST be present only when `merkle-root@guildhouse.dev` is present. MAY be omitted even when `merkle-root` is present (the root alone is useful for epoch pinning). **Value:** Base64-encoded (standard alphabet with padding, per RFC 4648 Section 4) serialized inclusion proof. **Proof wire format:** The proof is a byte sequence consisting of concatenated 32-byte SHA-256 sibling hashes followed by a single final byte encoding the direction bits. Each bit in the direction byte indicates whether the corresponding sibling is on the left (0) or right (1) of the path, with the least-significant bit corresponding to the first sibling. This limits proofs to trees of depth 8 (256 leaves). For deeper trees, a multi-byte direction encoding will be specified in a future revision. **Example:** ``` merkle-proof@guildhouse.dev = QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ehQ= ``` ### 6.9 `governance-epoch@guildhouse.dev` **Presence:** OPTIONAL. **Value:** Decimal string representation of an unsigned 64-bit integer. The value MUST match `[1-9][0-9]*|0` (no leading zeros except for the value zero itself). The governance epoch is a monotonically increasing counter that increments with each governance state change. It enables stale-state detection without requiring full merkle verification: if a server's last-known epoch is greater than the certificate's epoch, the certificate was issued against stale governance state. **Example:** ``` governance-epoch@guildhouse.dev = 42 ``` ### 6.10 `governance-intent@guildhouse.dev` **Presence:** OPTIONAL -- present when the certificate was issued through the governance flow and has an associated MutationIntent. **Value:** UUID string formatted per RFC 4122, using the same format specified in Section 6.3. This extension references the MutationIntent that authorized the credential issuance. It enables audit correlation between the SSH certificate and the governance audit trail maintained by the GovernanceService. > **Security:** The `governance-intent` value MUST be set by the SSH > Credential Composer from the actual `CreateIntentResponse.intent_id`, > NOT from external input (e.g., requester-supplied headers). Verifiers > SHOULD cross-check this value against the GovernanceService to confirm > that the referenced intent exists, is in `redeemed` status, and > corresponds to this credential's issuance. A syntactically valid but > fabricated intent UUID would pass format validation but fail this > cross-check. **Example:** ``` governance-intent@guildhouse.dev = c8d9e0f1-2a3b-4c5d-6e7f-8a9b0c1d2e3f ``` ## 7. Encoding Rules The following encoding rules apply to all Shellstream extension values: 1. All values MUST be valid UTF-8 (RFC 3629). 2. Hash values (in `sat-hash`, `merkle-root`) MUST be lowercase hexadecimal (`[0-9a-f]+`). Uppercase hex digits MUST be rejected. 3. Base64 values (in `merkle-proof`) MUST use the standard alphabet (`A-Z`, `a-z`, `0-9`, `+`, `/`) with `=` padding as specified in RFC 4648 Section 4. URL-safe base64 MUST NOT be used. 4. JSON values (in `sat-scope`) MUST use compact encoding: no spaces after `:` or `,`, no newlines, no indentation. Parsers SHOULD accept non-compact JSON for robustness but generators MUST produce compact JSON. 5. UUID values (in `tenant-id`, `ceremony-id`, `governance-intent`) MUST be lowercase with hyphens in 8-4-4-4-12 format. Uppercase UUID strings MUST be rejected. 6. Numeric values (in `governance-epoch`) MUST be decimal strings without leading zeros (except for the literal `"0"`). 7. Comma-separated values (in `roles`) MUST NOT contain whitespace between items. ## 8. Validation Requirements Implementations receiving SSH certificates with Shellstream extensions MUST validate the following constraints before using extension values for authorization or audit purposes: ### 8.1 Structural Validation - Each extension value MUST conform to the format specified in its registry entry (Section 6). - Values that fail format validation MUST be treated as absent. The server MAY log a warning but MUST NOT terminate the SSH connection solely due to a malformed extension value. ### 8.2 Co-occurrence Constraints The following co-occurrence rules MUST be enforced: | If present | Then MUST also be present | |-------------------------------|--------------------------------| | `sat-scope@guildhouse.dev` | `sat-hash@guildhouse.dev` | | `sat-hash@guildhouse.dev` | `sat-scope@guildhouse.dev` | | `ceremony-id@guildhouse.dev` | `ceremony-type@guildhouse.dev` | | `ceremony-type@guildhouse.dev` | `ceremony-id@guildhouse.dev` | | `merkle-proof@guildhouse.dev` | `merkle-root@guildhouse.dev` | Note: `merkle-root@guildhouse.dev` MAY be present without `merkle-proof@guildhouse.dev` (root-only pinning). Note: `governance-intent@guildhouse.dev` has no co-occurrence constraints. It MAY appear independently or alongside merkle extensions. ### 8.3 Required Extensions The following extensions MUST always be present in a Shellstream-bearing SSH certificate: - `tenant-id@guildhouse.dev` - `roles@guildhouse.dev` A certificate that contains any `@guildhouse.dev` extension but is missing either `tenant-id` or `roles` MUST be treated as invalid. The server SHOULD reject the session. ### 8.4 Forward Compatibility Unknown extensions bearing the `@guildhouse.dev` suffix MUST be ignored. Implementations MUST NOT reject a certificate solely because it contains unrecognized `@guildhouse.dev` extensions. This ensures that new extensions can be introduced without breaking existing deployments. ## 9. Security Considerations ### 9.1 Extension Visibility SSH certificate extensions are not encrypted. Any entity that can read the certificate (including intermediate proxies, logging infrastructure, and the SSH server) can read extension values. Accordingly: - Implementations MUST NOT embed secrets, bearer tokens, private keys, or other sensitive credentials in extension values. - The `sat-hash` extension contains a SHA-256 hash of the SAT, not the SAT itself. The SAT MUST be validated through a separate, secure channel. ### 9.2 Authorization Boundary - Merkle proofs provide **auditability**, not authorization. A valid merkle inclusion proof means the credential issuance event was recorded in the governance tree; it does not assert that the event was correct or authorized. Authorization decisions MUST be based on SAT scope and Accord policy, not on merkle proof validity alone. - The `governance-epoch` extension enables stale-state detection but MUST NOT be used as the sole authorization signal. A stale epoch indicates that governance state may have changed since issuance; the server SHOULD require re-attestation in this case. ### 9.3 Parsing Safety Extension values are strings, not executable code. Implementations MUST NOT evaluate extension values as code, shell commands, SQL, or any other executable format. JSON values MUST be parsed with a standard JSON parser; hand-rolled parsers are strongly discouraged. ### 9.4 Size Constraints The total size of all Shellstream extension values (keys and values combined) SHOULD NOT exceed 4096 bytes (4 KB). Exceeding this limit may cause compatibility issues with certain SSH implementations that impose limits on certificate size. Implementations MAY reject certificates whose total `@guildhouse.dev` extension payload exceeds this threshold. ### 9.5 Replay and Freshness SSH certificates have their own validity period (valid-after to valid-before). Shellstream extensions inherit this validity window. Implementations SHOULD treat extension values as valid only within the certificate's validity period. The `governance-epoch` extension provides an additional freshness signal beyond the certificate's temporal validity. ## 10. Compatibility ### 10.1 SSH Protocol Compatibility All Shellstream extensions use the standard SSH certificate extension format: a string key mapping to a string value. This is fully compatible with OpenSSH and any SSH implementation that conforms to the PROTOCOL.certkeys specification. ### 10.2 Transparent Degradation SSH servers that do not understand Shellstream extensions will ignore them entirely. This is standard OpenSSH behavior for unrecognized extensions. Certificates bearing Shellstream extensions remain valid SSH certificates and can be used for authentication on non-Guildhouse SSH servers (though governance-based authorization will not be available). ### 10.3 Additive Evolution Extensions are additive. New `@guildhouse.dev` extensions can be introduced in future revisions of this specification without breaking existing parsers, per the forward compatibility rule in Section 8.4. ### 10.4 Version Negotiation Version negotiation is implicit via extension presence. There is no explicit version field. If a future revision deprecates or changes the semantics of an extension, it MUST do so under a new extension name. The original extension name retains its original semantics indefinitely. ### 10.5 `consent-channels@guildhouse.dev` **Presence:** OPTIONAL. **Value:** Comma-separated list of available consent transport channel identifiers with no whitespace. Each channel identifier MUST match `[a-z][a-z0-9]*(-[a-z0-9]+)*`. Valid channel identifiers (corresponding to `substrate:consent/channel.channel-kind`): | Identifier | Tier | Description | |------------------|------|------------------------------------------------| | `local-tty` | 0 | Synchronous, local terminal prompt | | `unix-socket` | 0-1 | Synchronous or async via Unix domain socket | | `dbus` | 1 | Asynchronous, local D-Bus notification | | `http-webhook` | 2 | Asynchronous, network HTTP webhook | | `message-queue` | 2 | Asynchronous, network message queue | | `store-forward` | 3 | Store-and-forward, delivered on reconnect | This extension advertises the consent transport channels available on the host that issued the certificate. Client modules use this information to determine which consent tier is available for governance operations requiring human or policy-automated approval. See [GH-DESIGN-0005 §5](../../guildhouse-platform/docs/GH-DESIGN-0005-wasm-component-model.md) for the tiered consent transport model. The value parallels the `consent_channels` field in `HostCapabilities` (SAT-SPEC-0001 §3.9). When both are present, they SHOULD contain the same set of channels. If they differ, the SAT's `HostCapabilities` is authoritative. **Example:** ``` consent-channels@guildhouse.dev = local-tty,unix-socket,http-webhook ``` **Example (air-gapped host):** ``` consent-channels@guildhouse.dev = local-tty ``` ### 10.6 `network-policy@guildhouse.dev` **Presence:** OPTIONAL. **Value:** SHA-256 hash (lowercase hexadecimal, exactly 64 characters) of the GovernedNetworkPolicy applied to this workload. The hash is computed over the canonical (RFC 8785 JCS) JSON serialization of the policy object. This extension binds network governance policy to workload identity through the SPIRE credential chain. The `ssh-credential-composer` embeds the policy hash when SPIRE issues an SVID for a pod. At CNI ADD time, Kedge reads the policy hash from the workload's SVID and passes it to the host function layer via `substrate:network/workload-network.attach-workload()` in the `governance-context` field. The host function layer resolves the hash to a full GovernedNetworkPolicy and installs identity-based flow rules in the eBPF enforcement plane. The trust chain: 1. SPIRE attests workload identity 2. `ssh-credential-composer` embeds `network-policy@guildhouse.dev` hash 3. Kedge CNI reads the hash during `CNI ADD` 4. `substrate:network` WIT host functions install governed flow policy 5. eBPF in the VPP processing graph enforces at wire speed 6. `governance-notifier` records the network attach event in Chronicle See [GH-DESIGN-0005 §11](../../guildhouse-platform/docs/GH-DESIGN-0005-wasm-component-model.md) for the GovernedNetworkPolicy schema and the network-as-API model. **Example:** ``` network-policy@guildhouse.dev = a1b2c3d4e5f6...64 hex chars... ``` **Co-occurrence:** This extension MAY appear alongside `sat-hash@guildhouse.dev`. When both are present, the SAT's `HostCapabilities.wit_packages` SHOULD include `substrate:network@0.1` to indicate that the host supports network governance host functions. ## 11. References - **OpenSSH PROTOCOL.certkeys** -- OpenSSH certificate format and extension mechanism. https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys - **RFC 2119** -- Key words for use in RFCs to Indicate Requirement Levels. Bradner, S. March 1997. https://datatracker.ietf.org/doc/html/rfc2119 - **RFC 3629** -- UTF-8, a transformation format of ISO 10646. Yergeau, F. November 2003. https://datatracker.ietf.org/doc/html/rfc3629 - **RFC 4122** -- A Universally Unique IDentifier (UUID) URN Namespace. Leach, P., Mealling, M., and R. Salz. July 2005. https://datatracker.ietf.org/doc/html/rfc4122 - **RFC 4251** -- The Secure Shell (SSH) Protocol Architecture. Ylonen, T. and C. Lonvick, Ed. January 2006. https://datatracker.ietf.org/doc/html/rfc4251 - **RFC 4648** -- The Base16, Base32, and Base64 Data Encodings. Josefsson, S. October 2006. https://datatracker.ietf.org/doc/html/rfc4648 - **RFC 8785** -- JSON Canonicalization Scheme (JCS). Rundgren, B., Jordan, B., and S. Erdtman. June 2020. https://datatracker.ietf.org/doc/html/rfc8785