1{2 lib,3 fleetLib,4 config,5 pkgs,6 ...7}:8let9 inherit (builtins) hashString;10 inherit (lib.stringsWithDeps) stringAfter;11 inherit (lib.options) mkOption literalExpression;12 inherit (lib.lists) optional;13 inherit (lib.attrsets) mapAttrs;14 inherit (lib.modules) mkIf;15 inherit (lib.types)16 submodule17 str18 attrsOf19 nullOr20 unspecified21 lazyAttrsOf22 uniq23 functionTo24 package25 ;26 inherit (fleetLib.strings) decodeRawSecret;2728 sysConfig = config;29 secretPartType =30 secretName:31 submodule (32 { config, ... }:33 let34 partName = config._module.args.name;35 in36 {37 options = {38 raw = mkOption {39 type = str;40 internal = true;41 description = "Encoded & Encrypted secret part data, passed from fleet.nix";42 };43 hash = mkOption {44 type = str;45 description = "Hash of secret in encoded format";46 };47 path = mkOption {48 type = str;49 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";50 };51 stablePath = mkOption {52 type = str;53 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";54 };55 data = mkOption {56 type = str;57 description = "Secret public data (only available for plaintext)";58 };59 };60 config = {61 hash = hashString "sha1" config.raw;62 data = decodeRawSecret config.raw;63 path = "/run/secrets/${secretName}/${config.hash}-${partName}";64 stablePath = "/run/secrets/${secretName}/${partName}";65 };66 }67 );68 secretType = submodule (69 { config, ... }:70 let71 secretName = config._module.args.name;72 in73 {74 freeformType = lazyAttrsOf (secretPartType secretName);75 options = {76 shared = mkOption {77 description = "Is this secret owned by this machine, or propagated from shared secrets";78 default = false;79 };8081 generator = mkOption {82 type = uniq (nullOr (functionTo package));83 description = "Derivation to evaluate for secret generation";84 default = null;85 };86 mode = mkOption {87 type = str;88 description = "Secret mode";89 default = "0440";90 };91 owner = mkOption {92 type = str;93 description = "Owner of the secret";94 default = "root";95 };96 group = mkOption {97 type = str;98 description = "Group of the secret";99 default = sysConfig.users.users.${config.owner}.group;100 defaultText = literalExpression "config.users.users.$${owner}.group";101 };102 expectedGenerationData = mkOption {103 type = unspecified;104 description = "Data that gets embedded into secret part";105 default = null;106 };107 };108 }109 );110 processPart = part: {111 inherit (part) raw path stablePath;112 };113 processSecret =114 secret:115 {116 inherit (secret) group mode owner;117 }118 // (mapAttrs (_: processPart) (119 removeAttrs secret [120 "shared"121 "generator"122 "mode"123 "group"124 "owner"125 "expectedGenerationData"126 ]127 ));128 secretsFile = pkgs.writeTextFile {129 name = "secrets.json";130 text = builtins.toJSON (mapAttrs (_: processSecret) config.secrets);131 };132 useSysusers =133 (config.systemd ? sysusers && config.systemd.sysusers.enable)134 || (config ? userborn && config.userborn.enable);135in136{137 options = {138 secrets = mkOption {139 type = attrsOf secretType;140 default = { };141 description = "Host-local secrets";142 };143 };144 config = {145 environment.systemPackages = [ pkgs.fleet-install-secrets ];146147 systemd.services.fleet-install-secrets = mkIf useSysusers {148 wantedBy = [ "sysinit.target" ];149 after = [ "systemd-sysusers.service" ];150 restartTriggers = [151 secretsFile152 ];153 aliases = [154 "sops-install-secrets"155 "agenix-install-secrets"156 ];157158 unitConfig.DefaultDependencies = false;159160 serviceConfig = {161 Type = "oneshot";162 RemainAfterExit = true;163 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";164 };165 };166 system.activationScripts.decryptSecrets = mkIf (!useSysusers) (167 stringAfter168 (169 [170 171 "users"172 "groups"173 "specialfs"174 ]175 176 177 178 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")179 )180 ''181 1>&2 echo "setting up secrets"182 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}183 ''184 );185 };186}