1{2 lib,3 ...4}:5let6 inherit (lib.options) mkOption literalExpression;7 inherit (lib.types)8 unspecified9 nullOr10 listOf11 str12 bool13 attrsOf14 submodule15 functionTo16 package17 uniq18 ;19 inherit (lib.strings) concatStringsSep;2021 sharedSecret =22 { config, ... }:23 {24 options = {25 expectedOwners = mkOption {26 type = nullOr (listOf str);27 description = ''28 Specifies the list of hosts authorized to decrypt and access this shared secret.2930 When null, secret ownership is managed manually via fleet.nix and CLI.31 Decrypted secrets will be stored at /run/secrets/$\{name} on authorized hosts.32 '';33 default = null;34 };35 regenerateOnOwnerAdded = mkOption {36 type = bool;37 description = ''38 Controls whether the secret must be regenerated when new owners are added.3940 Set to true when the secret contains owner-specific references (e.g., X.509 Subject Alternative Names).41 When true, adding a new owner will trigger secret regeneration instead of simple re-encryption.42 '';43 };44 regenerateOnOwnerRemoved = mkOption {45 default = config.regenerateOnOwnerAdded;46 defaultText = literalExpression "regenerateOnOwnerAdded";47 type = bool;48 description = ''49 Determines secret behavior when owners are removed from the configuration.5051 Typically mirrors regenerateOnOwnerAdded. Override cautiously.52 Set to false if host permissions are revoked through alternative mechanisms like firewall rules.53 '';54 };55 allowDifferent = mkOption {56 type = bool;57 description = ''58 When adding owner, do not update secret value for other owners, instead creating a new distribution59 '';60 };61 generator = mkOption {62 type = uniq (nullOr (functionTo package));63 description = ''64 Function evaluating to nix derivation responsible for (re)generating the secret's content.6566 An input to this function - `pkgs` of a generator host with implementation-defined representation of extra encryption data,67 use `mkSecretGenerator` helpers to implement own generators.68 '';69 default = null;70 };71 expectedGenerationData = mkOption {72 type = unspecified;73 description = "Contextual metadata embedded within the secret part value";74 default = null;75 };76 expectedPrivateParts = mkOption {77 type = listOf str;78 default = [ ];79 description = "List of parts that are expected to be encrypted";80 };81 expectedPublicParts = mkOption {82 type = listOf str;83 default = [ ];84 description = "List of parts that are expected to be public";85 };86 };87 };88in89{90 options = {91 secrets = mkOption {92 type = attrsOf (submodule sharedSecret);93 default = { };94 description = "Collection of secrets shared across multiple hosts with configurable ownership";95 };96 };97 config = {98 nixpkgs.overlays = [99 (final: prev: {100 mkSecretGenerators =101 { recipients }:102 rec {103 104 105 106 mkImpureSecretGenerator =107 {108 script,109 110 111 impureOn ? null,112 parts,113 }:114 (prev.writeShellScript "impureGenerator.sh" ''115 116 set -eu117118 export GENERATOR_HELPER_IDENTITIES="${concatStringsSep "\n" recipients}";119 export PATH=${final.fleet-generator-helper}/bin:$PATH120121 122 tmp=$(mktemp -d)123 cd $tmp124 125126 created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")127128 ${script}129130 if ! test -d $out; then131 echo "impure generator script did not produce expected \$out output"132 exit 1133 fi134135 echo -n $created_at > $out/created_at136 echo -n SUCCESS > $out/marker137 '').overrideAttrs138 (old: {139 passthru = {140 inherit impureOn parts;141 generatorKind = "impure";142 };143 });144 145 mkSecretGenerator = { script, parts }: mkImpureSecretGenerator { inherit script parts; };146147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 };176 })177 ];178 };179}