1{2 lib,3 config,4 pkgs,5 ...6}: let7 inherit (lib.strings) hasPrefix removePrefix;8 inherit (lib.stringsWithDeps) stringAfter;9 inherit (lib.options) mkOption;10 inherit (lib.lists) optional;11 inherit (lib.attrsets) mapAttrs;12 inherit (lib.modules) mkOptionDefault mkIf;13 inherit (lib.types) submodule str attrsOf nullOr unspecified lazyAttrsOf;14 plaintextPrefix = "<PLAINTEXT>";15 plaintextNewlinePrefix = "<PLAINTEXT-NL>";1617 sysConfig = config;18 secretPartType = secretName:19 submodule ({config, ...}: {20 options = {21 raw = mkOption {22 description = "Secret in fleet-specific undocumented format, do not use. Import from fleet.nix";23 internal = true;24 };25 hash = mkOption {26 type = str;27 description = "Hash of secret in encoded format";28 };29 path = mkOption {30 type = str;31 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";32 };33 stablePath = mkOption {34 type = str;35 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";36 };37 data = mkOption {38 type = str;39 description = "Secret public data (only available for plaintext)";40 };41 };42 config = let43 partName = config._module.args.name;44 in {45 hash = mkOptionDefault (builtins.hashString "sha1" config.raw);46 data = mkOptionDefault (47 if hasPrefix plaintextPrefix config.raw48 then removePrefix plaintextPrefix config.raw49 else if hasPrefix plaintextNewlinePrefix config.raw50 then removePrefix plaintextNewlinePrefix config.raw51 else throw "secret.part.data attribute only works for public plaintext secret parts, got ${config.raw}"52 );53 path = mkOptionDefault "/run/secrets/${secretName}/${config.hash}-${partName}";54 stablePath = mkOptionDefault "/run/secrets/${secretName}/${partName}";55 };56 });57 secretType = submodule ({config, ...}: let58 secretName = config._module.args.name;59 in {60 freeformType = lazyAttrsOf (secretPartType secretName);61 options = {62 shared = mkOption {63 description = "Is this secret owned by this machine, or propagated from shared secrets";64 default = false;65 };66 expectedOwners = mkOption {67 type = nullOr unspecified;68 default = null;69 internal = true;70 };7172 generator = mkOption {73 type = nullOr unspecified;74 description = "Derivation to evaluate for secret generation";75 default = null;76 };77 mode = mkOption {78 type = str;79 description = "Secret mode";80 default = "0440";81 };82 owner = mkOption {83 type = str;84 description = "Owner of the secret";85 default = "root";86 };87 group = mkOption {88 type = str;89 description = "Group of the secret";90 default = sysConfig.users.users.${config.owner}.group;91 };92 };93 });94 processPart = part: {95 inherit (part) raw path stablePath;96 };97 processSecret = secret:98 {99 inherit (secret) group mode owner;100 }101 // (mapAttrs (_: processPart) (removeAttrs secret [102 "shared"103 "generator"104 "mode"105 "group"106 "owner"107108 109 "expectedOwners"110 ]));111 secretsFile = pkgs.writeTextFile {112 name = "secrets.json";113 text =114 builtins.toJSON (mapAttrs (_: processSecret)115 config.secrets);116 };117 useSysusers = (config.systemd ? sysusers && config.systemd.sysusers.enable) || (config ? userborn && config.userborn.enable);118in {119 options = {120 secrets = mkOption {121 type = attrsOf secretType;122 default = {};123 description = "Host-local secrets";124 };125 };126 config = {127 environment.systemPackages = [pkgs.fleet-install-secrets];128129 systemd.services.fleet-install-secrets = mkIf useSysusers {130 wantedBy = ["sysinit.target"];131 after = ["systemd-sysusers.service"];132 restartTriggers = [133 secretsFile134 ];135 aliases = [136 "sops-install-secrets"137 "agenix-install-secrets"138 ];139140 unitConfig.DefaultDependencies = false;141142 serviceConfig = {143 Type = "oneshot";144 RemainAfterExit = true;145 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";146 };147 };148 system.activationScripts.decryptSecrets =149 mkIf (!useSysusers)150 (151 stringAfter (152 [153 154 "users"155 "groups"156 "specialfs"157 ]158 159 160 161 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")162 ) ''163 1>&2 echo "setting up secrets"164 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}165 ''166 );167 };168}