git.delta.rocks / jrsonnet / refs/commits / cc4ecd613a27

difftreelog

source

modules/fleet/secrets.nix7.3 KiBsourcehistory
1{2  lib,3  fleetLib,4  config,5  ...6}: let7  inherit (fleetLib.options) mkHostsOption;8  inherit (lib.options) mkOption;9  inherit (lib.types) lazyAttrsOf unspecified nullOr listOf str bool attrsOf submodule;10  inherit (lib.lists) sort elem;11  inherit (lib.attrsets) mapAttrsToList mapAttrs filterAttrs;12  inherit (lib.strings) toJSON concatStringsSep;1314  sharedSecret = {config, ...}: {15    freeformType = lazyAttrsOf unspecified;16    options = {17      expectedOwners = mkOption {18        type = nullOr (listOf str);19        description = ''20          List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)2122          Secrets would be decrypted and stored to /run/secrets/$\{name} on owners23        '';24        default = null;25      };26      # TODO: Aren't those options may be just desugared to data/expectedData?27      regenerateOnOwnerAdded = mkOption {28        type = bool;29        description = ''30          Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.3132          You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.33        '';34      };35      regenerateOnOwnerRemoved = mkOption {36        default = config.regenerateOnOwnerAdded;37        type = bool;38        description = ''39          Should this secret be removed on owner removal, or it may be just reencrypted4041          Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.42          Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked43          in some other way than by this secret ownership, I.e by firewall/etc.44        '';45      };46      generator = mkOption {47        type = nullOr unspecified;48        description = "Derivation to evaluate for secret generation";49        default = null;50      };51      createdAt = mkOption {52        type = nullOr str;53        description = "When this secret was (re)generated";54        default = null;55      };56      expiresAt = mkOption {57        type = nullOr str;58        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";59        default = null;60      };6162      owners = mkOption {63        type = listOf str;64        description = ''65          For which owners this secret is currently encrypted,66          if not matches expectedOwners - then this secret is considered outdated, and67          should be regenerated/reencrypted.6869          Imported from fleet.nix70        '';71        default = [];72      };73    };74  };75  hostSecret = {76    freeformType = lazyAttrsOf unspecified;77    options = {78      createdAt = mkOption {79        type = nullOr str;80        default = null;81      };82      expiresAt = mkOption {83        type = nullOr str;84        default = null;85      };86    };87  };88  inherit (config) hostSecrets sharedSecrets;89in {90  options = {91    version = mkOption {92      type = str;93      internal = true;94    };95    sharedSecrets = mkOption {96      type = attrsOf (submodule sharedSecret);97      default = {};98      description = "Shared secrets";99    };100    hostSecrets = mkOption {101      type = attrsOf (attrsOf (submodule hostSecret));102      default = {};103      description = "Host secrets. Imported from fleet.nix";104      internal = true;105    };106    hosts = mkHostsOption ({config, ...}: {107      nixos = {108        secrets = let109          host = config._module.args.name;110          processSecret = v:111            (removeAttrs v ["createdAt" "expiresAt" "expectedOwners" "owners" "regenerateOnOwnerAdded" "regenerateOnOwnerRemoved"])112            // {113              shared = true;114            };115        in116          (117            mapAttrs (_: processSecret)118            (filterAttrs (_: v: elem host v.owners) sharedSecrets)119          )120          // (mapAttrs (_: processSecret) (hostSecrets.${host} or {}));121        _file = ./secrets.nix;122      };123    });124  };125  config = {126    assertions =127      mapAttrsToList128      (name: secret: {129        assertion = secret.expectedOwners == null || sort (a: b: a < b) secret.owners == sort (a: b: a < b) secret.expectedOwners;130        message = "Shared secret ${name} is expected to be encrypted for ${toJSON secret.expectedOwners}, but it is encrypted for ${toJSON secret.owners}. Run fleet secrets regenerate to fix";131      })132      config.sharedSecrets;133    nixpkgs.overlays = [134      (final: prev: {135        mkSecretGenerators = {recipients}: rec {136          # TODO: Merge both generators to one with consistent options syntax?137          # Impure generator is built on local machine, then built closure is copied to remote machine,138          # and then it is ran in inpure context, so that this generator may access HSMs and other things.139          mkImpureSecretGenerator = {140            script,141            # If set - script will be run on remote machine, otherwise it will be run with fleet project in CWD142            # (Some secrets-encryption-in-git/managed PKI solution is expected)143            impureOn ? null,144          }:145            (prev.writeShellScript "impureGenerator.sh" ''146              #!/bin/sh147              set -eu148149              export GENERATOR_HELPER_IDENTITIES="${concatStringsSep "\n" recipients}";150              export PATH=${final.fleet-generator-helper}/bin:$PATH151152              # TODO: Provide tempdir from outside, to make it securely erasurable as needed?153              tmp=$(mktemp -d)154              cd $tmp155              # cd /var/empty156157              created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")158159              ${script}160161              if ! test -d $out; then162                echo "impure generator script did not produce expected \$out output"163                exit 1164              fi165166              echo -n $created_at > $out/created_at167              echo -n SUCCESS > $out/marker168            '')169            .overrideAttrs (old: {170              passthru = {171                inherit impureOn;172                generatorKind = "impure";173              };174            });175          # Pure generators are disabled for now176          mkSecretGenerator = {script}: mkImpureSecretGenerator {inherit script;};177178          # TODO: Implement consistent naming179          # Pure secret generator is supposed to be run entirely by nix, using `__impure` derivation type...180          # But for now, it is ran the same way as `impureSecretGenerator`, but on the local machine.181          # mkSecretGenerator = {script}:182          #   (prev.writeShellScript "generator.sh" ''183          #     #!/bin/sh184          #     set -eu185          #     # TODO: make nix daemon build secret, not just the script.186          #     cd /var/empty187          #188          #     created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")189          #190          #     ${script}191          #     if ! test -d $out; then192          #       echo "impure generator script did not produce expected \$out output"193          #       exit 1194          #     fi195          #196          #     echo -n $created_at > $out/created_at197          #     echo -n SUCCESS > $out/marker198          #   '')199          #   .overrideAttrs (old: {200          #     passthru = {201          #       generatorKind = "pure";202          #     };203          #     # TODO: make nix daemon build secret, not just the script.204          #     # __impure = true;205          #   });206        };207      })208    ];209  };210}