From 2656cbf2a91f1f350e29e2ee2faa0bbe90f9b717 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 22 Dec 2021 23:27:07 +0100
Subject: [PATCH 01/10] empty -> emptyDirectory

---
 krebs/3modules/git.nix       | 4 ++--
 krebs/5pkgs/simple/empty.nix | 2 --
 2 files changed, 2 insertions(+), 4 deletions(-)
 delete mode 100644 krebs/5pkgs/simple/empty.nix

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/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"

From 9d65a3cdd8d73fd92418ef317b671bd14d105141 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 00:46:12 +0100
Subject: [PATCH 02/10] lib: add maybeHead

---
 lib/default.nix | 2 ++
 1 file changed, 2 insertions(+)

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;
 

From d6ebd497f09ed8994594a32f8848d218beea93a3 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 01:10:22 +0100
Subject: [PATCH 03/10] krebs.systemd.services: restart by LoadCredential

---
 krebs/3modules/default.nix |  1 +
 krebs/3modules/systemd.nix | 51 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)
 create mode 100644 krebs/3modules/systemd.nix

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/systemd.nix b/krebs/3modules/systemd.nix
new file mode 100644
index 000000000..c30b2264a
--- /dev/null
+++ b/krebs/3modules/systemd.nix
@@ -0,0 +1,51 @@
+{ config, options, pkgs, ... }: let {
+  lib = import ../../lib;
+
+  body.options.krebs.systemd.services = lib.mkOption {
+    default = {};
+    type = lib.types.attrs;
+    description = ''
+      Definition of systemd service units with bonus features.
+
+      Services defined using this option will be restarted whenever any file
+      (described by an absolute path) used in LoadCredential changes.
+    '';
+  };
+
+  body.config.systemd =
+    lib.mkMerge
+      (lib.flatten
+        (lib.mapAttrsToList (serviceName: cfg: let
+          prefix = [ "krebs" "systemd" "services" serviceName ];
+          opts = options.systemd.services.type.getSubOptions prefix;
+
+          paths =
+            lib.filter
+              lib.types.absolute-pathname.check
+              (map
+                (lib.compose [ lib.maybeHead (lib.match "[^:]*:(.*)") ])
+                (cfg.serviceConfig.LoadCredential or []));
+        in
+          lib.singleton {
+            services.${serviceName} = cfg;
+          }
+          ++
+          lib.optionals (cfg.enable or opts.enable.default) (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 restart"
+                  (lib.shell.escape serviceName)
+                ]);
+              };
+            };
+          }) paths)
+        ) config.krebs.systemd.services));
+}

From 21e407aa593c4ead51b44b0b993093f32cbdd852 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 01:12:38 +0100
Subject: [PATCH 04/10] krebs.tinc: use LoadCredential

---
 krebs/3modules/tinc.nix | 77 +++++++++++++++--------------------------
 1 file changed, 27 insertions(+), 50 deletions(-)

diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix
index 3d0cc8fb4..a0fc39e6f 100644
--- a/krebs/3modules/tinc.nix
+++ b/krebs/3modules/tinc.nix
@@ -28,10 +28,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 +165,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 <secrets> + "/${tinc.config.netname}.rsa_key.priv";
-          };
+          type = types.absolute-pathname;
+          default = toString <secrets> + "/${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 <secrets> + "/${tinc.config.netname}.ed25519_key.priv";
-            };
+            if tinc.config.host.nets.${netname}.tinc.pubkey_ed25519 == null
+              then null
+              else toString <secrets> + "/${tinc.config.netname}.ed25519_key.priv";
           defaultText = "‹secrets/‹netname›.ed25519_key.priv›";
         };
 
@@ -230,24 +218,6 @@ let
     # 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;
-
     users.users = mapAttrs' (netname: cfg:
       nameValuePair "${netname}" {
         inherit (cfg.user) home name uid;
@@ -267,30 +237,37 @@ let
       }
     ) config.krebs.tinc;
 
-    systemd.services = mapAttrs (netname: cfg:
+    krebs.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
-        ];
-        partOf = [
-          config.krebs.secret.files."${netname}.rsa_key.priv".service
-        ] ++ optionals (cfg.privkey_ed25519 != null) [
-          config.krebs.secret.files."${netname}.ed25519_key.priv".service
-        ];
+        after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
         path = [ tinc iproute ];
         reloadIfChanged = true;
         restartTriggers = [ cfg.confDir ];
