1{2 lib,3 fleetLib,4 config,5 ...6}: let7 inherit (fleetLib.options) mkHostsOption;8 inherit (lib.options) mkOption;9 inherit (lib.types) lazyAttrsOf unspecified nullOr listOf str bool attrsOf submodule;10 inherit (lib.lists) sort elem;11 inherit (lib.attrsets) mapAttrsToList mapAttrs filterAttrs;12 inherit (lib.strings) toJSON concatStringsSep;1314 sharedSecret = {config, ...}: {15 freeformType = lazyAttrsOf unspecified;16 options = {17 expectedOwners = mkOption {18 type = nullOr (listOf str);19 description = ''20 List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)2122 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners23 '';24 default = null;25 };26 27 regenerateOnOwnerAdded = mkOption {28 type = bool;29 description = ''30 Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.3132 You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.33 '';34 };35 regenerateOnOwnerRemoved = mkOption {36 default = config.regenerateOnOwnerAdded;37 type = bool;38 description = ''39 Should this secret be removed on owner removal, or it may be just reencrypted4041 Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.42 Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked43 in some other way than by this secret ownership, I.e by firewall/etc.44 '';45 };46 generator = mkOption {47 type = nullOr unspecified;48 description = "Derivation to evaluate for secret generation";49 default = null;50 };51 createdAt = mkOption {52 type = nullOr str;53 description = "When this secret was (re)generated";54 default = null;55 };56 expiresAt = mkOption {57 type = nullOr str;58 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";59 default = null;60 };6162 owners = mkOption {63 type = listOf str;64 description = ''65 For which owners this secret is currently encrypted,66 if not matches expectedOwners - then this secret is considered outdated, and67 should be regenerated/reencrypted.6869 Imported from fleet.nix70 '';71 default = [];72 };73 };74 };75 hostSecret = {76 freeformType = lazyAttrsOf unspecified;77 options = {78 createdAt = mkOption {79 type = nullOr str;80 default = null;81 };82 expiresAt = mkOption {83 type = nullOr str;84 default = null;85 };86 };87 };88 inherit (config) hostSecrets sharedSecrets;89in {90 options = {91 version = mkOption {92 type = str;93 internal = true;94 };95 sharedSecrets = mkOption {96 type = attrsOf (submodule sharedSecret);97 default = {};98 description = "Shared secrets";99 };100 hostSecrets = mkOption {101 type = attrsOf (attrsOf (submodule hostSecret));102 default = {};103 description = "Host secrets. Imported from fleet.nix";104 internal = true;105 };106 hosts = mkHostsOption ({config, ...}: {107 nixos = {108 secrets = let109 host = config._module.args.name;110 processSecret = v:111 (removeAttrs v ["createdAt" "expiresAt" "expectedOwners" "owners" "regenerateOnOwnerAdded" "regenerateOnOwnerRemoved"])112 // {113 shared = true;114 };115 in116 (117 mapAttrs (_: processSecret)118 (filterAttrs (_: v: elem host v.owners) sharedSecrets)119 )120 // (mapAttrs (_: processSecret) (hostSecrets.${host} or {}));121 _file = ./secrets.nix;122 };123 });124 };125 config = {126 assertions =127 mapAttrsToList128 (name: secret: {129 assertion = secret.expectedOwners == null || sort (a: b: a < b) secret.owners == sort (a: b: a < b) secret.expectedOwners;130 message = "Shared secret ${name} is expected to be encrypted for ${toJSON secret.expectedOwners}, but it is encrypted for ${toJSON secret.owners}. Run fleet secrets regenerate to fix";131 })132 config.sharedSecrets;133 nixpkgs.overlays = [134 (final: prev: {135 mkSecretGenerators = {recipients}: rec {136 137 138 139 mkImpureSecretGenerator = {140 script,141 142 143 impureOn ? null,144 }:145 (prev.writeShellScript "impureGenerator.sh" ''146 147 set -eu148149 export GENERATOR_HELPER_IDENTITIES="${concatStringsSep "\n" recipients}";150 export PATH=${final.fleet-generator-helper}/bin:$PATH151152 153 tmp=$(mktemp -d)154 cd $tmp155 156157 created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")158159 ${script}160161 if ! test -d $out; then162 echo "impure generator script did not produce expected \$out output"163 exit 1164 fi165166 echo -n $created_at > $out/created_at167 echo -n SUCCESS > $out/marker168 '')169 .overrideAttrs (old: {170 passthru = {171 inherit impureOn;172 generatorKind = "impure";173 };174 });175 176 mkSecretGenerator = {script}: mkImpureSecretGenerator {inherit script;};177178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 };207 })208 ];209 };210}