1{2 lib,3 fleetLib,4 config,5 pkgs,6 ...7}: let8 inherit (builtins) hashString;9 inherit (lib.stringsWithDeps) stringAfter;10 inherit (lib.options) mkOption literalExpression;11 inherit (lib.lists) optional;12 inherit (lib.attrsets) mapAttrs;13 inherit (lib.modules) mkIf;14 inherit (lib.types) submodule str attrsOf nullOr unspecified lazyAttrsOf;15 inherit (fleetLib.strings) decodeRawSecret;1617 sysConfig = config;18 secretPartType = secretName:19 submodule ({config, ...}: let20 partName = config._module.args.name;21 in {22 options = {23 raw = mkOption {24 type = str;25 internal = true;26 description = "Encoded & Encrypted secret part data, passed from fleet.nix";27 };28 hash = mkOption {29 type = str;30 description = "Hash of secret in encoded format";31 };32 path = mkOption {33 type = str;34 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";35 };36 stablePath = mkOption {37 type = str;38 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";39 };40 data = mkOption {41 type = str;42 description = "Secret public data (only available for plaintext)";43 };4445 expectedGenerationData = mkOption {46 type = unspecified;47 description = "Data that gets embedded into secret part";48 default = null;49 };50 generationData = mkOption {51 type = unspecified;52 description = "Data that is embedded into secret part";53 default = null;54 };55 };56 config = {57 hash = hashString "sha1" config.raw;58 data = decodeRawSecret config.raw;59 path = "/run/secrets/${secretName}/${config.hash}-${partName}";60 stablePath = "/run/secrets/${secretName}/${partName}";61 };62 });63 secretType = submodule ({config, ...}: let64 secretName = config._module.args.name;65 in {66 freeformType = lazyAttrsOf (secretPartType secretName);67 options = {68 shared = mkOption {69 description = "Is this secret owned by this machine, or propagated from shared secrets";70 default = false;71 };7273 generator = mkOption {74 type = nullOr unspecified;75 description = "Derivation to evaluate for secret generation";76 default = null;77 };78 mode = mkOption {79 type = str;80 description = "Secret mode";81 default = "0440";82 };83 owner = mkOption {84 type = str;85 description = "Owner of the secret";86 default = "root";87 };88 group = mkOption {89 type = str;90 description = "Group of the secret";91 default = sysConfig.users.users.${config.owner}.group;92 defaultText = literalExpression "config.users.users.$${owner}.group";93 };94 };95 });96 processPart = part: {97 inherit (part) raw path stablePath;98 };99 processSecret = secret:100 {101 inherit (secret) group mode owner;102 }103 // (mapAttrs (_: processPart) (removeAttrs secret [104 "shared"105 "generator"106 "mode"107 "group"108 "owner"109 ]));110 secretsFile = pkgs.writeTextFile {111 name = "secrets.json";112 text =113 builtins.toJSON (mapAttrs (_: processSecret)114 config.secrets);115 };116 useSysusers = (config.systemd ? sysusers && config.systemd.sysusers.enable) || (config ? userborn && config.userborn.enable);117in {118 options = {119 secrets = mkOption {120 type = attrsOf secretType;121 default = {};122 description = "Host-local secrets";123 };124 };125 config = {126 environment.systemPackages = [pkgs.fleet-install-secrets];127128 systemd.services.fleet-install-secrets = mkIf useSysusers {129 wantedBy = ["sysinit.target"];130 after = ["systemd-sysusers.service"];131 restartTriggers = [132 secretsFile133 ];134 aliases = [135 "sops-install-secrets"136 "agenix-install-secrets"137 ];138139 unitConfig.DefaultDependencies = false;140141 serviceConfig = {142 Type = "oneshot";143 RemainAfterExit = true;144 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";145 };146 };147 system.activationScripts.decryptSecrets =148 mkIf (!useSysusers)149 (150 stringAfter (151 [152 153 "users"154 "groups"155 "specialfs"156 ]157 158 159 160 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")161 ) ''162 1>&2 echo "setting up secrets"163 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}164 ''165 );166 };167}