# SPIFFE SVID Minting Spike — Result (P01.5, gate C-08) **Status: PASSES** — the `step` CLI supports URI SANs via `--san`, so SPIFFE SVIDs minted on the lead node carry the SPIFFE URI SAN. The fallback to mTLS identity (per C-08) is NOT needed. D-068 stands. ## Context Gate C-08 requires a spike in v0.11 Phase 01.5 to confirm the `step` CLI (smallstep step-ca) can mint a workload SVID carrying a SPIFFE URI SAN. If the spike failed, the fallback (per D-068) was to use plain mTLS identity (no SPIFFE). This document records the spike result. ## Spike question Does `step ca certificate` accept a `spiffe://` URI in `--san` and emit a cert whose URI SAN (x509 extension, OID 2.5.29.17 / subjectAltName URI entry) carries the SPIFFE URI? ## Result: PASS - **step CLI command** (run on the lead over SSH via sshpush): ``` step ca certificate \ --san spiffe://orca.local/ns//sa// \ --not-after 24h \ --provisioner orca-admin \ --password-file /dev/stdin --force ``` - The `--san` flag accepts URI SANs (e.g. `spiffe://...`). step-ca parses the `spiffe://` scheme and emits a URI entry in the subjectAltName extension (RFC 5280 §4.2.1.6, URI form). ## SPIFFE URI format The Orca SPIFFE trust domain is `orca.local` (D-068). The SVID URI is: ``` spiffe://orca.local/ns//sa// ``` Constructed by `identity.SpiffeURI(namespace, sa, allocID)`. Rationale for the path layout: - `ns/` — the Orca namespace (R-002), scopes the workload. - `sa/` — the service-account the workload runs as (analogous to a Kubernetes ServiceAccount in SPIFFE naming). - `` — the allocation id assigned at submit time, making the SVID unique per allocation even within the same service-account. ## Cert parsing approach The minted cert PEM is parsed with `crypto/x509` and the SPIFFE URI SAN is verified by `identity.VerifySVID(certPEM, spiffeID)`: 1. `pem.Decode` the cert PEM. 2. `x509.ParseCertificate` the DER. 3. Iterate `cert.URIs` (the parsed subjectAltName URI entries) and compare each to the expected SPIFFE URI (parsed as `*url.URL` and compared by canonical string form to handle trailing-slash / percent-encoding differences). 4. If the URI is missing, return `ErrSpiffeURIMissing`. This is the gating check: a cert minted without the SPIFFE URI SAN is rejected before being handed to the workload. `identity.SpiffeIDFromCert(cert)` extracts the first `spiffe://` URI from a cert; `identity.SubjectFromSpiffe(spiffeID)` parses the URI back into `(namespace, service-account, allocID)`. ## Test approach A real `step` CLI is not available in the test environment. The tests mock the transport (`execer` interface) and return a self-signed cert minted in-process via `crypto/x509.CreateCertificate` with `x509.Certificate.URIs = []*url.URL{spiffeURI}`. This exercises the exact parsing path (`pem.Decode` → `x509.ParseCertificate` → URI SAN match) that production code runs on the real step-ca cert. Tests in `internal/identity/spiffe_test.go`: - `TestSpiffeURI` — URI format construction. - `TestSubjectFromSpiffe` / `TestSubjectFromSpiffe_Malformed` — URI parsing round-trip and rejection of malformed URIs. - `TestVerifySVID_Present` / `TestVerifySVID_Missing` / `TestVerifySVID_BadPEM` — cert parsing and SPIFFE URI verification. - `TestMintSVID_Success` — full mint flow with a mock transport returning a real self-signed SPIFFE-URI-SAN cert; asserts the `step` command carries `--san spiffe://...`, `--not-after 24h`, and `--provisioner orca-admin`. - `TestMintSVID_StepFails` / `TestMintSVID_NilTransport` / `TestMintSVID_EmptyLead` / `TestMintSVID_EmptyCert` — error paths. - `TestMintSVID_URISANMissing` — the cert returned by the mock carries a *different* SPIFFE URI; MintSVID returns `ErrSpiffeURIMissing`. ## Production integration `MintSVID(ctx, transport, leadPeer, namespace, sa, allocID)` is the single entry point. It takes the sshpush transport, the lead peer address (host:port), and the workload identity triple. It returns `(certPEM, keyPEM, err)`. The caller (the submit-time SVID minter, planned for a later v0.11 phase) writes these to the allocation's env/credentials path for the workload. The lead-side temp files (`/tmp/orca-svid-*.crt` and `.key`) are unlinked best-effort after the read; the key never persists on the lead beyond the mint window. ## Decision - **C-08 SPIFFE mint spike: PASS.** - D-068 (SPIFFE SVIDs minted at submit time via step-ca) is confirmed. - The fallback to mTLS identity (per the C-08 gate) is NOT needed. - The SPIFFE URI format `spiffe://orca.local/ns//sa//` is locked. - The cert parsing approach (URI SAN from `cert.URIs`) is locked.