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

difftreelog

source

modules/fleet/secrets.nix7.2 KiBsourcehistory
1{2  lib,3  fleetLib,4  config,5  ...6}: let7  inherit (fleetLib) hostsToAttrs;8  inherit (lib) mkOption mapAttrsToList mapAttrs filterAttrs concatStringsSep;9  inherit (lib.types) lazyAttrsOf unspecified nullOr listOf str bool attrsOf submodule;1011  sharedSecret = {config, ...}: {12    freeformType = lazyAttrsOf unspecified;13    options = {14      expectedOwners = mkOption {15        type = nullOr (listOf str);16        description = ''17          List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)1819          Secrets would be decrypted and stored to /run/secrets/$\{name} on owners20        '';21        default = null;22      };23      # TODO: Aren't those options may be just desugared to data/expectedData?24      regenerateOnOwnerAdded = mkOption {25        type = bool;26        description = ''27          Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.2829          You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.30        '';31      };32      regenerateOnOwnerRemoved = mkOption {33        default = config.regenerateOnOwnerAdded;34        type = bool;35        description = ''36          Should this secret be removed on owner removal, or it may be just reencrypted3738          Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.39          Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked40          in some other way than by this secret ownership, I.e by firewall/etc.41        '';42      };43      generator = mkOption {44        type = nullOr unspecified;45        description = "Derivation to evaluate for secret generation";46        default = null;47      };48      createdAt = mkOption {49        type = nullOr str;50        description = "When this secret was (re)generated";51        default = null;52      };53      expiresAt = mkOption {54        type = nullOr str;55        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";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    };71  };72  hostSecret = {73    freeformType = lazyAttrsOf unspecified;74    options = {75      createdAt = mkOption {76        type = nullOr str;77        default = null;78      };79      expiresAt = mkOption {80        type = nullOr str;81        default = null;82      };83    };84  };85in {86  options = {87    version = mkOption {88      type = str;89      default = "";90      internal = true;91    };92    sharedSecrets = mkOption {93      type = attrsOf (submodule sharedSecret);94      default = {};95      description = "Shared secrets";96    };97    hostSecrets = mkOption {98      type = attrsOf (attrsOf (submodule hostSecret));99      default = {};100      description = "Host secrets. Imported from fleet.nix";101      internal = true;102    };103  };104  config = {105    assertions =106      mapAttrsToList107      (name: secret: {108        assertion = secret.expectedOwners == null || builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;109        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";110      })111      config.sharedSecrets;112    hosts = hostsToAttrs (host: {113      nixosModules = let114        # processPart115        processSecret = v:116          (removeAttrs v ["createdAt" "expiresAt" "expectedOwners" "owners" "regenerateOnOwnerAdded" "regenerateOnOwnerRemoved"])117          // {118            shared = true;119          };120      in [121        {122          secrets =123            (124              mapAttrs (_: processSecret)125              (filterAttrs (_: v: builtins.elem host v.owners) config.sharedSecrets)126            )127            // (mapAttrs (_: processSecret) (config.hostSecrets.${host} or {}));128        }129      ];130    });131    # TODO: Should this attribute be moved to `nixpkgs.overlays`?132    overlays = [133      (final: prev: {134        mkSecretGenerators = {recipients}: rec {135          # TODO: Merge both generators to one with consistent options syntax?136          # Impure generator is built on local machine, then built closure is copied to remote machine,137          # and then it is ran in inpure context, so that this generator may access HSMs and other things.138          mkImpureSecretGenerator = {139            script,140            # If set - script will be run on remote machine, otherwise it will be run with fleet project in CWD141            # (Some secrets-encryption-in-git/managed PKI solution is expected)142            impureOn ? null,143          }:144            (prev.writeShellScript "impureGenerator.sh" ''145              #!/bin/sh146              set -eu147148              export GENERATOR_HELPER_IDENTITIES="${concatStringsSep "\n" recipients}";149              export PATH=${final.fleet-generator-helper}/bin:$PATH150151              # TODO: Provide tempdir from outside, to make it securely erasurable as needed?152              tmp=$(mktemp -d)153              cd $tmp154              # cd /var/empty155156              created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")157158              ${script}159160              if ! test -d $out; then161                echo "impure generator script did not produce expected \$out output"162                exit 1163              fi164165              echo -n $created_at > $out/created_at166              echo -n SUCCESS > $out/marker167            '')168            .overrideAttrs (old: {169              passthru = {170                inherit impureOn;171                generatorKind = "impure";172              };173            });174          # Pure generators are disabled for now175          mkSecretGenerator = {script}: mkImpureSecretGenerator {inherit script;};176177          # TODO: Implement consistent naming178          # Pure secret generator is supposed to be run entirely by nix, using `__impure` derivation type...179          # But for now, it is ran the same way as `impureSecretGenerator`, but on the local machine.180          # mkSecretGenerator = {script}:181          #   (prev.writeShellScript "generator.sh" ''182          #     #!/bin/sh183          #     set -eu184          #     # TODO: make nix daemon build secret, not just the script.185          #     cd /var/empty186          #187          #     created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")188          #189          #     ${script}190          #     if ! test -d $out; then191          #       echo "impure generator script did not produce expected \$out output"192          #       exit 1193          #     fi194          #195          #     echo -n $created_at > $out/created_at196          #     echo -n SUCCESS > $out/marker197          #   '')198          #   .overrideAttrs (old: {199          #     passthru = {200          #       generatorKind = "pure";201          #     };202          #     # TODO: make nix daemon build secret, not just the script.203          #     # __impure = true;204          #   });205        };206      })207    ];208  };209}