fcitx5: tweak classicui settings
[julm/julm-nix.git] / nixos / modules / security / systemd-creds.nix
index ca2065fabec6340870dbd7715cba99f299673db7..b3873342888992dc8a9065b49e489d58e66b18bb 100644 (file)
@@ -1,7 +1,13 @@
-{ pkgs, lib, config, ... }:
-with builtins;
+{
+  pkgs,
+  lib,
+  config,
+  ...
+}:
 with lib;
-let cfg = config.security.systemd-creds; in
+let
+  cfg = config.security.systemd-creds;
+in
 {
   options.security.systemd-creds = {
     target = mkOption {
@@ -19,12 +25,19 @@ 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,
-        and then the `.cred` suffix if any.
+        by removing the `builtins.storeDir` prefix and then one directory level.
       '';
       apply = concatStringsSep " ";
-      default = [ "gpg" "--batch" "--decrypt" "\${credBase}.gpg" ];
-      example = [ "pass" "\${credBase}" ];
+      default = [
+        "gpg"
+        "--batch"
+        "--decrypt"
+        "\${credBase%.cred}.gpg"
+      ];
+      example = [
+        "pass"
+        "\${credBase%.cred}"
+      ];
     };
     shell = mkOption {
       type = with types; listOf str;
@@ -33,9 +46,13 @@ let cfg = config.security.systemd-creds; in
       '';
       apply = concatStringsSep " ";
       default = [
-        "ssh" "-o" "StrictHostKeyChecking=yes"
-        "-o" "ControlMaster=auto"
-        "-o" "ControlPersist=16s"
+        "ssh"
+        "-o"
+        "StrictHostKeyChecking=yes"
+        "-o"
+        "ControlMaster=auto"
+        "-o"
+        "ControlPersist=16s"
         "\"\${SYSTEMD_CREDS_TARGET:-${cfg.target}}\""
       ];
       defaultText = mdLiteral ''
@@ -50,10 +67,30 @@ let cfg = config.security.systemd-creds; in
       type = with types; listOf str;
       description = mdDoc ''
         Command to run `systemd-creds encrypt` on the target host.
+
+        ::: {.warning}
+        Beware that the files `/etc/machine-id`
+        and `/var/lib/systemd/credential.secret` on the target host,
+        are both used to encrypt and decrypt when using the `host` key mechanism.
+        Meaning that reinstalling the system on a new drive
+        without restoring those two files
+        will require to reencrypt the credentials.
+        :::
       '';
       apply = concatStringsSep " ";
-      default = [ "systemd-creds" "encrypt" "--name" "\"$credID\"" "--with-key=auto" ];
-      example = ["sudo" "systemd-creds" "encrypt" "--with-key=host"];
+      default = [
+        "systemd-creds"
+        "encrypt"
+        "--name"
+        "\"$credID\""
+        "--with-key=auto"
+      ];
+      example = [
+        "sudo"
+        "systemd-creds"
+        "encrypt"
+        "--with-key=host"
+      ];
     };
     install = mkOption {
       type = with types; listOf str;
@@ -61,80 +98,95 @@ let cfg = config.security.systemd-creds; in
       description = mdDoc ''
         Command to install the encrypted credential on the orchestrating host.
       '';
-      default = [ "install" "-D" "-m" "640" "/dev/stdin" "\"$credBase\".cred" ];
+      default = [
+        "install"
+        "-D"
+        "-m"
+        "640"
+        "/dev/stdin"
+        "\"$credBase\""
+      ];
     };
-    script = mkOption {
+    reencrypt = mkOption {
       type = types.lines;
-      apply = pkgs.writeShellScriptBin "systemd-creds-encrypt-${replaceStrings ["@"] ["-"] cfg.target}";
+      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 = ''
-      shopt -s extglob globstar nullglob
-      set -o pipefail
-      set -eux
-      '' + concatMapStringsSep "\n"
-        (service:
-          concatMapStringsSep "\n"
-            (credential: let
-              cred = splitString ":" credential;
-              credID = elemAt cred 0;
-              credPath = elemAt cred 1;
-            in ''
-              credID=${escapeShellArg credID}
-              credPath=${escapeShellArg credPath}
-              if test -f "$credPath" -a ! -s "$credPath"; then
-                credBase=''${credPath#${storeDir}/}
-                credBase=''${credBase#*/}
-                credBase=''${credBase%.cred}
-                { ${cfg.decrypt}; } |
-                { ${cfg.shell} -- ${cfg.encrypt} - -; } |
-                { ${cfg.install}; }
-              elif test -d "$credPath"; then
-                for credPath in "$credPath"/**(.); do
-                  if test ! -s "$credPath"; then
-                    credBase=''${credPath#${storeDir}/}
-                    credBase=''${credBase#*-}
-                    credBase=''${credBase%.cred}
-                    { ${cfg.decrypt}; } |
-                    { ${cfg.shell} -- ${cfg.encrypt} - -; } |
-                    { ${cfg.install}; }
-                  fi
-                done
-              fi
-            ''
-            )
-            service.serviceConfig.LoadCredentialEncrypted)
-        (attrValues
-          (filterAttrs (serviceName: service:
-            service.enable &&
-            hasAttr "LoadCredentialEncrypted" service.serviceConfig
-            ) config.systemd.services
+    security.systemd-creds.reencrypt =
+      ''
+        shopt -s extglob globstar nullglob
+        set -o pipefail
+        set -eux
+      ''
+      +
+        concatMapStringsSep "\n"
+          (
+            service:
+            concatMapStringsSep "\n" (
+              credential:
+              let
+                cred = splitString ":" credential;
+                credID = elemAt cred 0;
+                credPath = elemAt cred 1;
+              in
+              ''
+                credID=${escapeShellArg credID}
+                credPath=${escapeShellArg credPath}
+                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
+              ''
+            ) (toList service.serviceConfig.LoadCredentialEncrypted)
           )
-        );
+          (
+            attrValues (
+              filterAttrs (
+                _serviceName: service: service.enable && hasAttr "LoadCredentialEncrypted" service.serviceConfig
+              ) config.systemd.services
+            )
+          );
   };
 }