-        serviceConfig = rec {
+        serviceConfig = {
+          LoadCredential = filter (x: x != "") [
+            (optionalString (cfg.privkey_ed25519 != null)
+              "ed25519_key:${cfg.privkey_ed25519}"
+            )
+            "rsa_key:${cfg.privkey}"
+          ];
           Restart = "always";
-          ExecStart = "${tinc}/sbin/tincd -c /etc/tinc/${netname} -d 0 -U ${cfg.user.name} -D --pidfile=/var/run/tinc.${SyslogIdentifier}.pid";
+          ExecStart = toString [
+            "${tinc}/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"
+          ];
           ExecReload = "${tinc}/sbin/tinc -n ${netname} reload";
           SyslogIdentifier = netname;
         };

From 5410c7dcccc44529e5d1071237fbb3cac5aec936 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 01:23:06 +0100
Subject: [PATCH 05/10] ci: configure krebs.build.host

---
 ci.nix | 3 +++
 1 file changed, 3 insertions(+)

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;
+          })
         ];
       }];
     }

From 018018e16b95b45f4a086df48c10a102a34e79ba Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 03:12:02 +0100
Subject: [PATCH 06/10] krebs.tinc: don't bother aliasing packages

---
 krebs/3modules/tinc.nix | 70 ++++++++++++++++++++---------------------
 1 file changed, 34 insertions(+), 36 deletions(-)

diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix
index a0fc39e6f..2daef8e15 100644
--- a/krebs/3modules/tinc.nix
+++ b/krebs/3modules/tinc.nix
@@ -237,41 +237,39 @@ let
       }
     ) config.krebs.tinc;
 
-    krebs.systemd.services = mapAttrs (netname: cfg:
-      let
-        tinc = cfg.tincPackage;
-        iproute = cfg.iproutePackage;
-      in {
-        description = "Tinc daemon for ${netname}";
-        after = [ "network.target" ];
-        wantedBy = [ "multi-user.target" ];
-        path = [ tinc iproute ];
-        reloadIfChanged = true;
-        restartTriggers = [ cfg.confDir ];
-        serviceConfig = {
-          LoadCredential = filter (x: x != "") [
-            (optionalString (cfg.privkey_ed25519 != null)
-              "ed25519_key:${cfg.privkey_ed25519}"
-            )
-            "rsa_key:${cfg.privkey}"
-          ];
-          Restart = "always";
-          ExecStart = toString [
-            "${tinc}/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"
-          ];
-          ExecReload = "${tinc}/sbin/tinc -n ${netname} reload";
-          SyslogIdentifier = netname;
-        };
-      }
-    ) config.krebs.tinc;
+    krebs.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 = {
+        LoadCredential = filter (x: x != "") [
+          (optionalString (cfg.privkey_ed25519 != null)
+            "ed25519_key:${cfg.privkey_ed25519}"
+          )
+          "rsa_key:${cfg.privkey}"
+        ];
+        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"
+        ];
+        ExecReload = "${cfg.tincPackage}/sbin/tinc -n ${netname} reload";
+        SyslogIdentifier = netname;
+      };
+    }) config.krebs.tinc;
   };
 in out

From 8029e80632da0dcb886445bd1e9ba2d55821cc30 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 03:16:44 +0100
Subject: [PATCH 07/10] krebs.tinc: drop api and imp boilerplate

---
 krebs/3modules/tinc.nix | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix
index 2daef8e15..91aa37fdf 100644
--- a/krebs/3modules/tinc.nix
+++ b/krebs/3modules/tinc.nix
@@ -1,12 +1,6 @@
 with import <stockholm/lib>;
-{ config, pkgs, ... }:
-let
-  out = {
-    options.krebs.tinc = api;
-    config = imp;
-  };
-
-  api = mkOption {
+{ config, pkgs, ... }: {
+  options.krebs.tinc = mkOption {
     default = {};
     description = ''
       define a tinc network
@@ -214,7 +208,7 @@ let
     }));
   };
 
-  imp = {
+  config = {
     # TODO `environment.systemPackages = [ cfg.tincPackage cfg.iproutePackage ]` for each network,
     # avoid conflicts in environment if the packages differ
 
@@ -272,4 +266,4 @@ let
       };
     }) config.krebs.tinc;
   };
-in out
+}

From 5f7ab23ebf220194dc9ef28dd164f042ee2804c4 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 03:20:36 +0100
Subject: [PATCH 08/10] krebs.tinc: drop environment.systemPackages TODO

Nobody bothered about this for more than five years.  And even though
fixable, chances are quite high that this feature is not needed anymore.
---
 krebs/3modules/tinc.nix | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix
