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;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 };44 };45 config = {46 hash = hashString "sha1" config.raw;47 data = decodeRawSecret config.raw;48 path = "/run/secrets/${secretName}/${config.hash}-${partName}";49 stablePath = "/run/secrets/${secretName}/${partName}";50 };51 });52 secretType = submodule ({config, ...}: let53 secretName = config._module.args.name;54 in {55 freeformType = lazyAttrsOf (secretPartType secretName);56 options = {57 shared = mkOption {58 description = "Is this secret owned by this machine, or propagated from shared secrets";59 default = false;60 };6162 generator = mkOption {63 type = nullOr unspecified;64 description = "Derivation to evaluate for secret generation";65 default = null;66 };67 mode = mkOption {68 type = str;69 description = "Secret mode";70 default = "0440";71 };72 owner = mkOption {73 type = str;74 description = "Owner of the secret";75 default = "root";76 };77 group = mkOption {78 type = str;79 description = "Group of the secret";80 default = sysConfig.users.users.${config.owner}.group;81 };82 };83 });84 processPart = part: {85 inherit (part) raw path stablePath;86 };87 processSecret = secret:88 {89 inherit (secret) group mode owner;90 }91 // (mapAttrs (_: processPart) (removeAttrs secret [92 "shared"93 "generator"94 "mode"95 "group"96 "owner"97 ]));98 secretsFile = pkgs.writeTextFile {99 name = "secrets.json";100 text =101 builtins.toJSON (mapAttrs (_: processSecret)102 config.secrets);103 };104 useSysusers = (config.systemd ? sysusers && config.systemd.sysusers.enable) || (config ? userborn && config.userborn.enable);105in {106 options = {107 secrets = mkOption {108 type = attrsOf secretType;109 default = {};110 description = "Host-local secrets";111 };112 };113 config = {114 environment.systemPackages = [pkgs.fleet-install-secrets];115116 systemd.services.fleet-install-secrets = mkIf useSysusers {117 wantedBy = ["sysinit.target"];118 after = ["systemd-sysusers.service"];119 restartTriggers = [120 secretsFile121 ];122 aliases = [123 "sops-install-secrets"124 "agenix-install-secrets"125 ];126127 unitConfig.DefaultDependencies = false;128129 serviceConfig = {130 Type = "oneshot";131 RemainAfterExit = true;132 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";133 };134 };135 system.activationScripts.decryptSecrets =136 mkIf (!useSysusers)137 (138 stringAfter (139 [140 141 "users"142 "groups"143 "specialfs"144 ]145 146 147 148 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")149 ) ''150 1>&2 echo "setting up secrets"151 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}152 ''153 );154 };155}