git.delta.rocks / jrsonnet / refs/commits / 71200382b2ad

difftreelog

source

modules/nixos/secrets.nix5.0 KiBsourcehistory
1{2  lib,3  fleetLib,4  config,5  pkgs,6  ...7}:8let9  inherit (builtins) hashString;10  inherit (lib.stringsWithDeps) stringAfter;11  inherit (lib.options) mkOption literalExpression;12  inherit (lib.lists) optional;13  inherit (lib.attrsets) mapAttrs;14  inherit (lib.modules) mkIf;15  inherit (lib.types)16    submodule17    str18    attrsOf19    nullOr20    unspecified21    lazyAttrsOf22    uniq23    functionTo24    package25    ;26  inherit (fleetLib.strings) decodeRawSecret;2728  sysConfig = config;29  secretPartType =30    secretName:31    submodule (32      { config, ... }:33      let34        partName = config._module.args.name;35      in36      {37        options = {38          raw = mkOption {39            type = str;40            internal = true;41            description = "Encoded & Encrypted secret part data, passed from fleet.nix";42          };43          hash = mkOption {44            type = str;45            description = "Hash of secret in encoded format";46          };47          path = mkOption {48            type = str;49            description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";50          };51          stablePath = mkOption {52            type = str;53            description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";54          };55          data = mkOption {56            type = str;57            description = "Secret public data (only available for plaintext)";58          };59        };60        config = {61          hash = hashString "sha1" config.raw;62          data = decodeRawSecret config.raw;63          path = "/run/secrets/${secretName}/${config.hash}-${partName}";64          stablePath = "/run/secrets/${secretName}/${partName}";65        };66      }67    );68  secretType = submodule (69    { config, ... }:70    let71      secretName = config._module.args.name;72    in73    {74      freeformType = lazyAttrsOf (secretPartType secretName);75      options = {76        shared = mkOption {77          description = "Is this secret owned by this machine, or propagated from shared secrets";78          default = false;79        };8081        generator = mkOption {82          type = uniq (nullOr (functionTo package));83          description = "Derivation to evaluate for secret generation";84          default = null;85        };86        mode = mkOption {87          type = str;88          description = "Secret mode";89          default = "0440";90        };91        owner = mkOption {92          type = str;93          description = "Owner of the secret";94          default = "root";95        };96        group = mkOption {97          type = str;98          description = "Group of the secret";99          default = sysConfig.users.users.${config.owner}.group;100          defaultText = literalExpression "config.users.users.$${owner}.group";101        };102        expectedGenerationData = mkOption {103          type = unspecified;104          description = "Data that gets embedded into secret part";105          default = null;106        };107      };108    }109  );110  processPart = part: {111    inherit (part) raw path stablePath;112  };113  processSecret =114    secret:115    {116      inherit (secret) group mode owner;117    }118    // (mapAttrs (_: processPart) (119      removeAttrs secret [120        "shared"121        "generator"122        "mode"123        "group"124        "owner"125        "expectedGenerationData"126      ]127    ));128  secretsFile = pkgs.writeTextFile {129    name = "secrets.json";130    text = builtins.toJSON (mapAttrs (_: processSecret) config.secrets);131  };132  useSysusers =133    (config.systemd ? sysusers && config.systemd.sysusers.enable)134    || (config ? userborn && config.userborn.enable);135in136{137  options = {138    secrets = mkOption {139      type = attrsOf secretType;140      default = { };141      description = "Host-local secrets";142    };143  };144  config = {145    environment.systemPackages = [ pkgs.fleet-install-secrets ];146147    systemd.services.fleet-install-secrets = mkIf useSysusers {148      wantedBy = [ "sysinit.target" ];149      after = [ "systemd-sysusers.service" ];150      restartTriggers = [151        secretsFile152      ];153      aliases = [154        "sops-install-secrets"155        "agenix-install-secrets"156      ];157158      unitConfig.DefaultDependencies = false;159160      serviceConfig = {161        Type = "oneshot";162        RemainAfterExit = true;163        ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";164      };165    };166    system.activationScripts.decryptSecrets = mkIf (!useSysusers) (167      stringAfter168        (169          [170            # secrets are owned by user/group, thus we need to refer to those171            "users"172            "groups"173            "specialfs"174          ]175          # nixos-impermanence compatibility: secrets are encrypted by host-key,176          # but with impermanence we expect that the host-key is installed by177          # persist-file activation script.178          ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")179        )180        ''181          1>&2 echo "setting up secrets"182          ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}183        ''184    );185  };186}