feat(federation): Step-CA sidecar in federated compose [FED-M2-02] #490

Merged
jason.woltje merged 2 commits from feat/federation-m2-stepca into main 2026-04-22 02:21:51 +00:00
Owner

Summary

Adds a profile-gated step-ca service to docker-compose.federated.yml so the federated tier has its own internal CA. No code uses the CA yet — that lands in M2-04 (CA service).

What's in this PR

  • docker-compose.federated.yml: new step-ca service (image smallstep/step-ca:0.27.4, named volume step_ca_data, port 9000, [federated] profile gate, healthcheck with 30s start_period)
  • infra/step-ca/init.sh: idempotent first-boot init creating CA + JWK provisioner mosaic-fed
  • infra/step-ca/dev-password.example: sample dev password (real file gitignored)
  • infra/step-ca/templates/federation.tpl: SAN OID template skeleton (TODO: M2-04 lands real OID-bearing CSRs)
  • .gitignore: ignore real dev password file

Manual verification

  • docker compose -f docker-compose.federated.yml --profile federated up -d step-ca brings the CA up
  • docker compose -f docker-compose.federated.yml --profile federated logs step-ca shows "Server is starting on :9000"
  • curl -k https://localhost:9000/health returns 200
  • Idempotent: re-run up -d does not re-init (init.sh skips when /home/step/config/ca.json already exists)

Test plan

  • pnpm format:check passes
  • pnpm typecheck passes (all cached, no TS changes)
  • pnpm lint passes (all cached, no TS changes)
  • docker compose -f docker-compose.federated.yml config --quiet validates YAML syntax
  • CI green
  • M2-04 will exercise CSR submission against this CA

Decisions to confirm before M2-04

  1. Image tag: Used smallstep/step-ca:0.27.4 (pinned stable as of late 2025). If Docker Hub shows a newer 0.27.* patch by the time M2-04 lands, bump then.
  2. OID template skeleton: infra/step-ca/templates/federation.tpl is wired but incomplete. It sets keyUsage: digitalSignature and extKeyUsage: clientAuth — correct for federation client certs. The custom OID extension block (OIDs 1.3.6.1.4.1.99999.1 / .2) is stubbed with a TODO comment because the exact Step-CA template syntax for otherName SAN extensions requires testing against a live CA. M2-04 (CA service + CSR submission) will prove this end-to-end.
  3. --no-db flag on init: Step-CA is initialized with --no-db (no BadgerDB). This is appropriate for a sidecar whose cert state lives in the named volume; it avoids BadgerDB locking issues in containers. If OCSP/CRL storage is needed later, this flag should be revisited.
  4. Password mount path: Dev uses a bind-mount at ./infra/step-ca/dev-password/run/secrets/ca_password. Production should replace the bind-mount with a Docker secret (same mount path, init.sh unchanged).

Refs #461

## Summary Adds a profile-gated `step-ca` service to `docker-compose.federated.yml` so the federated tier has its own internal CA. No code uses the CA yet — that lands in M2-04 (CA service). ## What's in this PR - `docker-compose.federated.yml`: new `step-ca` service (image `smallstep/step-ca:0.27.4`, named volume `step_ca_data`, port 9000, `[federated]` profile gate, healthcheck with 30s start_period) - `infra/step-ca/init.sh`: idempotent first-boot init creating CA + JWK provisioner `mosaic-fed` - `infra/step-ca/dev-password.example`: sample dev password (real file gitignored) - `infra/step-ca/templates/federation.tpl`: SAN OID template skeleton (TODO: M2-04 lands real OID-bearing CSRs) - `.gitignore`: ignore real dev password file ## Manual verification - `docker compose -f docker-compose.federated.yml --profile federated up -d step-ca` brings the CA up - `docker compose -f docker-compose.federated.yml --profile federated logs step-ca` shows "Server is starting on :9000" - `curl -k https://localhost:9000/health` returns 200 - Idempotent: re-run `up -d` does not re-init (init.sh skips when `/home/step/config/ca.json` already exists) ## Test plan - [x] `pnpm format:check` passes - [x] `pnpm typecheck` passes (all cached, no TS changes) - [x] `pnpm lint` passes (all cached, no TS changes) - [x] `docker compose -f docker-compose.federated.yml config --quiet` validates YAML syntax - [ ] CI green - [ ] M2-04 will exercise CSR submission against this CA ## Decisions to confirm before M2-04 1. **Image tag:** Used `smallstep/step-ca:0.27.4` (pinned stable as of late 2025). If Docker Hub shows a newer `0.27.*` patch by the time M2-04 lands, bump then. 2. **OID template skeleton:** `infra/step-ca/templates/federation.tpl` is wired but incomplete. It sets `keyUsage: digitalSignature` and `extKeyUsage: clientAuth` — correct for federation client certs. The custom OID extension block (OIDs `1.3.6.1.4.1.99999.1` / `.2`) is stubbed with a TODO comment because the exact Step-CA template syntax for `otherName` SAN extensions requires testing against a live CA. M2-04 (CA service + CSR submission) will prove this end-to-end. 3. **`--no-db` flag on init:** Step-CA is initialized with `--no-db` (no BadgerDB). This is appropriate for a sidecar whose cert state lives in the named volume; it avoids BadgerDB locking issues in containers. If OCSP/CRL storage is needed later, this flag should be revisited. 4. **Password mount path:** Dev uses a bind-mount at `./infra/step-ca/dev-password` → `/run/secrets/ca_password`. Production should replace the bind-mount with a Docker secret (same mount path, init.sh unchanged). Refs #461
jason.woltje force-pushed feat/federation-m2-stepca from d1925149c6 to 586129faf4 2026-04-22 02:09:47 +00:00 Compare
jason.woltje merged commit c56dda74aa into main 2026-04-22 02:21:51 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#490