diff --git a/flake.lock b/flake.lock index e12bc8e..884db1b 100644 --- a/flake.lock +++ b/flake.lock @@ -121,11 +121,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1773374581, - "narHash": "sha256-cqbRdYEmO8FNoaUtoc6+GLR4EGU1f24cGJiQUPJJmxI=", + "lastModified": 1773720169, + "narHash": "sha256-rDYvCjc50uxasQjU07Y8vHudR28LtRQbfrvRqZRyiN4=", "owner": "rycee", "repo": "nur-expressions", - "rev": "c73146d00a2a01e2ac844ceed9640e0f314a5dda", + "rev": "7f4fdba8e1b5177ef1508e2d32843c68c4aebf5c", "type": "gitlab" }, "original": { @@ -344,11 +344,11 @@ ] }, "locked": { - "lastModified": 1773422513, - "narHash": "sha256-MPjR48roW7CUMU6lu0+qQGqj92Kuh3paIulMWFZy+NQ=", + "lastModified": 1773681856, + "narHash": "sha256-+bRqxoFCJFO9ZTFhcCkzNXbDT3b8AEk88fyjB7Is6eo=", "owner": "nix-community", "repo": "home-manager", - "rev": "ef12a9a2b0f77c8fa3dda1e7e494fca668909056", + "rev": "57d5560ee92a424fb71fde800acd6ed2c725dfce", "type": "github" }, "original": { @@ -400,10 +400,10 @@ "nix-secrets": { "flake": false, "locked": { - "lastModified": 1773429715, - "narHash": "sha256-fw57QRzSlX23V3qYejECwrYkxSca7TY4WRCY4OF79t4=", + "lastModified": 1773505989, + "narHash": "sha256-zmKDguP5ReYfb2LK3gICP0xVZXnkV7Zt+iq6dFGqLPo=", "ref": "main", - "rev": "58f5109e5195b3015e01356574f67abd719f3039", + "rev": "e7472aa92a8bce003fccb310191c45948165a8c3", "shallow": true, "type": "git", "url": "ssh://git@github.com/hektor/nix-secrets" @@ -453,11 +453,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1772972630, - "narHash": "sha256-mUJxsNOrBMNOUJzN0pfdVJ1r2pxeqm9gI/yIKXzVVbk=", + "lastModified": 1773533765, + "narHash": "sha256-qonGfS2lzCgCl59Zl63jF6dIRRpvW3AJooBGMaXjHiY=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "3966ce987e1a9a164205ac8259a5fe8a64528f72", + "rev": "f8e82243fd601afb9f59ad230958bd073795cbfe", "type": "github" }, "original": { @@ -469,11 +469,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1773282481, - "narHash": "sha256-b/GV2ysM8mKHhinse2wz+uP37epUrSE+sAKXy/xvBY4=", + "lastModified": 1773646010, + "narHash": "sha256-iYrs97hS7p5u4lQzuNWzuALGIOdkPXvjz7bviiBjUu8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "fe416aaedd397cacb33a610b33d60ff2b431b127", + "rev": "5b2c2d84341b2afb5647081c1386a80d7a8d8605", "type": "github" }, "original": { @@ -667,11 +667,11 @@ ] }, "locked": { - "lastModified": 1773096132, - "narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=", + "lastModified": 1773698643, + "narHash": "sha256-VCiDjE8kNs8uCAK73Ezk1r3fFuc4JepvW07YFqaN968=", "owner": "Mic92", "repo": "sops-nix", - "rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784", + "rev": "8237de83e8200d16fe0c4467b02a1c608ff28044", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 3a0ad76..ce985d7 100644 --- a/flake.nix +++ b/flake.nix @@ -60,8 +60,8 @@ let inherit (self) outputs; inherit (inputs.nixpkgs) lib; - utils = import ./utils { inherit lib; }; - hostDirNames = utils.dirNames ./hosts; + myUtils = import ./utils { inherit lib; }; + hostDirNames = myUtils.dirNames ./hosts; system = "x86_64-linux"; dotsPath = ./dots; gitHooks = import ./git-hooks.nix { @@ -82,7 +82,12 @@ { nixpkgs.hostPlatform = import ./hosts/${host}/system.nix; } ]; specialArgs = { - inherit inputs outputs dotsPath; + inherit + inputs + outputs + dotsPath + myUtils + ; }; } )) @@ -97,7 +102,12 @@ } ]; specialArgs = { - inherit inputs outputs dotsPath; + inherit + inputs + outputs + dotsPath + myUtils + ; }; }; sd-image-raspberry-pi-aarch64 = nixpkgs.lib.nixosSystem { @@ -110,7 +120,12 @@ } ]; specialArgs = { - inherit inputs outputs dotsPath; + inherit + inputs + outputs + dotsPath + myUtils + ; }; }; }; @@ -123,7 +138,12 @@ }; modules = [ ./home/hosts/work ]; extraSpecialArgs = { - inherit inputs outputs dotsPath; + inherit + inputs + outputs + dotsPath + myUtils + ; }; }; }; diff --git a/home/hosts/work/default.nix b/home/hosts/work/default.nix index 4bd0536..edcd8e4 100644 --- a/home/hosts/work/default.nix +++ b/home/hosts/work/default.nix @@ -41,41 +41,7 @@ in ../../modules/vscode ]; - sops = { - age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; - defaultSopsFile = "${inputs.nix-secrets}/secrets.yaml"; - - secrets = { - taskwarrior_sync_server_url = { }; - taskwarrior_sync_server_client_id = { }; - taskwarrior_sync_encryption_secret = { }; - anki_sync_user = { }; - anki_sync_key = { }; - opencode_api_key = { }; - }; - - templates = { - "taskrc.d/sync" = { - content = '' - sync.server.url=${config.sops.placeholder.taskwarrior_sync_server_url} - sync.server.client_id=${config.sops.placeholder.taskwarrior_sync_server_client_id} - sync.encryption_secret=${config.sops.placeholder.taskwarrior_sync_encryption_secret} - ''; - }; - - "opencode/auth.json" = { - path = "${config.home.homeDirectory}/.local/share/opencode/auth.json"; - content = '' - { - "zai-coding-plan": { - "type": "api", - "key": "${config.sops.placeholder.opencode_api_key}" - } - } - ''; - }; - }; - }; + sops.age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; nixpkgs.config.allowUnfree = true; diff --git a/home/modules/anki/default.nix b/home/modules/anki/default.nix index 70ec96c..337679f 100644 --- a/home/modules/anki/default.nix +++ b/home/modules/anki/default.nix @@ -2,20 +2,17 @@ config, lib, pkgs, + myUtils, osConfig ? null, ... }: let - hmSopsAvailable = config ? sops && config.sops ? secrets; - osSopsAvailable = osConfig != null && osConfig ? sops && osConfig.sops ? secrets; - sopsAvailable = hmSopsAvailable || osSopsAvailable; - - sopsSecrets = if hmSopsAvailable then config.sops.secrets else osConfig.sops.secrets; + sops = myUtils.sopsAvailability config osConfig; in { warnings = lib.optional ( - !sopsAvailable && config.programs.anki.enable + !sops.available && config.programs.anki.enable ) "anki is enabled but sops secrets are not available. anki sync will not be configured."; programs.anki = { @@ -26,9 +23,9 @@ in puppy-reinforcement review-heatmap ]; - profiles."User 1".sync = lib.mkIf sopsAvailable { - usernameFile = "${sopsSecrets."anki_sync_user".path}"; - keyFile = "${sopsSecrets."anki_sync_key".path}"; + profiles."User 1".sync = lib.mkIf sops.available { + usernameFile = "${sops.secrets."anki-sync-user".path}"; + keyFile = "${sops.secrets."anki-sync-key".path}"; }; }; } diff --git a/home/modules/cloud/hetzner.nix b/home/modules/cloud/hetzner.nix index 9c3d5df..b6a64d3 100644 --- a/home/modules/cloud/hetzner.nix +++ b/home/modules/cloud/hetzner.nix @@ -14,8 +14,7 @@ in warnings = lib.optional (!isNixOS) "hcloud module requires NixOS host configuration. This module will not work with standalone home-manager."; - home = { - packages = with pkgs; [ hcloud ]; - }; + + home.packages = with pkgs; [ hcloud ]; }; } diff --git a/home/modules/taskwarrior/default.nix b/home/modules/taskwarrior/default.nix index c202bbf..0ec05d6 100644 --- a/home/modules/taskwarrior/default.nix +++ b/home/modules/taskwarrior/default.nix @@ -3,20 +3,17 @@ lib, pkgs, dotsPath, + myUtils, osConfig ? null, ... }: let - hmSopsAvailable = config ? sops && config.sops ? templates; - osSopsAvailable = osConfig != null && osConfig ? sops && osConfig.sops ? templates; - sopsAvailable = hmSopsAvailable || osSopsAvailable; - - sopsTemplates = if hmSopsAvailable then config.sops.templates else osConfig.sops.templates; + sops = myUtils.sopsAvailability config osConfig; in { warnings = - lib.optional (!sopsAvailable && config.programs.taskwarrior.enable) + lib.optional (!sops.available && config.programs.taskwarrior.enable) "taskwarrior is enabled, but sops templates are not available. taskwarrior sync will not be configured."; home.packages = with pkgs; [ @@ -27,7 +24,7 @@ in home.file = { ".config/task/taskrc" = { - force = true; # overwrite when present + force = true; source = dotsPath + "/.config/task/taskrc"; }; ".config/task/taskrc.d/aliases".source = dotsPath + "/.config/task/taskrc.d/aliases"; @@ -60,8 +57,8 @@ in config = { recurrence = "off"; }; - extraConfig = lib.optionalString sopsAvailable '' - include ${sopsTemplates."taskrc.d/sync".path} + extraConfig = lib.optionalString sops.available '' + include ${sops.templates."taskrc.d/sync".path} ''; }; } diff --git a/hosts/andromache/default.nix b/hosts/andromache/default.nix index ac3931b..b9c7bac 100644 --- a/hosts/andromache/default.nix +++ b/hosts/andromache/default.nix @@ -17,7 +17,6 @@ in inputs.nixos-hardware.nixosModules.common-cpu-intel inputs.nixos-hardware.nixosModules.common-pc inputs.nixos-hardware.nixosModules.common-pc-ssd - inputs.sops-nix.nixosModules.sops ../../modules/common ../../modules/boot/bootloader.nix (import ../../modules/disko/zfs-encrypted-root.nix { @@ -44,6 +43,7 @@ in ../../modules/users ../../modules/wol ../../modules/yubikey + ../../modules/hcloud ]; home-manager.users.${config.host.username} = import ../../home/hosts/andromache { @@ -58,10 +58,15 @@ in ssh.username = config.host.username; ssh.authorizedHosts = [ "astyanax" ]; - secrets.username = config.host.username; + secrets = { + inherit (config.host) username; + nixSigningKey.enable = true; + }; docker.user = config.host.username; - - nix.settings.secret-key-files = [ config.sops.secrets.nix_signing_key_andromache.path ]; + hcloud = { + enable = true; + inherit (config.host) username; + }; disko.devices = { disk.data = { diff --git a/hosts/astyanax/default.nix b/hosts/astyanax/default.nix index 53e3f12..26f48ae 100644 --- a/hosts/astyanax/default.nix +++ b/hosts/astyanax/default.nix @@ -16,7 +16,6 @@ in inputs.nixos-hardware.nixosModules.common-pc inputs.nixos-hardware.nixosModules.common-pc-ssd # inputs.nixos-hardware.nixosModules.lenovo-thinkpad-e14-intel-gen7 (not available yet?) - inputs.sops-nix.nixosModules.sops ../../modules/common ../../modules/boot/bootloader.nix (import ../../modules/disko/zfs-encrypted-root.nix { @@ -53,14 +52,15 @@ in ssh.username = config.host.username; ssh.authorizedHosts = [ "andromache" ]; - secrets.username = config.host.username; + secrets = { + inherit (config.host) username; + nixSigningKey.enable = true; + }; docker.user = config.host.username; nfc.user = config.host.username; desktop.ly.enable = true; audio.automation.enable = true; - nix.settings.secret-key-files = [ config.sops.secrets.nix_signing_key_astyanax.path ]; - hardware = { cpu.intel.updateMicrocode = true; # https://wiki.nixos.org/wiki/Intel_Graphics diff --git a/hosts/vm/default.nix b/hosts/vm/default.nix index e876cf3..69f9ede 100644 --- a/hosts/vm/default.nix +++ b/hosts/vm/default.nix @@ -10,7 +10,6 @@ inputs.disko.nixosModules.disko ./hard.nix ./host.nix - inputs.sops-nix.nixosModules.sops ./disk.nix ../../modules/common ../../modules/boot/bootloader.nix diff --git a/modules/backups/default.nix b/modules/backups/default.nix index 2ef35f4..8e934ba 100644 --- a/modules/backups/default.nix +++ b/modules/backups/default.nix @@ -6,18 +6,19 @@ let cfg = config.restic-backup; + inherit (config.secrets) sopsDir; in { options = { restic-backup = { repository = lib.mkOption { type = lib.types.str; - default = "b2:${config.sops.placeholder."b2_bucket_name"}:${config.networking.hostName}"; + default = "b2:${config.sops.placeholder.b2-bucket-name}:${config.networking.hostName}"; }; passwordFile = lib.mkOption { type = lib.types.str; - default = config.sops.secrets."restic_password".path; + default = config.sops.secrets.restic-password.path; }; paths = lib.mkOption { @@ -29,17 +30,30 @@ in config = { sops = { - secrets.b2_bucket_name = { }; - - templates."restic/repo-${config.networking.hostName}" = { - content = "b2:${config.sops.placeholder."b2_bucket_name"}:${config.networking.hostName}"; + secrets = { + restic-password = { + sopsFile = "${sopsDir}/restic-password"; + }; + b2-bucket-name = { + sopsFile = "${sopsDir}/b2-bucket-name"; + }; + b2-account-id = { + sopsFile = "${sopsDir}/b2-account-id"; + }; + b2-account-key = { + sopsFile = "${sopsDir}/b2-account-key"; + }; }; - - templates."restic/b2-env-${config.networking.hostName}" = { - content = '' - B2_ACCOUNT_ID=${config.sops.placeholder."b2_account_id"} - B2_ACCOUNT_KEY=${config.sops.placeholder."b2_account_key"} - ''; + templates = { + "restic/repo-${config.networking.hostName}" = { + content = "b2:${config.sops.placeholder.b2-bucket-name}:${config.networking.hostName}"; + }; + "restic/b2-env-${config.networking.hostName}" = { + content = '' + B2_ACCOUNT_ID=${config.sops.placeholder.b2-account-id} + B2_ACCOUNT_KEY=${config.sops.placeholder.b2-account-key} + ''; + }; }; }; diff --git a/modules/common/default.nix b/modules/common/default.nix index 20a0444..e70647d 100644 --- a/modules/common/default.nix +++ b/modules/common/default.nix @@ -2,6 +2,7 @@ inputs, outputs, dotsPath, + myUtils, config, ... }: @@ -61,7 +62,12 @@ in useGlobalPkgs = true; useUserPackages = true; extraSpecialArgs = { - inherit inputs outputs dotsPath; + inherit + inputs + outputs + dotsPath + myUtils + ; }; }; }; diff --git a/modules/hcloud/default.nix b/modules/hcloud/default.nix new file mode 100644 index 0000000..7a7df65 --- /dev/null +++ b/modules/hcloud/default.nix @@ -0,0 +1,38 @@ +{ + lib, + config, + ... +}: + +let + cfg = config.hcloud; + inherit (config.secrets) sopsDir; +in +{ + options.hcloud = { + enable = lib.mkEnableOption "hcloud CLI configuration"; + username = lib.mkOption { + type = lib.types.str; + description = "Username for hcloud CLI configuration"; + }; + }; + + config = lib.mkIf cfg.enable { + sops.secrets.hcloud-token = { + sopsFile = "${sopsDir}/hcloud-token"; + owner = config.users.users.${cfg.username}.name; + }; + + sops.templates."hcloud/cli.toml" = { + owner = config.users.users.${cfg.username}.name; + path = "/home/${cfg.username}/.config/hcloud/cli.toml"; + content = '' + active_context = "server" + + [[contexts]] + name = "server" + token = "${config.sops.placeholder.hcloud-token}" + ''; + }; + }; +} diff --git a/modules/secrets/default.nix b/modules/secrets/default.nix index 02ff5df..1ef1897 100644 --- a/modules/secrets/default.nix +++ b/modules/secrets/default.nix @@ -7,102 +7,100 @@ let cfg = config.secrets; -in -{ - options = { - secrets.username = lib.mkOption { - type = lib.types.str; + inherit (cfg) sopsDir; + owner = config.users.users.${cfg.username}.name; + + mkSecret = name: { + ${name} = { + sopsFile = "${sopsDir}/${name}"; + inherit owner; }; }; +in +{ + imports = [ inputs.sops-nix.nixosModules.sops ]; + + options = { + secrets = { + username = lib.mkOption { + type = lib.types.str; + }; + + sopsDir = lib.mkOption { + type = lib.types.str; + default = "${toString inputs.nix-secrets}/secrets"; + }; + + nixSigningKey = { + enable = lib.mkEnableOption "nix signing key configuration"; + name = lib.mkOption { + type = lib.types.str; + default = "${config.host.name}-nix-signing-key"; + }; + }; + }; + }; + config = { sops = { - defaultSopsFile = "${builtins.toString inputs.nix-secrets}/secrets.yaml"; - defaultSopsFormat = "yaml"; age.keyFile = "/home/${cfg.username}/.config/sops/age/keys.txt"; - secrets = { - "taskwarrior_sync_server_url".owner = config.users.users.${cfg.username}.name; - "taskwarrior_sync_server_client_id".owner = config.users.users.${cfg.username}.name; - "taskwarrior_sync_encryption_secret".owner = config.users.users.${cfg.username}.name; - "email_personal".owner = config.users.users.${cfg.username}.name; - "email_work".owner = config.users.users.${cfg.username}.name; - "anki_sync_user".owner = config.users.users.${cfg.username}.name; - "anki_sync_key".owner = config.users.users.${cfg.username}.name; - "hcloud".owner = config.users.users.${cfg.username}.name; - "nix_signing_key_astyanax" = { }; - "nix_signing_key_andromache" = { }; - "opencode_api_key".owner = config.users.users.${cfg.username}.name; - # TODO: using shared secrets for now, but would be better to to per-host secrets - # To add per-host secrets: - # "restic_password_${config.networking.hostName}" = { }; - # "restic_b2_account_id_${config.networking.hostName}" = { }; - # "restic_b2_account_key_${config.networking.hostName}" = { }; - "restic_password" = { }; - "b2_bucket_name" = { }; - "b2_account_id" = { }; - "b2_account_key" = { }; - }; + secrets = lib.mkMerge [ + (mkSecret "taskwarrior-sync-server-url") + (mkSecret "taskwarrior-sync-server-client-id") + (mkSecret "taskwarrior-sync-encryption-secret") + (mkSecret "anki-sync-user") + (mkSecret "anki-sync-key") + (mkSecret "email-personal") + (mkSecret "email-work") + (mkSecret "opencode-api-key") + (lib.mkIf cfg.nixSigningKey.enable (mkSecret cfg.nixSigningKey.name)) + ]; templates = { "taskrc.d/sync" = { - owner = config.users.users.${cfg.username}.name; + inherit owner; content = '' - sync.server.url=${config.sops.placeholder."taskwarrior_sync_server_url"} - sync.server.client_id=${config.sops.placeholder."taskwarrior_sync_server_client_id"} - sync.encryption_secret=${config.sops.placeholder."taskwarrior_sync_encryption_secret"} + sync.server.url=${config.sops.placeholder.taskwarrior-sync-server-url} + sync.server.client_id=${config.sops.placeholder.taskwarrior-sync-server-client-id} + sync.encryption_secret=${config.sops.placeholder.taskwarrior-sync-encryption-secret} ''; }; ".gitconfig.email" = { - owner = config.users.users.${cfg.username}.name; + inherit owner; path = "/home/${cfg.username}/.gitconfig.email"; content = '' [user] - email = ${config.sops.placeholder."email_personal"} + email = ${config.sops.placeholder.email-personal} ''; }; - ".gitconfig.work.email" = { - owner = config.users.users.${cfg.username}.name; + inherit owner; path = "/home/${cfg.username}/.gitconfig.work.email"; content = '' [user] - email = ${config.sops.placeholder."email_work"} - ''; - }; - - "hcloud/cli.toml" = { - owner = config.users.users.${cfg.username}.name; - path = "/home/${cfg.username}/.config/hcloud/cli.toml"; - content = '' - active_context = "server" - - [[contexts]] - name = "server" - token = "${config.sops.placeholder."hcloud"}" + email = ${config.sops.placeholder.email-work} ''; }; "opencode/auth.json" = { - owner = config.users.users.${cfg.username}.name; + inherit owner; path = "/home/${cfg.username}/.local/share/opencode/auth.json"; content = '' { "zai-coding-plan": { "type": "api", - "key": "${config.sops.placeholder."opencode_api_key"}" + "key": "${config.sops.placeholder.opencode-api-key}" } } ''; }; - - "restic/b2-env" = { - content = '' - B2_ACCOUNT_ID=${config.sops.placeholder."b2_account_id"} - B2_ACCOUNT_KEY=${config.sops.placeholder."b2_account_key"} - ''; - }; }; }; + + nix.settings.secret-key-files = lib.mkIf cfg.nixSigningKey.enable [ + config.sops.secrets.${cfg.nixSigningKey.name}.path + ]; }; } diff --git a/utils/default.nix b/utils/default.nix index 911b33d..a8a091d 100644 --- a/utils/default.nix +++ b/utils/default.nix @@ -10,4 +10,16 @@ import (hostDir + "/meta.nix") else throw "meta.nix required in ${hostDir}"; + + sopsAvailability = + config: osConfig: + let + hmSopsAvailable = config ? sops && config.sops ? secrets; + osSopsAvailable = osConfig != null && osConfig ? sops && osConfig.sops ? secrets; + in + { + available = hmSopsAvailable || osSopsAvailable; + secrets = if hmSopsAvailable then config.sops.secrets else osConfig.sops.secrets; + templates = if hmSopsAvailable then config.sops.templates else osConfig.sops.templates; + }; }