difftreelog
feat mkAskEnv, mkAskFile
in: trunk
1 file changed
lib/default.nixdiffbeforeafterboth1# Shared functions for fleet configuration, available as `fleet` module argument2{ lib }:3let4 inherit (lib.trivial) isFunction functionArgs;5 inherit (lib.options) mkOption mergeOneOption;6 inherit (lib.modules) mkOverride;7 inherit (lib.types)8 listOf9 submodule10 attrsOf11 mkOptionType12 ;13 inherit (lib.strings) optionalString hasPrefix removePrefix;14in15rec {16 types = {17 overlay = mkOptionType {18 name = "nixpkgs-overlay";19 description = "nixpkgs overlay";20 check = {21 __functor = _self: isFunction;22 isV2MergeCoherent = true;23 };24 merge = mergeOneOption;25 };26 listOfOverlay = listOf types.overlay;2728 mkHostsType = module: attrsOf (submodule module);29 mkDataType = module: submodule module;30 };3132 options = {33 mkHostsOption =34 module:35 mkOption {36 type = types.mkHostsType module;37 };38 mkDataOption =39 module:40 mkOption {41 type = types.mkDataType module;42 };43 };4445 inherit (options) mkHostsOption;4647 modules = {48 /**49 Use in places, where fleet might know better than nixpkgs defaults to50 */51 mkFleetDefault = mkOverride 999;52 /**53 Some generators use mkDefault, but optionDefault is set by nixpkgs.54 */55 mkFleetGeneratorDefault = mkOverride 1001;56 };5758 inherit (modules) mkFleetDefault mkFleetGeneratorDefault;5960 secrets = {6162 /**63 Generate a random secret password, 32 ascii characters by default6465 Options:66 size: generated password length in ascii characters (bytes).67 noSymbols: by default, character set includes various special characters ($ , ! + * : ~), and might68 not be accepted in some contexts, this option switches charset to just [A-Za-z0-9].6970 Output:71 Resulting secret has only part: secret, which contains encrypted password.72 */73 mkPassword =74 {75 size ? 32,76 }:77 (78 {79 coreutils,80 mkSecretGenerator,81 }:82 mkSecretGenerator {83 script = ''84 mkdir $out85 gh generate password -o $out/secret --size ${toStringsize}86 '';87 parts.secret.encrypted = true;88 }89 );9091 /**92 Generate a random ed25519 keypair9394 Options:95 noEmbedPublic: By default, secret key also embeds public key in itself ("extended" format, 64 bytes)96 When noEmbedPublis is enabled - only the private scalar is included.97 encoding: Encoring of public and secret parts, can be "raw" (default), "base64" or "hex".9899 Output:100 Resulting secret has two parts: public and secret, where the secret part is encrypted.101102 This secret format is used by e.g Garage S3 server103 */104 mkEd25519 =105 {106 noEmbedPublic ? false,107 encoding ? null,108 }:109 (110 { mkSecretGenerator }:111 mkSecretGenerator {112 script = ''113 mkdir $out114 gh generate ed25519 -p $out/public -s $out/secret \115 ${optionalStringnoEmbedPublic"--no-embed-public"} \116 ${optionalString(encoding!=null)"--encoding=${encoding}"}117 '';118 parts.secret.encrypted = true;119 parts.public.encrypted = false;120 }121 );122123 /**124 Generate a random x25519 keypair125126 Options:127 encoding: Encoring of public and secret parts, can be "raw" (default), "base64" or "hex".128129 Output:130 Resulting secret has two parts: public and secret, where the secret part is encrypted.131132 This secret format is used by e.g Wireguard VPN for peers (base64-encoded)133 */134 mkX25519 =135 {136 encoding ? null,137 }:138 (139 { mkSecretGenerator }:140 mkSecretGenerator {141 script = ''142 mkdir $out143 gh generate x25519 -p $out/public -s $out/secret \144 ${optionalString(encoding!=null)"--encoding=${encoding}"}145 '';146147 parts.secret.encrypted = true;148 parts.public.encrypted = false;149 }150 );151152 mkAskPass =153 {154 prompt ? "Secret value",155 part ? "secret",156 }:157 (158 {159 kdePackages,160 mkImpureSecretGenerator,161 }:162 mkImpureSecretGenerator {163 # TODO: Escape prompt/part (preferrably just use env) to prevent shell injection164 script = ''165 mkdir $out166 ${kdePackages.kdialog}/bin/kdialog --inputbox "${prompt}" | gh private -o $out/${part}167 '';168169 parts.${part}.encrypted = true;170 }171 );172173 mkAskFile =174 {175 header ? "",176 part ? "secret",177 }:178 (179 {180 kdePackages,181 coreutils,182 mkImpureSecretGenerator,183 }:184 mkImpureSecretGenerator {185 script = ''186 mkdir $out187 tmpfile=$(${coreutils}/bin/mktemp)188 trap "${coreutils}/bin/rm -f $tmpfile" EXIT189 cat > "$tmpfile" <<'HEADER'190 ${header}191 HEADER192 ${kdePackages.kate}/bin/kate --startanon --new --block "$tmpfile"193 gh private -o $out/${part} < "$tmpfile"194 '';195196 parts.${part}.encrypted = true;197 }198 );199200 mkAskEnv =201 {202 header ? "",203 variables ? [ ],204 part ? "secret",205 }:206 mkAskFile {207 inherit part;208 header = builtins.concatStringsSep "\n" (209 (map (l: "# ${l}") (lib.splitString "\n" header))210 ++ (map (v: "${v}=") variables)211 );212 };213214 /**215 Generate a random RSA keypair216217 Options:218 size: RSA key size, 4096 by default219220 Output:221 Resulting secret has two parts: public and secret, where the secret part is encrypted.222 Both parts are PEM encoded.223 */224 mkRsa =225 {226 size ? 4096,227 }:228 (229 {230 openssl,231 mkSecretGenerator,232 }:233 mkSecretGenerator {234 script = ''235 mkdir $out236237 ${openssl}/bin/openssl genrsa -out rsa_private.key ${toStringsize}238 ${openssl}/bin/openssl rsa -in rsa_private.key -pubout -out rsa_public.key239240 cat rsa_private.key | gh private -o $out/secret241 cat rsa_public.key | gh public -o $out/public242 '';243244 parts.secret.encrypted = true;245 parts.public.encrypted = false;246 }247 );248249 /**250 Generate a random byte sequence251252 Options:253 size: generated password length in bytes, 32 by default.254 encoding: how the generated bytes should be encoded, "raw" (default), "hex" or "base64"255 noNuls: prevent output byte sequence from containing internal \0, useful for some C applications256 that can't handle their strings properly.257258 Output:259 Resulting secret has only part: secret, which contains encrypted bytes.260261 Might be used for e.g. Wireguard VPN PSK keys (base64-encoded)262 */263 mkBytes =264 {265 count ? 32,266 encoding,267 noNuls ? false,268 }:269 (270 { mkSecretGenerator }:271 mkSecretGenerator {272 script = ''273 mkdir $out274 gh generate bytes --count=${toStringcount} --encoding=${encoding} -o $out/secret \275 ${optionalStringnoNuls"--no-nuls"}276 '';277 parts.secret.encrypted = true;278 }279 );280 /**281 Shorthand for `mkBytes`, which defaults to "hex" encoding282 */283 mkHexBytes =284 {285 count ? 32,286 }:287 mkBytes {288 inherit count;289 encoding = "hex";290 };291 /**292 Shorthand for `mkBytes`, which defaults to "base64" encoding293 */294 mkBase64Bytes =295 {296 count ? 32,297 }:298 mkBytes {299 inherit count;300 encoding = "base64";301 };302303 # Wireguard304 # mkWireguard = {}: mkX25519 {encoding = "base64";};305 # mkWireguardPsk = {}: mkBase64Bytes {count = 32;};306 };307308 inherit (secrets)309 mkPassword310 mkEd25519311 mkX25519312 mkRsa313 mkBytes314 mkHexBytes315 mkBase64Bytes316 mkAskPass317 mkAskFile318 mkAskEnv319 ;320321 strings =322 let323 plaintextPrefix = "<PLAINTEXT>";324 plaintextNewlinePrefix = "<PLAINTEXT-NL>";325 in326 {327 /**328 Decode public secret part into string329 */330 decodeRawSecret =331 raw:332 if hasPrefix plaintextPrefix raw then333 removePrefix plaintextPrefix raw334 else if hasPrefix plaintextNewlinePrefix raw then335 removePrefix plaintextNewlinePrefix raw336 else337 throw "decodeRawSecret only works with plaintext-encoded secret public parts, got ${raw}";338 };339340 inherit (strings) decodeRawSecret;341}