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 };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 defaultText = literalExpression "config.users.users.$${owner}.group";82 };83 expectedGenerationData = mkOption {84 type = unspecified;85 description = "Data that gets embedded into secret part";86 default = null;87 };88 };89 });90 processPart = part: {91 inherit (part) raw path stablePath;92 };93 processSecret = secret:94 {95 inherit (secret) group mode owner;96 }97 // (mapAttrs (_: processPart) (removeAttrs secret [98 "shared"99 "generator"100 "mode"101 "group"102 "owner"103 ]));104 secretsFile = pkgs.writeTextFile {105 name = "secrets.json";106 text =107 builtins.toJSON (mapAttrs (_: processSecret)108 config.secrets);109 };110 useSysusers = (config.systemd ? sysusers && config.systemd.sysusers.enable) || (config ? userborn && config.userborn.enable);111in {112 options = {113 secrets = mkOption {114 type = attrsOf secretType;115 default = {};116 description = "Host-local secrets";117 };118 };119 config = {120 environment.systemPackages = [pkgs.fleet-install-secrets];121122 systemd.services.fleet-install-secrets = mkIf useSysusers {123 wantedBy = ["sysinit.target"];124 after = ["systemd-sysusers.service"];125 restartTriggers = [126 secretsFile127 ];128 aliases = [129 "sops-install-secrets"130 "agenix-install-secrets"131 ];132133 unitConfig.DefaultDependencies = false;134135 serviceConfig = {136 Type = "oneshot";137 RemainAfterExit = true;138 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";139 };140 };141 system.activationScripts.decryptSecrets =142 mkIf (!useSysusers)143 (144 stringAfter (145 [146 147 "users"148 "groups"149 "specialfs"150 ]151 152 153 154 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")155 ) ''156 1>&2 echo "setting up secrets"157 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}158 ''159 );160 };161}