diff --git a/ci.nix b/ci.nix index 16c866e76..212114538 100644 --- a/ci.nix +++ b/ci.nix @@ -8,6 +8,9 @@ let imports = [ ./krebs ./krebs/2configs + ({ config, ... }: { + krebs.build.host = config.krebs.hosts.test-all-krebs-modules; + }) ]; }]; } diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix index 2772d8d37..f76d3c536 100644 --- a/krebs/3modules/default.nix +++ b/krebs/3modules/default.nix @@ -50,6 +50,7 @@ let ./shadow.nix ./ssl.nix ./sync-containers.nix + ./systemd.nix ./tinc.nix ./tinc_graphs.nix ./upstream diff --git a/krebs/3modules/git.nix b/krebs/3modules/git.nix index 1bfd58e31..c038fd4c6 100644 --- a/krebs/3modules/git.nix +++ b/krebs/3modules/git.nix @@ -36,7 +36,7 @@ let type = types.user; default = { name = "fcgiwrap"; - home = toString pkgs.empty; + home = toString pkgs.emptyDirectory; }; }; }; @@ -111,7 +111,7 @@ let type = types.user; default = { name = "git"; - home = toString pkgs.empty; + home = toString pkgs.emptyDirectory; }; }; }; diff --git a/krebs/3modules/systemd.nix b/krebs/3modules/systemd.nix new file mode 100644 index 000000000..6b0fe9672 --- /dev/null +++ b/krebs/3modules/systemd.nix @@ -0,0 +1,67 @@ +{ config, pkgs, ... }: let { + lib = import ../../lib; + + body.options.krebs.systemd.services = lib.mkOption { + default = {}; + type = lib.types.attrsOf (lib.types.submodule { + options = { + ifCredentialsChange = lib.mkOption { + default = "restart"; + description = '' + Whether to reload or restart the service whenever any its + credentials change. Only credentials with an absolute path in + LoadCredential= are supported. + ''; + type = lib.types.enum [ + "reload" + "restart" + null + ]; + }; + serviceConfig.LoadCredential = lib.mkOption { + apply = lib.toList; + type = + lib.types.either lib.types.str (lib.types.listOf lib.types.str); + }; + }; + }); + }; + + body.config.systemd = + lib.mkMerge + (lib.flatten + (lib.mapAttrsToList (serviceName: cfg: let + paths = + lib.filter + lib.types.absolute-pathname.check + (map + (lib.compose [ lib.maybeHead (lib.match "[^:]*:(.*)") ]) + cfg.serviceConfig.LoadCredential); + in + lib.singleton { + services.${serviceName} = { + serviceConfig = { + LoadCredential = cfg.serviceConfig.LoadCredential; + }; + }; + } + ++ + lib.optionals (cfg.ifCredentialsChange != null) (map (path: let + triggerName = "trigger-${lib.systemd.encodeName path}"; + in { + paths.${triggerName} = { + wantedBy = ["multi-user.target"]; + pathConfig.PathChanged = path; + }; + services.${triggerName} = { + serviceConfig = { + Type = "oneshot"; + ExecStart = lib.singleton (toString [ + "${pkgs.systemd}/bin/systemctl ${cfg.ifCredentialsChange}" + (lib.shell.escape serviceName) + ]); + }; + }; + }) paths) + ) config.krebs.systemd.services)); +} diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix index 3d0cc8fb4..dca764f63 100644 --- a/krebs/3modules/tinc.nix +++ b/krebs/3modules/tinc.nix @@ -1,12 +1,6 @@ with import ; -{ config, pkgs, ... }: -let - out = { - options.krebs.tinc = api; - config = imp; - }; - - api = mkOption { +{ config, pkgs, ... }: { + options.krebs.tinc = mkOption { default = {}; description = '' define a tinc network @@ -28,10 +22,6 @@ let Interface = ${netname} Broadcast = no ${concatMapStrings (c: "ConnectTo = ${c}\n") tinc.config.connectTo} - ${optionalString (tinc.config.privkey_ed25519 != null) - "Ed25519PrivateKeyFile = ${tinc.config.privkey_ed25519.path}" - } - PrivateKeyFile = ${tinc.config.privkey.path} Port = ${toString tinc.config.host.nets.${netname}.tinc.port} ${tinc.config.extraConfig} ''; @@ -169,25 +159,17 @@ let }; privkey = mkOption { - type = types.secret-file; - default = { - name = "${tinc.config.netname}.rsa_key.priv"; - path = "${tinc.config.user.home}/tinc.rsa_key.priv"; - owner = tinc.config.user; - source-path = toString + "/${tinc.config.netname}.rsa_key.priv"; - }; + type = types.absolute-pathname; + default = toString + "/${tinc.config.netname}.rsa_key.priv"; defaultText = "‹secrets/‹netname›.rsa_key.priv›"; }; privkey_ed25519 = mkOption { - type = types.nullOr types.secret-file; + type = types.nullOr types.absolute-pathname; default = - if config.krebs.hosts.${tinc.config.host.name}.nets.${tinc.config.netname}.tinc.pubkey_ed25519 == null then null else { - name = "${tinc.config.netname}.ed25519_key.priv"; - path = "${tinc.config.user.home}/tinc.ed25519_key.priv"; - owner = tinc.config.user; - source-path = toString + "/${tinc.config.netname}.ed25519_key.priv"; - }; + if tinc.config.host.nets.${netname}.tinc.pubkey_ed25519 == null + then null + else toString + "/${tinc.config.netname}.ed25519_key.priv"; defaultText = "‹secrets/‹netname›.ed25519_key.priv›"; }; @@ -226,28 +208,7 @@ let })); }; - imp = { - # TODO `environment.systemPackages = [ cfg.tincPackage cfg.iproutePackage ]` for each network, - # avoid conflicts in environment if the packages differ - - krebs.secret.files = - let - ed25519_keys = - filterAttrs - (_: key: key != null) - (mapAttrs' - (netname: cfg: - nameValuePair "${netname}.ed25519_key.priv" cfg.privkey_ed25519 - ) - config.krebs.tinc); - - rsa_keys = - mapAttrs' - (netname: cfg: nameValuePair "${netname}.rsa_key.priv" cfg.privkey) - config.krebs.tinc; - in - ed25519_keys // rsa_keys; - + config = { users.users = mapAttrs' (netname: cfg: nameValuePair "${netname}" { inherit (cfg.user) home name uid; @@ -267,34 +228,42 @@ let } ) config.krebs.tinc; - systemd.services = mapAttrs (netname: cfg: - let - tinc = cfg.tincPackage; - iproute = cfg.iproutePackage; - in { - description = "Tinc daemon for ${netname}"; - after = [ - "network.target" - config.krebs.secret.files."${netname}.rsa_key.priv".service - ] ++ optionals (cfg.privkey_ed25519 != null) [ - config.krebs.secret.files."${netname}.ed25519_key.priv".service + krebs.systemd.services = mapAttrs (netname: cfg: { + serviceConfig.LoadCredential = filter (x: x != "") [ + (optionalString (cfg.privkey_ed25519 != null) + "ed25519_key:${cfg.privkey_ed25519}" + ) + "rsa_key:${cfg.privkey}" + ]; + }) config.krebs.tinc; + + systemd.services = mapAttrs (netname: cfg: { + description = "Tinc daemon for ${netname}"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ + cfg.iproutePackage + cfg.tincPackage + ]; + reloadIfChanged = true; + restartTriggers = [ cfg.confDir ]; + serviceConfig = { + Restart = "always"; + ExecStart = toString [ + "${cfg.tincPackage}/sbin/tincd" + "-D" + "-U ${cfg.user.name}" + "-c /etc/tinc/${netname}" + "-d 0" + (optionalString (cfg.privkey_ed25519 != null) + "-o Ed25519PrivateKeyFile=\${CREDENTIALS_DIRECTORY}/ed25519_key" + ) + "-o PrivateKeyFile=\${CREDENTIALS_DIRECTORY}/rsa_key" + "--pidfile=/var/run/tinc.${netname}.pid" ]; - partOf = [ - config.krebs.secret.files."${netname}.rsa_key.priv".service - ] ++ optionals (cfg.privkey_ed25519 != null) [ - config.krebs.secret.files."${netname}.ed25519_key.priv".service - ]; - wantedBy = [ "multi-user.target" ]; - path = [ tinc iproute ]; - reloadIfChanged = true; - restartTriggers = [ cfg.confDir ]; - serviceConfig = rec { - Restart = "always"; - ExecStart = "${tinc}/sbin/tincd -c /etc/tinc/${netname} -d 0 -U ${cfg.user.name} -D --pidfile=/var/run/tinc.${SyslogIdentifier}.pid"; - ExecReload = "${tinc}/sbin/tinc -n ${netname} reload"; - SyslogIdentifier = netname; - }; - } - ) config.krebs.tinc; + ExecReload = "${cfg.tincPackage}/sbin/tinc -n ${netname} reload"; + SyslogIdentifier = netname; + }; + }) config.krebs.tinc; }; -in out +} diff --git a/krebs/5pkgs/simple/empty.nix b/krebs/5pkgs/simple/empty.nix deleted file mode 100644 index a45723b65..000000000 --- a/krebs/5pkgs/simple/empty.nix +++ /dev/null @@ -1,2 +0,0 @@ -{ pkgs }: -pkgs.runCommand "empty-1.0.0" {} "mkdir $out" diff --git a/lib/default.nix b/lib/default.nix index 738e52186..574713e48 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -39,6 +39,8 @@ let listToAttrs (map (name: nameValuePair name set.${name}) (filter (flip hasAttr set) names)); + maybeHead = x: if isList x && length x > 0 then head x else null; + packageName = pkg: pkg.pname or (parseDrvName pkg.name).name;