git.delta.rocks / jrsonnet / refs/commits / 0f6e11e64e77

difftreelog

source

modules/secrets-data.nix4.2 KiBsourcehistory
1{2  lib,3  fleetLib,4  config,5  ...6}: let7  inherit (fleetLib.options) mkDataOption;8  inherit (lib.options) mkOption;9  inherit (lib.types) nullOr listOf str attrsOf submodule bool unspecified;10  inherit (lib.attrsets) mapAttrsToList mapAttrs filterAttrs genAttrs;11  inherit (lib.lists) sort unique concatLists;12  inherit (lib.strings) toJSON;1314  secretDataValue = {15    options = {16      raw = mkOption {17        type = nullOr str;18        description = "Raw secret data in unspecified encoded and optionally encrypted format.";19        default = null;20      };21    };22  };2324  sharedSecretData = {25    freeformType = attrsOf (submodule secretDataValue);26    options = {27      createdAt = mkOption {28        type = str;29        description = "Timestamp of secret generation/last rotation.";30        default = null;31      };32      expiresAt = mkOption {33        type = nullOr str;34        description = "Expiration timestamp triggering mandatory secret rotation.";35        default = null;36      };3738      owners = mkOption {39        type = listOf str;40        description = ''41          List of hosts currently authorized to decrypt this shared secret.4243          If owners differ from expected owners, the secret is considered outdated44          and requires regeneration or re-encryption.45        '';46        default = [];47      };48      generationData = mkOption {49        type = unspecified;50        description = "Contextual metadata associated with secret part.";51        default = null;52      };53    };54    config = {};55  };5657  hostSecretData = {58    freeformType = attrsOf (submodule secretDataValue);59    options = {60      createdAt = mkOption {61        type = str;62        description = "Timestamp of secret generation/last rotation.";63        default = null;64      };65      expiresAt = mkOption {66        type = nullOr str;67        description = "Expiration timestamp triggering mandatory secret rotation.";68        default = null;69      };70      shared = mkOption {71        type = bool;72        description = "Indicates if secret is a shared secret, so other hosts might have the same piece of secret data.";73        default = false;74      };75      generationData = mkOption {76        type = unspecified;77        description = "Contextual metadata associated with secret part.";78        default = null;79      };80    };81    config = {};82  };83in {84  options.data = mkDataOption ({config, ...}: {85    options = {86      sharedSecrets = mkOption {87        type = attrsOf (submodule sharedSecretData);88        default = {};89        description = "Shared secret data.";90      };91      hostSecrets = mkOption {92        type = attrsOf (attrsOf (submodule hostSecretData));93        default = {};94        description = "Host-specific secrets.";95        internal = true;96      };97    };98    config.hostSecrets = let99      hostsWithSharedSecrets = unique (concatLists (mapAttrsToList (_: s: s.owners) config.sharedSecrets));100      secretsHavingHost = host: filterAttrs (_: secret: lib.elem host secret.owners) config.sharedSecrets;101      toHostSecret = _: secret: (removeAttrs secret ["owners"]) // {shared = true;};102    in103      genAttrs hostsWithSharedSecrets (host: mapAttrs toHostSecret (secretsHavingHost host));104  });105  config = {106    assertions =107      (mapAttrsToList108        (name: secret: {109          assertion = secret.expectedOwners == null || sort (a: b: a < b) config.data.sharedSecrets.${name}.owners == sort (a: b: a < b) secret.expectedOwners;110          message = "Shared secret ${name} is expected to be encrypted for ${toJSON secret.expectedOwners}, but it is encrypted for ${toJSON config.data.sharedSecrets.${name}.owners}. Run fleet secrets regenerate to fix";111        })112        config.sharedSecrets)113      ++ (mapAttrsToList114        (name: secret: {115          # TODO: Same aassertion should be in host secrets116          assertion = config.data.sharedSecrets.${name}.generationData == secret.expectedGenerationData;117          message = "Shared secret ${name} has unexpected generation data ${toJSON secret.expectedGenerationData} != ${toJSON config.data.sharedSecrets.${name}.expectedGenerationData}. Run fleet secrets regenerate to fix";118        })119        config.sharedSecrets);120    sharedSecrets =121      mapAttrs (_: _: {}) config.data.sharedSecrets;122  };123}