1{ lib, config, pkgs, ... }:23with lib;45let6 sysConfig = config;7 secretType = types.submodule ({ config, ... }: {8 config = let secretName = config._module.args.name; in {9 stableSecretPath = mkOptionDefault "/run/secrets/secret-stable-${secretName}";10 secretPath = mkOptionDefault "/run/secrets/secret-${config.secretHash}-${secretName}";11 secretHash = mkOptionDefault (if config.secret != null then (builtins.hashString "sha1" config.secret) else throw "secret is not defined for secret ${secretName}");1213 stablePublicPath = mkOptionDefault "/run/secrets/public-stable-${secretName}";14 publicPath = mkOptionDefault "/run/secrets/public-${config.publicHash}-${secretName}";15 publicHash = mkOptionDefault (if config.public != null then (builtins.hashString "sha1" config.public) else throw "public is not defined for secret ${secretName}");16 };17 options = with types; {18 shared = mkOption {19 description = "Is this secret owned by this machine, or propagated from shared secrets";20 default = false;21 };2223 generator = mkOption {24 type = nullOr unspecified;25 description = "Derivation to evaluate for secret generation";26 default = null;27 };2829 public = mkOption {30 type = nullOr str;31 description = "Secret public data";32 default = null;33 };34 secret = mkOption {35 type = nullOr str;36 description = "Encrypted secret data";37 default = null;38 };39 mode = mkOption {40 type = str;41 description = "Secret mode";42 default = "0440";43 };44 owner = mkOption {45 type = str;46 description = "Owner of the secret";47 default = "root";48 };49 group = mkOption {50 type = str;51 description = "Group of the secret";52 default = sysConfig.users.users.${config.owner}.group;53 };5455 secretHash = mkOption {56 type = str;57 description = "Hash of .secret field";58 };59 publicHash = mkOption {60 type = str;61 description = "Hash of .public field";62 };6364 stableSecretPath = mkOption {65 type = str;66 description = ''67 Use this, if target process supports re-reading of secret from disk,68 and doesn't needs to be restarted when secret is updated in file69 '';70 };71 secretPath = mkOption {72 type = str;73 description = "Path to decrypted secret, suffixed with contents hash";74 };7576 stablePublicPath = mkOption {77 type = str;78 description = ''79 Use this, if target process supports re-reading of secret from disk,80 and doesn't needs to be restarted when secret is updated in file81 '';82 };83 publicPath = mkOption {84 type = str;85 description = "Path to the public part of secret";86 };87 };88 });89 secretsFile = pkgs.writeTextFile {90 name = "secrets.json";91 text = builtins.toJSON (mapAttrs (_: value: rec {92 inherit (value) group mode owner secret public;93 publicPath = if public != null then value.publicPath else "/missingno";94 stablePublicPath = if public != null then value.stablePublicPath else "/missingno";95 secretPath = if secret != null then value.secretPath else "/missingno";96 stableSecretPath = if secret != null then value.stableSecretPath else "/missingno";97 }) config.secrets);98 };99in100{101 options = {102 secrets = mkOption {103 type = types.attrsOf secretType;104 default = { };105 description = "Host-local secrets";106 };107 };108 config = {109 environment.systemPackages = with pkgs; [pkgs.fleet-install-secrets];110 system.activationScripts.decryptSecrets = stringAfter [ "users" "groups" "specialfs" ] ''111 1>&2 echo "setting up secrets"112 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}113 '';114 };115}