# sops-nix wiring (D6 infra secrets). cc-ci decrypts secrets at activation using its own # ed25519 SSH host key as the age identity (no separate key file to manage on the box). # Encrypted material lives in ../secrets/secrets.yaml — Phase-1c moved this into the private # `cc-ci-secrets` repo, mounted here as a git SUBMODULE at ../secrets/ (so the path is unchanged). # Readable only by the recipients in secrets/.sops.yaml (host key + off-box master recovery key). { config, ... }: { sops = { defaultSopsFile = ../secrets/secrets.yaml; # Decrypt using the host's SSH host key (converted to an age identity by sops-nix). age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; # Phase-1c: also accept a bootstrap age key at a fixed path — THE one out-of-band secret, # provisioned to the host before the first rebuild. On the canonical cc-ci this holds the # host-derived age identity (== the sshKeyPaths recipient, no new exposure); on a fresh/cloned # host (e.g. the throwaway-VM rebuild) it holds the off-box recovery key, so a host whose SSH # host key is NOT a sops recipient can still decrypt every secret. NOTE: sops-install-secrets # aborts activation if this file is set but missing, so it must exist before `nixos-rebuild`. age.keyFile = "/var/lib/sops-nix/key.txt"; # Do not also look for a GPG key. gnupg.sshKeyPaths = [ ]; # M0 proof secret — confirms the decrypt path works end to end. secrets.test_secret = { }; # M2 Drone (A2 internal secrets). drone_rpc_secret is shared between the swarm-deployed # Drone server (inserted as the `rpc_secret` swarm secret by scripts/deploy-drone.sh) and # the host exec runner (read via the env template below). drone_gitea_client_secret is the # Gitea OAuth app secret, inserted as the server's `client_secret` swarm secret. secrets.drone_rpc_secret = { }; secrets.drone_gitea_client_secret = { }; # M3 comment-bridge (A2). Read by modules/bridge.nix's reconcile oneshot, which copies them # into swarm secrets the bridge container mounts. webhook_hmac is also set on the Gitea webhook. secrets.bridge_webhook_hmac = { }; secrets.bridge_drone_token = { }; secrets.bridge_gitea_token = { }; # Phase-1c C2: the wildcard TLS cert+key are now sops secrets (in cc-ci-secrets), decrypted at # activation to /var/lib/ci-certs/live/{fullchain.pem,privkey.pem} — the exact path the traefik # reconcile (modules/proxy.nix) already reads. Replaces the prior operator-drops-a-cert-file step. secrets.wildcard_cert = { path = "/var/lib/ci-certs/live/fullchain.pem"; mode = "0444"; # leaf+intermediate chain — not secret }; secrets.wildcard_key = { path = "/var/lib/ci-certs/live/privkey.pem"; mode = "0400"; # private key — root only }; # EnvironmentFile for the host exec runner: DRONE_RPC_SECRET rendered from the sops secret. templates."drone-runner.env".content = '' DRONE_RPC_SECRET=${config.sops.placeholder.drone_rpc_secret} ''; }; }