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

difftreelog

source

nixos/secrets.nix5.2 KiBsourcehistory
1{2  lib,3  config,4  pkgs,5  ...6}: let7  inherit (lib.strings) hasPrefix removePrefix;8  inherit (lib.stringsWithDeps) stringAfter;9  inherit (lib.options) mkOption;10  inherit (lib.lists) optional;11  inherit (lib.attrsets) mapAttrs;12  inherit (lib.modules) mkOptionDefault mkIf;13  inherit (lib.types) submodule str attrsOf nullOr unspecified lazyAttrsOf;14  plaintextPrefix = "<PLAINTEXT>";15  plaintextNewlinePrefix = "<PLAINTEXT-NL>";1617  sysConfig = config;18  secretPartType = secretName:19    submodule ({config, ...}: {20      options = {21        raw = mkOption {22          description = "Secret in fleet-specific undocumented format, do not use. Import from fleet.nix";23          internal = true;24        };25        hash = mkOption {26          type = str;27          description = "Hash of secret in encoded format";28        };29        path = mkOption {30          type = str;31          description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";32        };33        stablePath = mkOption {34          type = str;35          description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";36        };37        data = mkOption {38          type = str;39          description = "Secret public data (only available for plaintext)";40        };41      };42      config = let43        partName = config._module.args.name;44      in {45        hash = mkOptionDefault (builtins.hashString "sha1" config.raw);46        data = mkOptionDefault (47          if hasPrefix plaintextPrefix config.raw48          then removePrefix plaintextPrefix config.raw49          else if hasPrefix plaintextNewlinePrefix config.raw50          then removePrefix plaintextNewlinePrefix config.raw51          else throw "secret.part.data attribute only works for public plaintext secret parts, got ${config.raw}"52        );53        path = mkOptionDefault "/run/secrets/${secretName}/${config.hash}-${partName}";54        stablePath = mkOptionDefault "/run/secrets/${secretName}/${partName}";55      };56    });57  secretType = submodule ({config, ...}: let58    secretName = config._module.args.name;59  in {60    freeformType = lazyAttrsOf (secretPartType secretName);61    options = {62      shared = mkOption {63        description = "Is this secret owned by this machine, or propagated from shared secrets";64        default = false;65      };66      expectedOwners = mkOption {67        type = nullOr unspecified;68        default = null;69        internal = true;70      };7172      generator = mkOption {73        type = nullOr unspecified;74        description = "Derivation to evaluate for secret generation";75        default = null;76      };77      mode = mkOption {78        type = str;79        description = "Secret mode";80        default = "0440";81      };82      owner = mkOption {83        type = str;84        description = "Owner of the secret";85        default = "root";86      };87      group = mkOption {88        type = str;89        description = "Group of the secret";90        default = sysConfig.users.users.${config.owner}.group;91      };92    };93  });94  processPart = part: {95    inherit (part) raw path stablePath;96  };97  processSecret = secret:98    {99      inherit (secret) group mode owner;100    }101    // (mapAttrs (_: processPart) (removeAttrs secret [102      "shared"103      "generator"104      "mode"105      "group"106      "owner"107108      # FIXME: Some of those removed attributes shouldn't be here, but there is some error in passing shared secrets from fleet to nixos.109      "expectedOwners"110    ]));111  secretsFile = pkgs.writeTextFile {112    name = "secrets.json";113    text =114      builtins.toJSON (mapAttrs (_: processSecret)115        config.secrets);116  };117  useSysusers = (config.systemd ? sysusers && config.systemd.sysusers.enable) || (config ? userborn && config.userborn.enable);118in {119  options = {120    secrets = mkOption {121      type = attrsOf secretType;122      default = {};123      description = "Host-local secrets";124    };125  };126  config = {127    environment.systemPackages = [pkgs.fleet-install-secrets];128129    systemd.services.fleet-install-secrets = mkIf useSysusers {130      wantedBy = ["sysinit.target"];131      after = ["systemd-sysusers.service"];132      restartTriggers = [133        secretsFile134      ];135      aliases = [136        "sops-install-secrets"137        "agenix-install-secrets"138      ];139140      unitConfig.DefaultDependencies = false;141142      serviceConfig = {143        Type = "oneshot";144        RemainAfterExit = true;145        ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";146      };147    };148    system.activationScripts.decryptSecrets =149      mkIf (!useSysusers)150      (151        stringAfter (152          [153            # secrets are owned by user/group, thus we need to refer to those154            "users"155            "groups"156            "specialfs"157          ]158          # nixos-impermanence compatibility: secrets are encrypted by host-key,159          # but with impermanence we expect that the host-key is installed by160          # persist-file activation script.161          ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")162        ) ''163          1>&2 echo "setting up secrets"164          ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}165        ''166      );167  };168}