{ config, lib, ... }: let inherit (builtins) attrNames baseNameOf head match pathExists readFile ; inherit (lib) filter foldl genAttrs hasPrefix mapAttrsToList mkOption optionalAttrs unique ; inherit (lib.types) attrsOf listOf nullOr path ; allusers = config.users.users; cfg = config.nixsap.deployment; # XXX If the file is encrypted: # error: the contents of the file ‘...’ cannot be represented as a Nix string read = key: let m = match "^(.+)@[^@]+$" key; s = if m != null then head m else key; in if cfg.secrets != null then readFile (cfg.secrets + "/${s}") else ""; in { options.nixsap.deployment = { secrets = mkOption { description = '' Directory with the secrets on the deploy machine. If not specified, each key will be an empty file. ''; type = nullOr path; default = null; example = ""; }; keyStore = mkOption { description = '' Directory with the keys on the target machine. NixOps uses /run/keys, and this is default. If you use another deployment tool, you would like to set it to something else. ''; type = path; default = "/run/keys"; example = "/root/keys"; }; keyrings = mkOption { type = attrsOf (listOf (nullOr path)); description = '' Binds keys to a user. It's possible to share the same key between multiple users, of course by different names: "/run/keys/foo" and "/run/keys/foo@bar" will use the same secret file "foo". Any file whose path does not start with `nixsap.deployment.keyStore` is deliberately ignored. E. i. you can pass any file names, and nixsap will pick up keys for you. For convenience, it is allowed to pass null values, which are filtered-out as well. ''; default = {}; example = { mysqlbackup = [ "/run/keys/s3cmd.cfg" ]; pgbackup = [ "/run/keys/s3cmd.cfg@pgbackup" ]; }; }; }; config = { users.users = genAttrs (attrNames cfg.keyrings) ( name: optionalAttrs (name != "root") { extraGroups = [ "keys" ]; } ); deployment.keys = foldl (a: b: a//b) {} ( mapAttrsToList (name: keys: let realkeys = unique (filter (n: n != null && hasPrefix cfg.keyStore n) keys); in genAttrs (map baseNameOf realkeys) (key: { text = read key; user = toString allusers.${name}.uid; }) ) cfg.keyrings ); }; }