From b21c0ce3a82dd9c6663e1668710b78a726b1b5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janne=20He=C3=9F?= Date: Fri, 27 Aug 2021 13:35:53 +0200 Subject: [PATCH] Group gnupg and age in the module --- README.md | 4 +- modules/sops/default.nix | 101 +++++++++++++---------- pkgs/sops-install-secrets/nixos-test.nix | 4 +- 3 files changed, 60 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index e6175ef..e3091bd 100644 --- a/README.md +++ b/README.md @@ -678,9 +678,9 @@ If you uploaded it to `/var/lib/sops` than your sops configuration will look lik ```nix { # Make sure that `/var/lib/sops` is owned by root and is not world-readable/writable - sops.gnupgHome = "/var/lib/sops"; + sops.gnupg.home = "/var/lib/sops"; # disable import host ssh keys - sops.sshKeyPaths = []; + sops.gnupg.sshKeyPaths = []; } ``` diff --git a/modules/sops/default.nix b/modules/sops/default.nix index be2f835..650fc92 100644 --- a/modules/sops/default.nix +++ b/modules/sops/default.nix @@ -85,7 +85,9 @@ let # Does this need to be configurable? secretsMountPoint = "/run/secrets.d"; symlinkPath = "/run/secrets"; - inherit (cfg) gnupgHome sshKeyPaths ageKeyFile; + gnupgHome = cfg.gnupg.home; + sshKeyPaths = cfg.gnupg.sshKeyPaths; + ageKeyFile = cfg.age.keyFile; }); checkedManifest = let @@ -130,52 +132,61 @@ in { ''; }; - ageKeyFile = mkOption { - type = types.nullOr types.path; - default = null; - example = "/var/lib/sops-nix/key.txt"; - description = '' - Path to age key file used for sops decryption. - ''; + age = { + keyFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/lib/sops-nix/key.txt"; + description = '' + Path to age key file used for sops decryption. + Setting this to a non-null value causes age to be used instead of gnupg. + ''; + }; + + generateKey = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not to generate the age key. If this + option is set to false, the key must already be + present at the specified location. + ''; + }; }; - generateAgeKey = mkOption { - type = types.bool; - default = false; - description = '' - Whether or not to generate the age key. If this - option is set to false, the key must already be - present at the specified location. - ''; - }; + gnupg = { + home = mkOption { + type = types.nullOr types.str; + default = null; + example = "/root/.gnupg"; + description = '' + Path to gnupg database directory containing the key for decrypting the sops file. + ''; + }; - gnupgHome = mkOption { - type = types.nullOr types.str; - default = null; - example = "/root/.gnupg"; - description = '' - Path to gnupg database directory containing the key for decrypting sops file. - ''; - }; - - sshKeyPaths = mkOption { - type = types.listOf types.path; - default = if config.services.openssh.enable then - map (e: e.path) (lib.filter (e: e.type == "rsa") config.services.openssh.hostKeys) - else []; - description = '' - Path to ssh keys added as GPG keys during sops description. - This option must be explicitly unset if config.sops.sshKeyPaths. - ''; + sshKeyPaths = mkOption { + type = types.listOf types.path; + default = if config.services.openssh.enable then + map (e: e.path) (lib.filter (e: e.type == "rsa") config.services.openssh.hostKeys) + else []; + description = '' + Path to ssh keys added as GPG keys during sops description. + This option must be explicitly unset if config.sops.gnupg.sshKeyPaths is set. + ''; + }; }; }; + imports = [ + (mkRenamedOptionModule [ "sops" "gnupgHome" ] [ "sops" "gnupg" "home" ]) + (mkRenamedOptionModule [ "sops" "sshKeyPaths" ] [ "sops" "gnupg" "sshKeyPaths" ]) + ]; config = mkIf (cfg.secrets != {}) { assertions = [{ - assertion = cfg.ageKeyFile == null -> (cfg.gnupgHome == null) != (cfg.sshKeyPaths == []); - message = "Exactly one of sops.gnupgHome and sops.sshKeyPaths must be set"; + assertion = cfg.age.keyFile == null -> (cfg.gnupg.home == null) != (cfg.gnupg.sshKeyPaths == []); + message = "Exactly one of sops.gnupg.home and sops.gnupg.sshKeyPaths must be set for gnupg mode"; } { - assertion = (cfg.sshKeyPaths != [] || cfg.gnupgHome != null) != (cfg.ageKeyFile != null); - message = "sops.ageKeyFile is mutually exclusive with sops.gnupgHome and sops.sshKeyPaths"; + assertion = cfg.age.keyFile != null -> (cfg.age.sshKeyPaths != []) != (cfg.age.keyFile != null); + message = "sops.age.keyFile is mutually exclusive with sops.age.sshKeyPaths"; }] ++ optionals cfg.validateSopsFiles ( concatLists (mapAttrsToList (name: secret: [{ assertion = builtins.pathExists secret.sopsFile; @@ -190,17 +201,17 @@ in { system.activationScripts.setup-secrets = let sops-install-secrets = (pkgs.callPackage ../.. {}).sops-install-secrets; - in stringAfter ([ "specialfs" "users" "groups" ] ++ optional cfg.generateAgeKey "generate-age-key") '' + in stringAfter ([ "specialfs" "users" "groups" ] ++ optional cfg.age.generateKey "generate-age-key") '' echo setting up secrets... - ${optionalString (cfg.gnupgHome != null) "SOPS_GPG_EXEC=${pkgs.gnupg}/bin/gpg"} ${sops-install-secrets}/bin/sops-install-secrets ${checkedManifest} + ${optionalString (cfg.gnupg.home != null) "SOPS_GPG_EXEC=${pkgs.gnupg}/bin/gpg"} ${sops-install-secrets}/bin/sops-install-secrets ${checkedManifest} ''; - system.activationScripts.generate-age-key = (mkIf cfg.generateAgeKey) (stringAfter [] '' - if [[ ! -f "${cfg.ageKeyFile}" ]]; then; + system.activationScripts.generate-age-key = (mkIf cfg.age.generateKey) (stringAfter [] '' + if [[ ! -f "${cfg.age.keyFile}" ]]; then; echo generating machine-specific age key... - mkdir -p $(dirname ${cfg.ageKeyFile}) + mkdir -p $(dirname ${cfg.age.keyFile}) # age-keygen sets 0600 by default, no need to chmod. - ${pkgs.age}/bin/age-keygen -o ${cfg.ageKeyFile} + ${pkgs.age}/bin/age-keygen -o ${cfg.age.keyFile} fi ''); }; diff --git a/pkgs/sops-install-secrets/nixos-test.nix b/pkgs/sops-install-secrets/nixos-test.nix index a12539a..147e9cd 100644 --- a/pkgs/sops-install-secrets/nixos-test.nix +++ b/pkgs/sops-install-secrets/nixos-test.nix @@ -28,7 +28,7 @@ machine = { imports = [ ../../modules/sops ]; sops = { - ageKeyFile = ./test-assets/age-keys.txt; + age.keyFile = ./test-assets/age-keys.txt; defaultSopsFile = ./test-assets/secrets.yaml; secrets.test_key = {}; }; @@ -55,7 +55,7 @@ group = "nogroup"; }; - sops.gnupgHome = "/run/gpghome"; + sops.gnupg.home = "/run/gpghome"; sops.defaultSopsFile = ./test-assets/secrets.yaml; sops.secrets.test_key.owner = config.users.users.someuser.name; sops.secrets.existing-file = {