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 generator = mkOption {19 type = nullOr (submodule {20 packages = mkOption {21 type = attrsOf package;22 description = ''23 Derivation to execute for shared secret generation (key = system).24 This derivation should produce directory, with exactly two files:25 - publicData26 - encryptedSecretData2728 If null - secret value may only be created manually.29 '';30 };31 expectedData = mkOption {32 type = types.unspecified;33 description = "Data expected to be used for secret generation, if doesn't match specified - secret should be regenerated";34 };35 dependencies = mkOption {36 type = listOf str;37 description = ''38 List of secrets, on which this secret depends.3940 During generation, generator command will be ran on host, which already has specified secrets generated.41 '';42 default = [];43 };44 data = mkOption {45 type = types.unspecified;46 description = "Data used for secret generation. Imported from fleet.nix";47 default = null;48 internal = true;49 };50 });51 default = null;52 };53 expireIn = mkOption {54 type = nullOr int;55 description = "Time in hours, in which this secret should be regenerated";56 default = null;57 };58 createdAt = mkOption {59 type = nullOr str;60 default = null;61 };62 expiresAt = mkOption {63 type = nullOr str;64 default = null;65 };6667 owners = mkOption {68 type = listOf str;69 description = ''70 For which owners this secret is currently encrypted,71 if not matches expectedOwners - then this secret is considered outdated, and72 should be regenerated/reencrypted.7374 Imported from fleet.nix75 '';76 default = [ ];77 };78 public = mkOption {79 type = nullOr str;80 description = "Secret public data. Imported from fleet.nix";81 default = null;82 };83 secret = mkOption {84 type = nullOr str;85 description = "Encrypted secret data. Imported from fleet.nix";86 default = null;87 internal = true;88 };89 };90 };91 hostSecret = with types; {92 options = {93 createdAt = mkOption {94 type = nullOr str;95 default = null;96 };97 expiresAt = mkOption {98 type = nullOr str;99 default = null;100 };101 public = mkOption {102 type = nullOr str;103 description = "Secret public data. Imported from fleet.nix";104 default = null;105 };106 secret = mkOption {107 type = nullOr str;108 description = "Encrypted secret data. Imported from fleet.nix";109 default = null;110 internal = true;111 };112 };113 };114in115{116 options = with types; {117 sharedSecrets = mkOption {118 type = attrsOf (submodule sharedSecret);119 default = { };120 description = "Shared secrets";121 };122 hostSecrets = mkOption {123 type = attrsOf (attrsOf (submodule hostSecret));124 default = { };125 description = "Host secrets. Imported from fleet.nix";126 internal = true;127 };128 };129 config = {130 assertions = mapAttrsToList131 (name: secret: {132 assertion = builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;133 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";134 })135 config.sharedSecrets;136 hosts = hostsToAttrs (host: {137 modules =138 let139 cleanupSecret = (secretName: v: {140 inherit (v) public secret;141 });142 in143 [144 {145 secrets = (mapAttrs cleanupSecret146 (filterAttrs (_: v: builtins.elem host v.owners) config.sharedSecrets)147 ) // (mapAttrs cleanupSecret (config.hostSecrets.${host} or { }));148 }149 ];150 });151 };152}