M0 complete: sops-nix wiring + decrypt-a-test-secret; M0 gate CLAIMED
Host decrypts /run/secrets/test_secret via its ssh host key (age identity); off-box master recovery recipient. sops-nix pinned to a buildGoModule-era rev for nixpkgs 24.11 compat. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
39
JOURNAL.md
39
JOURNAL.md
@ -58,3 +58,42 @@ baseline; networking is up. Clean up by choosing one stack later.
|
||||
|
||||
**Next:** sops-nix wiring (host age key from ssh host key + a decrypt-a-test-secret proof), then
|
||||
CLAIM the M0 gate for the Adversary.
|
||||
|
||||
## 2026-05-26 — M0: sops-nix wiring + decrypt-a-test-secret (M0 COMPLETE, gate CLAIMED)
|
||||
|
||||
**Keys:**
|
||||
- Host age recipient from ssh host key: `ssh cc-ci 'nix run nixpkgs#ssh-to-age -- -i
|
||||
/etc/ssh/ssh_host_ed25519_key.pub'` → `age1h90utdztfc23kx8ewrtrtk80mnddvrf8pg4ppej55rwwwupzhfvqhmp3qa`.
|
||||
- Master recovery key generated on host (`age-keygen`), public `age1cmk26t…`; private moved off-box
|
||||
to `/srv/cc-ci/.sops/master-age.txt` (mode 600) and `shred`-ded from the host. Never in repo.
|
||||
|
||||
**Files:** `.sops.yaml` (both recipients, rule `secrets/.*\.(yaml|json|env)$`); `modules/secrets.nix`
|
||||
(`sops.age.sshKeyPaths=[/etc/ssh/ssh_host_ed25519_key]`, `secrets.test_secret={}`); flake gains
|
||||
`sops-nix` input + `sops-nix.nixosModules.sops`; configuration.nix imports the module.
|
||||
|
||||
**sops-nix version pin (dead-end avoided):** master sops-nix wants `buildGo125Module` (Go 1.25),
|
||||
absent in pinned nixpkgs 24.11 → eval error. Pinned sops-nix to `77c423a…` (2025-06-17, last using
|
||||
plain `buildGoModule`). Verified the file at that rev uses `buildGoModule`. Build then OK.
|
||||
|
||||
**Encrypt test secret:** on host, `printf 'test_secret: cc-ci-m0-<rand>' > secrets/secrets.yaml`
|
||||
then `nix run nixpkgs#sops -- --encrypt --in-place secrets/secrets.yaml` (run inside repo so
|
||||
`.sops.yaml` resolves) → rc=0, two age recipients in the file.
|
||||
|
||||
**Build + switch (commands + output):**
|
||||
- `nixos-rebuild build --flake .#cc-ci` → `BUILD EXIT 0` (built sops-install-secrets w/ Go 1.23.8).
|
||||
- `systemd-run --unit=ccci-rebuild2 ... nixos-rebuild switch --flake /root/cc-ci#cc-ci` →
|
||||
`Result=success ExecMainStatus=0`.
|
||||
|
||||
**Gate verification (M0):**
|
||||
- `systemctl is-system-running` → `running`; `systemctl --failed` → none.
|
||||
- `ls -la /run/secrets/test_secret` → `-r-------- 1 root root 41` ; `stat` → `root:root 400`.
|
||||
- `head -c9` → `cc-ci-m0-` (matches generated value), `wc -c` → 41 (9 + 32 hex). Decrypt path proven.
|
||||
- Pulled encrypted `secrets/secrets.yaml` + `flake.lock` back to clone; `grep cc-ci-m0 secrets.yaml`
|
||||
→ no plaintext leak; lock inputs = nixpkgs, sops-nix.
|
||||
|
||||
**Gate handshake:** set `Gate: M0 — CLAIMED, awaiting Adversary` in STATUS.md. REVIEW.md still empty
|
||||
(no Adversary activity yet). Per §6.1 liveness I won't idle-block: I keep M0 claimed and proceed
|
||||
with M1 (independent infra build), without advancing to M2 until M0 shows PASS.
|
||||
|
||||
**Next:** M1 — Docker + single-node swarm via Nix (modules/swarm.nix), then Traefik (file provider
|
||||
→ /var/lib/ci-certs/live/) + abra, then a by-hand HTTPS deploy/teardown of a trivial recipe.
|
||||
|
||||
Reference in New Issue
Block a user