inxi: add to essentials
[julm/julm-nix.git] / nixos / modules / security / systemd-creds.nix
index db641de71927aee0258163c8c4f516cbd6b854b1..d1d0d50163f5c9ec84efccb27ad07cc28f7056a6 100644 (file)
@@ -1,5 +1,4 @@
 { pkgs, lib, config, ... }:
-with builtins;
 with lib;
 let cfg = config.security.systemd-creds; in
 {
@@ -19,7 +18,7 @@ let cfg = config.security.systemd-creds; in
       description = mdDoc ''
         Command to get the cleartext of a credential.
         `credBase` is derived from the path of the credential in `LoadCredentialEncrypted=`,
-        by removing the `storeDir` prefix and then one directory level if any.
+        by removing the `builtins.storeDir` prefix and then one directory level.
       '';
       apply = concatStringsSep " ";
       default = [ "gpg" "--batch" "--decrypt" "\${credBase%.cred}.gpg" ];
@@ -75,37 +74,48 @@ let cfg = config.security.systemd-creds; in
       '';
       default = [ "install" "-D" "-m" "640" "/dev/stdin" "\"$credBase\"" ];
     };
-    script = mkOption {
+    reencrypt = mkOption {
       type = types.lines;
       apply = pkgs.writeShellScriptBin "systemd-creds-encrypt-${replaceStrings ["@"] ["-"] cfg.target}";
       description = mdDoc ''
         Encrypt credentials referenced in the `LoadCredentialEncrypted=`
         of enabled systemd services, by running `systemd-creds` on the {option}`security.systemd-creds.target` host.
-        Only *existing* and *empty* credential files, are considered.
-        Recursively if the credential path is a directory.
-        Note that when using flakes, the sandboxing requires those empty files to be added to Git beforehand.
+        Only *non-existing* credential files are considered,
+        unless the `SYSTEMD_CREDS_FORCE_REENCRYPT` envvar is set to a non-empty value.
+        Credential directories are not supported.
 
         Example of use:
         ```console
-        $ sudo wg genkey | gpg --encrypt --sign --recipient @$USER wireguard/wg-intra/privateKey.cred --output wireguard/wg-intra/privateKey.gpg
-        $ tee </dev/null >wireguard/wg-intra/privateKey.cred
-        $ git add wireguard/wg-intra/privateKey.cred
+        $ sudo wg genkey | gpg --encrypt --sign --recipient @$USER --output wireguard/wg-intra/privateKey.gpg
+        $ git add wireguard/wg-intra/privateKey.gpg
         ```
 
         ```nix
+        { config, pkgs, lib, inputs, ... }:
+        {
         systemd.services."wireguard-wg-intra".serviceConfig.LoadCredentialEncrypted =
-          [ "privateKey:''${wireguard/wg-intra/privateKey.cred}" ];
+          [ "privateKey:''${inputs.self}/wireguard/wg-intra/privateKey.cred" ];
+        }
         ```
 
         ```console
-        $ nix run .#nixosConfigurations.''${hostName}.config.security.systemd-creds.script
+        $ nix run .#nixosConfigurations.''${hostName}.config.security.systemd-creds.reencrypt
         $ git add wireguard/wg-intra/privateKey.cred
         ```
+
+        ::: {.warning}
+        To be able to access the relative path of the `.cred` file,
+        `inputs.self` has to be used in `LoadCredentialEncrypted=`.
+        Note that `inputs` is a `config._module.args` or `specialArgs`
+        usually set in your `flake.nix`.
+        In other words, using `''${wireguard/wg-intra/privatekey}` here,
+        would not work, because it drops the `wireguard/wg-intra/` part.
+        :::
       '';
     };
   };
   config = {
-    security.systemd-creds.script = ''
+    security.systemd-creds.reencrypt = ''
       shopt -s extglob globstar nullglob
       set -o pipefail
       set -eux
@@ -121,26 +131,17 @@ let cfg = config.security.systemd-creds; in
             ''
               credID=${escapeShellArg credID}
               credPath=${escapeShellArg credPath}
-              credBase=''${credPath#${storeDir}/*/}
-              if test -f "$credBase"; then
-                if test ! -s "$credBase"; then
-                  { ${cfg.decrypt}; } |
-                  { ${cfg.shell} -- ${cfg.encrypt} - -; } |
-                  { ${cfg.install}; }
-                fi
-              elif test -d "$credBase"; then
-                for credBase in "$credBase"/**(.); do
-                  credBase=''${credBase#${storeDir}/*-}
-                  if test ! -s "$credBase"; then
-                    { ${cfg.decrypt}; } |
-                    { ${cfg.shell} -- ${cfg.encrypt} - -; } |
-                    { ${cfg.install}; }
-                  fi
-                done
+              credBase=''${credPath#${builtins.storeDir}/*/}
+              if test "''${SYSTEMD_CREDS_FORCE_REENCRYPT:+set}" \
+                      -o ! -s "$credBase" \
+                      -o -e "''${credBase%.cred}.gpg" -a "$credBase" -ot "''${credBase%.cred}.gpg"; then
+                { ${cfg.decrypt}; } |
+                { ${cfg.shell} -- ${cfg.encrypt} - -; } |
+                { ${cfg.install}; }
               fi
             ''
           )
-          service.serviceConfig.LoadCredentialEncrypted)
+          (toList service.serviceConfig.LoadCredentialEncrypted))
       (attrValues
         (filterAttrs
           (_serviceName: service: