1{ lib, fleetLib, config, ... }: with lib; with fleetLib;2let3 sharedSecret = with types; {4 options = {5 expectedOwners = mkOption {6 type = listOf str;7 description = ''8 List of hosts to encrypt secret for910 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners11 '';12 default = [ ];13 };14 ownerDependent = mkOption {15 type = bool;16 description = "Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted";17 };18 generateImpure = mkOption {19 type = unspecified;20 };21 generator = mkOption {22 type = nullOr (submodule {23 packages = mkOption {24 type = attrsOf package;25 description = ''26 Derivation to execute for shared secret generation (key = system).27 This derivation should produce directory, with exactly two files:28 - publicData29 - encryptedSecretData3031 If null - secret value may only be created manually.32 '';33 };34 expectedData = mkOption {35 type = types.unspecified;36 description = "Data expected to be used for secret generation, if doesn't match specified - secret should be regenerated";37 };38 dependencies = mkOption {39 type = listOf str;40 description = ''41 List of secrets, on which this secret depends.4243 During generation, generator command will be ran on host, which already has specified secrets generated.44 '';45 default = [];46 };47 data = mkOption {48 type = types.unspecified;49 description = "Data used for secret generation. Imported from fleet.nix";50 default = null;51 internal = true;52 };53 });54 default = null;55 };56 expireIn = mkOption {57 type = nullOr int;58 description = "Time in hours, in which this secret should be regenerated";59 default = null;60 };61 createdAt = mkOption {62 type = nullOr str;63 default = null;64 };65 expiresAt = mkOption {66 type = nullOr str;67 default = null;68 };6970 owners = mkOption {71 type = listOf str;72 description = ''73 For which owners this secret is currently encrypted,74 if not matches expectedOwners - then this secret is considered outdated, and75 should be regenerated/reencrypted.7677 Imported from fleet.nix78 '';79 default = [ ];80 };81 public = mkOption {82 type = nullOr str;83 description = "Secret public data. Imported from fleet.nix";84 default = null;85 };86 secret = mkOption {87 type = nullOr str;88 description = "Encrypted secret data. Imported from fleet.nix";89 default = null;90 internal = true;91 };92 };93 };94 hostSecret = with types; {95 options = {96 createdAt = mkOption {97 type = nullOr str;98 default = null;99 };100 expiresAt = mkOption {101 type = nullOr str;102 default = null;103 };104 public = mkOption {105 type = nullOr str;106 description = "Secret public data. Imported from fleet.nix";107 default = null;108 };109 secret = mkOption {110 type = nullOr str;111 description = "Encrypted secret data. Imported from fleet.nix";112 default = null;113 internal = true;114 };115 };116 };117in118{119 options = with types; {120 sharedSecrets = mkOption {121 type = attrsOf (submodule sharedSecret);122 default = { };123 description = "Shared secrets";124 };125 hostSecrets = mkOption {126 type = attrsOf (attrsOf (submodule hostSecret));127 default = { };128 description = "Host secrets. Imported from fleet.nix";129 internal = true;130 };131 };132 config = {133 assertions = mapAttrsToList134 (name: secret: {135 assertion = builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;136 message = "Shared secret ${name} is expected to be encrypted for ${builtins.toJSON secret.expectedOwners}, but it is encrypted for ${builtins.toJSON secret.owners}. Run fleet secrets regenerate to fix";137 })138 config.sharedSecrets;139 hosts = hostsToAttrs (host: {140 modules =141 let142 cleanupSecret = (secretName: v: {143 inherit (v) public secret;144 });145 in146 [147 {148 secrets = (mapAttrs cleanupSecret149 (filterAttrs (_: v: builtins.elem host v.owners) config.sharedSecrets)150 ) // (mapAttrs cleanupSecret (config.hostSecrets.${host} or { }));151 }152 ];153 });154 };155}