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 };5859 owners = mkOption {60 type = listOf str;61 description = ''62 For which owners this secret is currently encrypted,63 if not matches expectedOwners - then this secret is considered outdated, and64 should be regenerated/reencrypted.6566 Imported from fleet.nix67 '';68 default = [ ];69 };70 public = mkOption {71 type = nullOr str;72 description = "Secret public data. Imported from fleet.nix";73 default = null;74 };75 secret = mkOption {76 type = nullOr str;77 description = "Encrypted secret data. Imported from fleet.nix";78 default = null;79 internal = true;80 };81 };82 };83 hostSecret = with types; {84 options = {85 generator = mkOption {86 type = package;87 description = "Derivation to execute for secret generation";88 };89 expireIn = mkOption {90 type = nullOr int;91 description = "Time in hours, in which this secret should be regenerated";92 default = null;93 };94 public = mkOption {95 type = nullOr str;96 description = "Secret public data";97 default = null;98 };99 secret = mkOption {100 type = str;101 description = "Encrypted secret data";102 };103 };104 };105in106{107 options = with types; {108 sharedSecrets = mkOption {109 type = attrsOf (submodule sharedSecret);110 default = { };111 description = "Shared secrets";112 };113 hostSecrets = mkOption {114 type = attrsOf (attrsOf (submodule hostSecret));115 default = { };116 description = "Host secrets";117 };118 };119 config = {120 assertions = mapAttrsToList121 (name: secret: {122 assertion = builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;123 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";124 })125 config.sharedSecrets;126 hosts = hostsToAttrs (host: {127 modules =128 let129 cleanupSecret = (secretName: v: {130 inherit (v) public secret;131 });132 in133 [134 {135 secrets = (mapAttrs cleanupSecret136 (filterAttrs (_: v: builtins.elem host v.owners) config.sharedSecrets)137 ) // (mapAttrs cleanupSecret (config.hostSecrets.${host} or { }));138 }139 ];140 });141 };142}