From 0e5aa044c0248b9f997687a9e77d813645a2b866 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Mon, 20 Jul 2026 09:49:30 +1000 Subject: [PATCH] Move nix-cache's binary cache signing key into sops nix-serve's secretKeyFile was a manual, undocumented-outside-a-comment `nix-store --generate-binary-cache-key` step per host -- easy to miss on a fresh nix-cache instance (as lxc-nix-cache testing just found: systemd fails the unit with EXIT_CREDENTIALS when LoadCredential can't find the source file, which nginx then reports as a 502 from clients). It also can't be regenerated per-host safely: modules/nix-cache/client.nix hardcodes every client's trust in one specific public key, so every nix-cache instance has to share the exact same keypair. Sourced from secrets/nix-cache.yaml's new cache-priv-key entry instead, via the same sops-nix pattern every other secret in this repo already uses. Verified the added value derives to the exact public key modules/nix-cache/client.nix already trusts before committing. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01La55Nsss8jZ7ZuzUV9mfot --- docs/nix-cache.md | 37 +++++++++++++++++++++++++++--------- modules/nix-cache/server.nix | 20 ++++++++++--------- secrets/nix-cache.yaml | 5 +++-- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/docs/nix-cache.md b/docs/nix-cache.md index ad2b1a4..63fe209 100644 --- a/docs/nix-cache.md +++ b/docs/nix-cache.md @@ -11,19 +11,38 @@ This repository configures `nix-cache` as a **binary cache server** and a **remo - Client hosts import `modules/nix-cache/client.nix` and, when remote building is enabled, `modules/nix-cache/remote-builder-client.nix`. - The `nix-cache` host imports `modules/nix-cache/server.nix`. -## Binary cache signing keys (on nix-cache) +## Binary cache signing key + +`modules/nix-cache/client.nix` hardcodes every client's trust in one +specific public key (`cache.local-1:usoWYanY3Kpq2+kDIS2nhWoLZiRxanmdysdzqCFBHW4=`). +That means whichever host is currently playing the `nix-cache` role has to +use that *exact* keypair — not a freshly generated one — or no client will +accept substitutes from it (they'd just silently fall back to building +from source). So unlike most per-host secrets, this one can't be +self-generated on first boot; it's managed via sops-nix like every other +secret in this repo, sourced from `secrets/nix-cache.yaml`'s +`cache-priv-key` entry (`modules/nix-cache/server.nix`). + +**Adding or rotating the value:** ```bash -sudo install -d -m 0700 /etc/nix -sudo nix-store --generate-binary-cache-key nix-cache-1 /etc/nix/cache-priv.pem /etc/nix/cache-pub.pem -sudo chmod 0600 /etc/nix/cache-priv.pem -sudo chmod 0644 /etc/nix/cache-pub.pem -cat /etc/nix/cache-pub.pem +nix-shell -p sops --run 'sops secrets/nix-cache.yaml' ``` -Do not commit private keys. -Do not commit new password hashes or live credentials. Existing committed hashes -should be rotated and moved to host-local secret management. +Add (or replace) a `cache-priv-key` entry with the private key file's exact +contents. If you don't have it yet, generate a keypair once: + +```bash +nix-store --generate-binary-cache-key nix-cache-1 cache-priv.pem cache-pub.pem +``` + +— paste `cache-priv.pem`'s contents into the `cache-priv-key` entry above, +delete both local files afterward, and update +`trusted-public-keys` in `modules/nix-cache/client.nix` (and every already-built +client) to match `cache-pub.pem` if this is a genuine rotation rather than +a first-time bootstrap. Any `nixos-configurations.*-nix-cache` host picks +the new key up automatically on next activation — no more manual +`/etc/nix/cache-priv.pem` install step. ## Remote builder SSH keys diff --git a/modules/nix-cache/server.nix b/modules/nix-cache/server.nix index eec4609..cd9c716 100644 --- a/modules/nix-cache/server.nix +++ b/modules/nix-cache/server.nix @@ -1,18 +1,20 @@ { config, pkgs, vars, ... }: { - # Generate the binary cache key pair on the nix-cache host: - # sudo install -d -m 0700 /etc/nix - # sudo nix-store --generate-binary-cache-key nix-cache-1 \ - # /etc/nix/cache-priv.pem \ - # /etc/nix/cache-pub.pem - # sudo chmod 0600 /etc/nix/cache-priv.pem - # sudo chmod 0644 /etc/nix/cache-pub.pem - # cat /etc/nix/cache-pub.pem + # nix-serve's signing key has to be the *same* key on every host that + # ever plays the nix-cache role -- modules/nix-cache/client.nix hardcodes + # every client's trust in one specific public key ("cache.local-1:..."), + # so a freshly self-generated key here wouldn't be trusted by anyone. + # Managed via sops-nix like every other secret in this repo instead of + # the old manual `nix-store --generate-binary-cache-key` step -- see + # "Binary cache signing key" in docs/nix-cache.md for how to add/rotate + # the value in secrets/nix-cache.yaml. + sops.secrets."cache-priv-key".sopsFile = ../../secrets/nix-cache.yaml; + services = { nix-serve = { enable = true; - secretKeyFile = "/etc/nix/cache-priv.pem"; + secretKeyFile = config.sops.secrets."cache-priv-key".path; }; nginx = { diff --git a/secrets/nix-cache.yaml b/secrets/nix-cache.yaml index b9b48a1..6d5ae6a 100644 --- a/secrets/nix-cache.yaml +++ b/secrets/nix-cache.yaml @@ -1,4 +1,5 @@ beszel-token: ENC[AES256_GCM,data:meuzUP/6wCssJDVTgbC0XwiLZPMGyDl55HEIiON9xOXCD9k6,iv:TDqWcp+8Mxd8wN09r5otQRQXq3XTeQphaTWxvvuLTAs=,tag:cRPZQGlwB/dTguBAheWPQg==,type:str] +cache-priv-key: ENC[AES256_GCM,data:6vQKIf7eS0WNL2Eptoi4VWr18SRMZfN/H/aFUUtXdMYQY5LLyBp2EHRKqZcGFuh1nZhUdAxUztq/CVXx+QFxKW+ElHxCxUSp0QqI1fdSkBkKZb8hlit5SoX9JtLzZGg0HBNM3nJu,iv:0J+xmrPJhInHhFR/c41ACjuTfaIoMkQFSfbL2KkgFa8=,tag:f4s9Szs5oprVVRSyXaX48A==,type:str] sops: age: - enc: | @@ -28,7 +29,7 @@ sops: 2SEMsctdGC+5E3ilPXvPpZ5RONZHbXxn6kQRBlBv6AJERpGDzsfgfA== -----END AGE ENCRYPTED FILE----- recipient: age164px2a8e48ptsf9ngtan38aa6jls4jdl26mzrgzf6sn3vcvt49hqjrgr8w - lastmodified: "2026-07-19T02:30:40Z" - mac: ENC[AES256_GCM,data:7+FeT6aeCGn+JFBXbPO0qP4BJ1nHPSennewv1kWkG+hOTIqs1ymuswUK1Hyfi6Z9h2umFX9HvK+o3qtmYvk6k7BUNe6w6QUHTNwm6lmNqrb7sgAE3iFVI2p9m14NGhgoTfnXx1M4JIZ1iuNYhCukpENI4+svIe+r7x5YeE5Evac=,iv:4AKAPI6upyAvHBr8BLWX7R/NupmJdcXdqiN8e0ZQ3ls=,tag:TkpfpCaLhn+Mx5cQZZuMdA==,type:str] + lastmodified: "2026-07-19T23:30:21Z" + mac: ENC[AES256_GCM,data:kLGE2xawQT7mx+sfw68hmGk5nCEGiEjZrqTEl9B1dtQmTrMwmoVr/1RISi4LfJrwxy31mDgff4lcIL4wIJuM373uk3X8j4RNyYQNTfKEkORT6r8NHeepNs267O77pKGd7OmcM4MT/BqOnB8ELS7Wlf2ect7CAlvUUVyc8icxgZE=,iv:EYLDsHYHZ1XOQXafOTqHHWpk/OBNq/R6IJnOBYV33E4=,tag:thxrCPC5oGvDjhK7Dz87YA==,type:str] unencrypted_suffix: _unencrypted version: 3.13.1