From 6fc10bd800032c603469c86625f40170f26fbaa7 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Sat, 18 Feb 2017 20:09:11 +0300 Subject: Added gnupg app --- modules/apps/gnupg/default.nix | 114 ++++++++++++++++++++++++++++++++++++++++ modules/apps/gnupg/instance.nix | 68 ++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 modules/apps/gnupg/default.nix create mode 100644 modules/apps/gnupg/instance.nix (limited to 'modules') diff --git a/modules/apps/gnupg/default.nix b/modules/apps/gnupg/default.nix new file mode 100644 index 0000000..7330b2a --- /dev/null +++ b/modules/apps/gnupg/default.nix @@ -0,0 +1,114 @@ +{ config, lib, pkgs, ... }: + +let + + inherit (lib) + concatMapStringsSep concatStrings filterAttrs foldAttrs mapAttrs' + mapAttrsToList mkOption optionalString ; + + inherit (lib.types) + attrsOf submodule ; + + explicit = filterAttrs (n: v: n != "_module" && v != null); + instances = explicit config.nixsap.apps.gnupg; + + keyrings = + let + ik = mapAttrsToList (_: i: { + "${i.user}" = i.secretKeys ++ mapAttrsToList (_: f: f) i.passphrase; + }) instances; + in foldAttrs (l: r: l ++ r) [] ik; + + + mkService = name: cfg: + let + + pubring = pkgs.runCommand "gnupg-${name}-pubring.kbx" {} '' + ${cfg.package}/bin/gpg2 \ + --homedir . \ + --import \ + ${concatMapStringsSep " " (k: "'${k}'") cfg.publicKeys} + cp pubring.kbx $out + ''; + + start = pkgs.writeBashScriptBin "gnupg-${name}-start" '' + set -euo pipefail + umask 0077 + + cat <<'CONF' > '${cfg.home}/gpg.conf' + batch + no-tty + trust-model always + yes + CONF + + # XXX forking: + ${cfg.package}/bin/gpg-agent \ + --homedir '${cfg.home}' \ + --allow-preset-passphrase \ + --batch \ + --quiet \ + --daemon + + ${optionalString (cfg.publicKeys != []) '' + ln -sf '${pubring}' '${cfg.home}/pubring.kbx' + ''} + + export GNUPGHOME='${cfg.home}' + + ${optionalString (cfg.secretKeys != []) '' + ${cfg.package}/bin/gpg2 --import \ + ${concatMapStringsSep " " (k: "'${k}'") cfg.secretKeys} + ''} + + + ${concatStrings (mapAttrsToList (cacheid: f: '' + head -n 1 '${f}' \ + | ${cfg.package}/libexec/gpg-preset-passphrase \ + --verbose --preset '${cacheid}' + '') cfg.passphrase) + } + + + ''; + + in { + name = "gnupg-${name}"; + value = { + description = "gnupg (${name})"; + wantedBy = [ "multi-user.target" ]; + after = [ "keys.target" "local-fs.target" ]; + preStart = '' + mkdir -p -- '${cfg.home}' + rm -rf -- '${cfg.home}/'* + chmod u=rwX,g=,o= -- '${cfg.home}' + chown '${cfg.user}.${cfg.user}' -- '${cfg.home}' + ''; + + serviceConfig = { + ExecStart = "${start}/bin/gnupg-${name}-start"; + PermissionsStartOnly = true; + Restart = "always"; + Type = "forking"; + User = cfg.user; + }; + }; + }; + +in { + + options = { + nixsap.apps.gnupg = mkOption { + description = "GnuPG instances"; + default = {}; + type = attrsOf (submodule (import ./instance.nix pkgs)); + }; + }; + + config = { + nixsap.deployment.keyrings = keyrings; + systemd.services = mapAttrs' mkService instances; + }; + +} + diff --git a/modules/apps/gnupg/instance.nix b/modules/apps/gnupg/instance.nix new file mode 100644 index 0000000..e421a1e --- /dev/null +++ b/modules/apps/gnupg/instance.nix @@ -0,0 +1,68 @@ +pkgs: +{ lib, name, ... }: + +let + + inherit (lib) + mkOption ; + + inherit (lib.types) + attrsOf listOf package path str ; + +in { + options = { + + user = mkOption { + description = '' + User to run as ang keyring owner. This option is required. + Note that this user is not created automaically. + ''; + type = str; + }; + + home = mkOption { + description = '' + GnuPG home directory where keyrings and gpg-agent socket + will be located. + ''; + type = path; + default = "/gnupg/${name}"; + }; + + package = mkOption { + description = "GnuPG2 package"; + type = package; + default = pkgs.gnupg21; + }; + + publicKeys = mkOption { + description = "Public GPG keys"; + type = listOf path; + default = []; + }; + + secretKeys = mkOption { + description = "Secret GPG keys"; + type = listOf path; + default = []; + }; + + passphrase = mkOption { + description = '' + Secret files with pass-phrase to unlock secret keys. Keys are + identified by cacheid, which is either a 40 character keygrip of + hexadecimal characters identifying the key or an arbitrary string + identifying a passphrase. Refer to the `gpg-preset-passphrase` + documentation, because it is what stays behind this mechanism. + Generally in unattended environments you need to use keygrip. + ''; + type = attrsOf path; + default = {}; + example = { + "ABCD...321" = "/run/keys/foo"; + "myapp:mykey" = "/run/keys/bar"; + }; + }; + }; +} + -- cgit v1.2.3