9 cfg = config.security.systemd-creds;
12 options.security.systemd-creds = {
16 Destination address of the target host able to encrypt the credentials.
17 Used by the default {option}`security.systemd-creds.shell`.
19 default = "root@${config.networking.hostName}.${config.networking.domain}";
20 defaultText = mdLiteral "root@\${config.networking.hostName}.\${config.networking.domain}";
21 example = mdLiteral "''${config.networking.hostName}.wg";
24 type = with types; listOf str;
25 description = mdDoc ''
26 Command to get the cleartext of a credential.
27 `credBase` is derived from the path of the credential in `LoadCredentialEncrypted=`,
28 by removing the `builtins.storeDir` prefix and then one directory level.
30 apply = concatStringsSep " ";
35 "\${credBase%.cred}.gpg"
43 type = with types; listOf str;
44 description = mdDoc ''
45 Command to get a shell on the target host.
47 apply = concatStringsSep " ";
51 "StrictHostKeyChecking=yes"
56 "\"\${SYSTEMD_CREDS_TARGET:-${cfg.target}}\""
58 defaultText = mdLiteral ''
59 ssh -o StrictHostKeyChecking=yes \
60 -o ControlMaster=auto \
61 -o ControlPersist=16s \
62 \"''${SYSTEMD_CREDS_TARGET:-root@''${config.security.systemd-creds.target}}\"
67 type = with types; listOf str;
68 description = mdDoc ''
69 Command to run `systemd-creds encrypt` on the target host.
72 Beware that the files `/etc/machine-id`
73 and `/var/lib/systemd/credential.secret` on the target host,
74 are both used to encrypt and decrypt when using the `host` key mechanism.
75 Meaning that reinstalling the system on a new drive
76 without restoring those two files
77 will require to reencrypt the credentials.
80 apply = concatStringsSep " ";
96 type = with types; listOf str;
97 apply = concatStringsSep " ";
98 description = mdDoc ''
99 Command to install the encrypted credential on the orchestrating host.
110 reencrypt = mkOption {
112 apply = pkgs.writeShellScriptBin "systemd-creds-encrypt-${
113 replaceStrings [ "@" ] [ "-" ] cfg.target
115 description = mdDoc ''
116 Encrypt credentials referenced in the `LoadCredentialEncrypted=`
117 of enabled systemd services, by running `systemd-creds` on the {option}`security.systemd-creds.target` host.
118 Only *non-existing* credential files are considered,
119 unless the `SYSTEMD_CREDS_FORCE_REENCRYPT` envvar is set to a non-empty value.
120 Credential directories are not supported.
124 $ sudo wg genkey | gpg --encrypt --sign --recipient @$USER --output wireguard/wg-intra/privateKey.gpg
125 $ git add wireguard/wg-intra/privateKey.gpg
129 { config, pkgs, lib, inputs, ... }:
131 systemd.services."wireguard-wg-intra".serviceConfig.LoadCredentialEncrypted =
132 [ "privateKey:''${inputs.self}/wireguard/wg-intra/privateKey.cred" ];
137 $ nix run .#nixosConfigurations.''${hostName}.config.security.systemd-creds.reencrypt
138 $ git add wireguard/wg-intra/privateKey.cred
142 To be able to access the relative path of the `.cred` file,
143 `inputs.self` has to be used in `LoadCredentialEncrypted=`.
144 Note that `inputs` is a `config._module.args` or `specialArgs`
145 usually set in your `flake.nix`.
146 In other words, using `''${wireguard/wg-intra/privatekey}` here,
147 would not work, because it drops the `wireguard/wg-intra/` part.
153 security.systemd-creds.reencrypt =
155 shopt -s extglob globstar nullglob
160 concatMapStringsSep "\n"
163 concatMapStringsSep "\n" (
166 cred = splitString ":" credential;
167 credID = elemAt cred 0;
168 credPath = elemAt cred 1;
171 credID=${escapeShellArg credID}
172 credPath=${escapeShellArg credPath}
173 credBase=''${credPath#${builtins.storeDir}/*/}
174 if test "''${SYSTEMD_CREDS_FORCE_REENCRYPT:+set}" \
175 -o ! -s "$credBase" \
176 -o -e "''${credBase%.cred}.gpg" -a "$credBase" -ot "''${credBase%.cred}.gpg"; then
177 { ${cfg.decrypt}; } |
178 { ${cfg.shell} -- ${cfg.encrypt} - -; } |
182 ) (toList service.serviceConfig.LoadCredentialEncrypted)
187 _serviceName: service: service.enable && hasAttr "LoadCredentialEncrypted" service.serviceConfig
188 ) config.systemd.services