git.delta.rocks / jrsonnet / refs/commits / 754b45cdacd0

difftreelog

source

modules/fleet/secrets.nix7.6 KiBsourcehistory
1{2  lib,3  fleetLib,4  config,5  ...6}:7with lib;8with fleetLib; let9  sharedSecret = with types; ({config, ...}: {10    options = {11      expectedOwners = mkOption {12        type = nullOr (listOf str);13        description = ''14          List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)1516          Secrets would be decrypted and stored to /run/secrets/$\{name} on owners17        '';18        default = null;19      };20      # TODO: Aren't those options may be just desugared to data/expectedData?21      regenerateOnOwnerAdded = mkOption {22        type = bool;23        description = ''24          Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.2526          You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.27        '';28      };29      regenerateOnOwnerRemoved = mkOption {30        default = config.regenerateOnOwnerAdded;31        type = bool;32        description = ''33          Should this secret be removed on owner removal, or it may be just reencrypted3435          Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.36          Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked37          in some other way than by this secret ownership, I.e by firewall/etc.38        '';39      };40      generator = mkOption {41        type = nullOr unspecified;42        description = "Derivation to evaluate for secret generation";43        default = null;44      };45      createdAt = mkOption {46        type = nullOr str;47        description = "When this secret was (re)generated";48        default = null;49      };50      expiresAt = mkOption {51        type = nullOr str;52        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";53        default = null;54      };5556      owners = mkOption {57        type = listOf str;58        description = ''59          For which owners this secret is currently encrypted,60          if not matches expectedOwners - then this secret is considered outdated, and61          should be regenerated/reencrypted.6263          Imported from fleet.nix64        '';65        default = [];66      };67      # TODO: Make secret generator generate arbitrary number of secret/public parts?68      # Make it generate a folder, where all files except suffixed by .enc are public, and the rest are secret?69      # How should modules refer to those files then?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      createdAt = mkOption {86        type = nullOr str;87        default = null;88      };89      expiresAt = mkOption {90        type = nullOr str;91        default = null;92      };93      public = mkOption {94        type = nullOr str;95        description = "Secret public data. Imported from fleet.nix";96        default = null;97      };98      secret = mkOption {99        type = nullOr str;100        description = "Encrypted secret data. Imported from fleet.nix";101        default = null;102        internal = true;103      };104    };105  };106in {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. Imported from fleet.nix";117      internal = true;118    };119  };120  config = {121    assertions =122      mapAttrsToList123      (name: secret: {124        assertion = secret.expectedOwners == null || builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;125        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";126      })127      config.sharedSecrets;128    hosts = hostsToAttrs (host: {129      modules = let130        cleanupSecret = secretName: v: {131          inherit (v) public secret;132          shared = true;133        };134      in [135        {136          secrets =137            (138              mapAttrs cleanupSecret139              (filterAttrs (_: v: builtins.elem host v.owners) config.sharedSecrets)140            )141            // (mapAttrs cleanupSecret (config.hostSecrets.${host} or {}));142        }143      ];144    });145    # TODO: Should this attribute be moved to `nixpkgs.overlays`?146    overlays = [147      (final: prev: let148        lib = final.lib;149      in {150        mkPassword = {size ? 32}:151          final.mkSecretGenerator ''152            ${final.coreutils}/bin/tr -dc 'A-Za-z0-9!?%=' < /dev/random \153              | ${final.coreutils}/bin/head -c ${toString size} \154              | encrypt > $out/secret155          '';156        mkRsa = {size ? 4096}:157          final.mkSecretGenerator ''158            ${final.openssl}/bin/openssl genrsa -out rsa_private.key ${toString size}159            ${final.openssl}/bin/openssl rsa -in rsa_private.key -pubout -out rsa_public.key160161            sudo cat rsa_private.key | encrypt > $out/secret162            sudo cat rsa_public.key > $out/public163          '';164        # TODO: Move to fleet165        # TODO: Merge both generators to one with consistent options syntax?166        # Impure generator is built on local machine, then built closure is copied to remote machine,167        # and then it is ran in inpure context, so that this generator may access HSMs and other things.168        mkImpureSecretGenerator = generatorText: machine:169          (prev.writeShellScript "impureGenerator.sh" ''170            #!/bin/sh171            set -eu172173            # TODO: Provide encryption function as script passed to `callPackage generator {encrypt = ...;}`174            function encrypt() {175              eval ${final.rage}/bin/rage $rageArgs176            }177178            created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")179            echo -n $created_at > $out/created_at180181            ${generatorText}182183            echo -n SUCCESS > $out/marker184          '')185          .overrideAttrs (old: {186            passthru = {187              generatorKind = "impure";188              impureOn = machine;189            };190          });191        # TODO: Implement consistent naming192        # Pure secret generator is supposed to be run entirely by nix, using `__impure` derivation type...193        # But for now, it is ran the same way as `impureSecretGenerator`, but on the local machine.194        mkSecretGenerator = generatorText:195          (prev.writeShellScript "generator.sh" ''196            #!/bin/sh197            set -eu198            # TODO: User should create output directory by themselves.199            cd $out200201            # TODO: Provide encryption function as script passed to `callPackage generator {encrypt = ...;}`202            function encrypt() {203              eval ${final.rage}/bin/rage $rageArgs204            }205206            created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")207            echo -n $created_at > $out/created_at208209            ${generatorText}210211            echo -n SUCCESS > $out/marker212          '')213          .overrideAttrs (old: {214            passthru = {215              generatorKind = "pure";216            };217            # TODO: make nix daemon build secret, not just the script.218            # __impure = true;219          });220      })221    ];222  };223}