index 91aa37fdf..f709b3343 100644
--- a/krebs/3modules/tinc.nix
+++ b/krebs/3modules/tinc.nix
@@ -209,9 +209,6 @@ with import <stockholm/lib>;
   };
 
   config = {
-    # TODO `environment.systemPackages = [ cfg.tincPackage cfg.iproutePackage ]` for each network,
-    # avoid conflicts in environment if the packages differ
-
     users.users = mapAttrs' (netname: cfg:
       nameValuePair "${netname}" {
         inherit (cfg.user) home name uid;

From 1cf495d6eb113541dfa1667f03f7edd10c2217b1 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 20:09:06 +0100
Subject: [PATCH 09/10] krebs.systemd: support credentials of any service

---
 krebs/3modules/systemd.nix | 33 ++++++++++++++++++---------------
 krebs/3modules/tinc.nix    | 15 +++++++++------
 2 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/krebs/3modules/systemd.nix b/krebs/3modules/systemd.nix
index c30b2264a..00538d5f3 100644
--- a/krebs/3modules/systemd.nix
+++ b/krebs/3modules/systemd.nix
@@ -1,36 +1,39 @@
-{ config, options, pkgs, ... }: let {
+{ config, pkgs, ... }: let {
   lib = import ../../lib;
 
   body.options.krebs.systemd.services = lib.mkOption {
     default = {};
-    type = lib.types.attrs;
-    description = ''
-      Definition of systemd service units with bonus features.
-
-      Services defined using this option will be restarted whenever any file
-      (described by an absolute path) used in LoadCredential changes.
-    '';
+    type = lib.types.attrsOf (lib.types.submodule {
+      options = {
+        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
-          prefix = [ "krebs" "systemd" "services" serviceName ];
-          opts = options.systemd.services.type.getSubOptions prefix;
-
           paths =
             lib.filter
               lib.types.absolute-pathname.check
               (map
                 (lib.compose [ lib.maybeHead (lib.match "[^:]*:(.*)") ])
-                (cfg.serviceConfig.LoadCredential or []));
+                cfg.serviceConfig.LoadCredential);
         in
           lib.singleton {
-            services.${serviceName} = cfg;
+            services.${serviceName} = {
+              serviceConfig = {
+                LoadCredential = cfg.serviceConfig.LoadCredential;
+              };
+            };
           }
           ++
-          lib.optionals (cfg.enable or opts.enable.default) (map (path: let
+          map (path: let
             triggerName = "trigger-${lib.systemd.encodeName path}";
           in {
             paths.${triggerName} = {
@@ -46,6 +49,6 @@
                 ]);
               };
             };
-          }) paths)
+          }) paths
         ) config.krebs.systemd.services));
 }
diff --git a/krebs/3modules/tinc.nix b/krebs/3modules/tinc.nix
index f709b3343..dca764f63 100644
--- a/krebs/3modules/tinc.nix
+++ b/krebs/3modules/tinc.nix
@@ -229,6 +229,15 @@ with import <stockholm/lib>;
     ) config.krebs.tinc;
 
     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" ];
@@ -239,12 +248,6 @@ with import <stockholm/lib>;
       reloadIfChanged = true;
       restartTriggers = [ cfg.confDir ];
       serviceConfig = {
-        LoadCredential = filter (x: x != "") [
-          (optionalString (cfg.privkey_ed25519 != null)
-            "ed25519_key:${cfg.privkey_ed25519}"
-          )
-          "rsa_key:${cfg.privkey}"
-        ];
         Restart = "always";
         ExecStart = toString [
           "${cfg.tincPackage}/sbin/tincd"

From d4521eb339a47c52c5e8f7d82969b54f6dce1e9c Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 23 Dec 2021 20:16:34 +0100
Subject: [PATCH 10/10] krebs.systemd: allow reload if credentials change

---
 krebs/3modules/systemd.nix | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/krebs/3modules/systemd.nix b/krebs/3modules/systemd.nix
index 00538d5f3..6b0fe9672 100644
--- a/krebs/3modules/systemd.nix
+++ b/krebs/3modules/systemd.nix
@@ -5,6 +5,19 @@
     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 =
@@ -33,7 +46,7 @@
             };
           }
           ++
-          map (path: let
+          lib.optionals (cfg.ifCredentialsChange != null) (map (path: let
             triggerName = "trigger-${lib.systemd.encodeName path}";
           in {
             paths.${triggerName} = {
@@ -44,11 +57,11 @@
               serviceConfig = {
                 Type = "oneshot";
                 ExecStart = lib.singleton (toString [
-                  "${pkgs.systemd}/bin/systemctl restart"
+                  "${pkgs.systemd}/bin/systemctl ${cfg.ifCredentialsChange}"
                   (lib.shell.escape serviceName)
                 ]);
               };
             };
-          }) paths
+          }) paths)
         ) config.krebs.systemd.services));
 }