# 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 <spiffe-id> <cert-path> <key-path> \
      --san spiffe://orca.local/ns/<ns>/sa/<sa>/<alloc-id> \
      --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/<namespace>/sa/<service-account>/<alloc-id>
```

Constructed by `identity.SpiffeURI(namespace, sa, allocID)`.

Rationale for the path layout:
- `ns/<namespace>` — the Orca namespace (R-002), scopes the workload.
- `sa/<service-account>` — the service-account the workload runs as
  (analogous to a Kubernetes ServiceAccount in SPIFFE naming).
- `<alloc-id>` — 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/<ns>/sa/<sa>/<alloc-id>`
  is locked.
- The cert parsing approach (URI SAN from `cert.URIs`) is locked.
