From 8914fa79eda834383934f135d4114d4b08fdeb2f Mon Sep 17 00:00:00 2001 From: Trolli Schmittlauch Date: Mon, 6 Apr 2026 00:14:48 +0200 Subject: [PATCH] sops: first secret integration (nix-settings) --- .sops.yaml | 7 ++++++- common/default.nix | 1 + common/nix-settings.nix | 18 +++++++++++++++++- common/secrets.yaml | 26 ++++++++++++++++++++++++++ common/sops.nix | 11 +++++++++++ darwin/configuration.nix | 1 + darwin/sops.nix | 13 +++++++++++++ flake.nix | 6 +++--- home/common.nix | 1 + home/modules/sops.nix | 7 +++++++ 10 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 common/secrets.yaml create mode 100644 common/sops.nix create mode 100644 darwin/sops.nix create mode 100644 home/modules/sops.nix diff --git a/.sops.yaml b/.sops.yaml index 5263e08..5477595 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -6,7 +6,12 @@ keys: - &machine_framenix age1kx93vp8l8jd6kz0kvk379udr5z8a9t6946w0ff5t9a2esn47nqzqlfzvwe creation_rules: # per-host secrets for host specific ones, but for service modules we could store and manage them also per module scope - - path_regex: hosts/framenix/secrets/[^/]+\.(yaml|json|env|ini)$ + - path_regex: hosts/framenix/secrets\.(yaml|json|env|ini)$ + key_groups: + - age: + - *admins + - *machine_framenix + - path_regex: common/secrets\.(yaml|json|env|ini)$ key_groups: - age: - *admins diff --git a/common/default.nix b/common/default.nix index 29608ca..69fc017 100644 --- a/common/default.nix +++ b/common/default.nix @@ -18,6 +18,7 @@ in ./guest.nix ./audio-sharing.nix ./angrr.nix + ./sops.nix ]; services.davfs2.enable = true; diff --git a/common/nix-settings.nix b/common/nix-settings.nix index 6199694..1cd0aed 100644 --- a/common/nix-settings.nix +++ b/common/nix-settings.nix @@ -18,6 +18,22 @@ in }; nixPath = lib.mapAttrsToList (key: value: "${key}=${value.to.path}") config.nix.registry; }; + sops = { + secrets."nix/access-tokens" = { + owner = "root"; + group = "users"; + mode = "0440"; + sopsFile = ./secrets.yaml; + }; + templates.nix-secrets = { + content = '' + access-tokens = ${config.sops.placeholder."nix/access-tokens"} + ''; + owner = "root"; + group = "users"; + mode = "0440"; + }; + }; nix.settings = builtins.mapAttrs (_: lib.mkDefault) { # keep around all inputs necessary for offline-rebuilding the system keep-outputs = true; @@ -35,6 +51,6 @@ in # TODO: manage access token with sops instead of manual deployment # permissions: needs to be readable by the user invoking nix and root (for nix daemon) nix.extraOptions = '' - !include /etc/nix/secrets.conf + !include ${config.sops.templates.nix-secrets.path} ''; } diff --git a/common/secrets.yaml b/common/secrets.yaml new file mode 100644 index 0000000..6a9fc8c --- /dev/null +++ b/common/secrets.yaml @@ -0,0 +1,26 @@ +nix: + access-tokens: ENC[AES256_GCM,data:0e58ZzTN81E/2BWphnGKRp8wM8CBOyC5JG2frU6pQ2a10DOwJBJiuv91H3IfHNq+YadNswQZhouQTczhIXlEIW3uADELSBhEiC/L8z9+zrgc4KyRLsMskipuCC3H,iv:DKnJmMs88QA4L9ozvYku4QGottrZVG3UFbw90XNzF0c=,tag:RoKuFIv/tJ/+ZF5aNzkpIQ==,type:str] +sops: + age: + - recipient: age1q80zzsgglj438verw74jghezn8ndpqldvg0mfxzwtaq4v5h7apusqysavz + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4VmtBVGRNNTRuekxad24v + TmhpVm5BV2wwMkJVclNYd0RkcldtdHhQZlQ4CkVXeDRicStxdk9NdWZoWXRjUWdE + Q2ZibEpVMzR5MFMyalZqVklEajJtejQKLS0tIHhYczc2eFhuVVlQNGE1eTBuUURz + MEI3c2xoSmFneDNiMU40L2QwWC8zWGcKKpI1peaS0IVWxD/q52zDTbIBMkvsGSCy + 3PbuFXZ0ksPpC3nVwTYI4g79X54dECLHQ5bIf4mefREX6wlP+EzdtQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1kx93vp8l8jd6kz0kvk379udr5z8a9t6946w0ff5t9a2esn47nqzqlfzvwe + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bmtiREFLNmdmdVNOOXNm + YW5XbWJaMHJYMExMZlNEMHJjSlRXUWJ1bmhFCmNBT25odmtGS3oxRFB1U1V6MXo0 + WWVHRk5oTi9DZ0t1c21WcnpSNjd2SmsKLS0tIGphQlFoSWFMVXJObmRLejR0QU54 + S2orZUZqT1g4eGhEMXJQUHp0UDdhSTgK7w+ht6QrXN8fqgIgU/JCkrZW42JhfRp9 + WSnwD5pLJduGVbxVlTRw2+EXFEglDp1WL11UTRj3K9Q3sCH3tH+p2Q== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-04-05T22:12:29Z" + mac: ENC[AES256_GCM,data:5do9aK676jnIpaOldsL72W68BLKlWISBeeVglRCVtvYq/gmcmLAIESJli6XIRAURJmX7O61VnBDr5uGmH3jV0cb7s8zd6mxnWJOsnPIiKMNFiDg57W72R4iNsdeYINu6Y9HFfkXcI6HkP2eHdpzsVmmDvT7WuGS0Q6HgpbAbygM=,iv:DPdmA8LuSTNNsV0OTShi2pifhxpbITRbZAKYszDrFIU=,tag:fsOFaubD+LWG1pja6ttYYg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/common/sops.nix b/common/sops.nix new file mode 100644 index 0000000..68e5d5b --- /dev/null +++ b/common/sops.nix @@ -0,0 +1,11 @@ +{ lib, config, ... }: +let + inputs = config.inputInjection.flake-inputs; +in +{ + sops = { + age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = lib.mkDefault toString (./. + "/hosts/${config.networking.hostname}/secrets.ini"); + defaultSopsFormat = "yaml"; # is the default. ini had some template rendering issues in practice + }; +} diff --git a/darwin/configuration.nix b/darwin/configuration.nix index 3ee831b..8d08b1a 100644 --- a/darwin/configuration.nix +++ b/darwin/configuration.nix @@ -8,6 +8,7 @@ in imports = [ ../common/nix-settings.nix ../common/angrr.nix + ./sops.nix ]; nix = { enable = true; diff --git a/darwin/sops.nix b/darwin/sops.nix new file mode 100644 index 0000000..a819347 --- /dev/null +++ b/darwin/sops.nix @@ -0,0 +1,13 @@ +{ + lib, + config, + pkgs, + ... +}: +{ + sops = { + age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = lib.mkDefault ./secrets.yaml; + defaultSopsFormat = "yaml"; # is the default. ini had some template rendering issues in practice + }; +} diff --git a/flake.nix b/flake.nix index 38080bb..5ad6638 100644 --- a/flake.nix +++ b/flake.nix @@ -86,11 +86,11 @@ }; defaultModules = system: [ inputInjection - sops-nix.nixosModules.sops # for some reason, `imports`-ing the home-manager module via inputInjection # from a sub-module causes infinite recursion, so importing it here instead home-manager.nixosModules.home-manager + inputs.sops-nix.nixosModules.sops ]; mkSystem = system: extraModules: @@ -105,9 +105,9 @@ modules = [ { imports = [ - sops-nix.homeManagerModules.sops ./home/common.nix ./home/${confName}.nix + inputs.sops-nix.homeManagerModules.sops ]; # extends the home config home.username = user; @@ -148,7 +148,7 @@ ./darwin/configuration.nix inputInjection inputs.angrr.darwinModules.angrr - + inputs.sops-nix.darwinModules.sops ]; }; homeConfigurations = { diff --git a/home/common.nix b/home/common.nix index d53b3ec..bf19896 100644 --- a/home/common.nix +++ b/home/common.nix @@ -13,6 +13,7 @@ ./modules/captive-browser.nix ./modules/ensureDirs.nix ./modules/ssh.nix + ./modules/sops.nix ]; home.homeDirectory = if pkgs.stdenv.isDarwin then "/Users/${config.home.username}" else "/home/${config.home.username}"; diff --git a/home/modules/sops.nix b/home/modules/sops.nix new file mode 100644 index 0000000..0e18ffe --- /dev/null +++ b/home/modules/sops.nix @@ -0,0 +1,7 @@ +{ inputs, ... }: +{ + sops = { + age.keyFile = "/home/user/.age-key.txt"; # must have no password! + # deliberately not setting `defaultSopsFile` because there is no clear file-hostname-mapping. Each separate home config has to configure this explicitly. + }; +}