1{ lib, config, pkgs, ... }:23with lib;45let6 sysConfig = config;7 secretType = types.submodule ({ config, ... }: {8 config = let secretName = config._module.args.name; in rec {9 stableSecretPath = mkOptionDefault "/run/secrets/secret-stable-${secretName}";10 secretPath = mkOptionDefault "/run/secrets/secret-${config.secretHash}-${secretName}";11 secretHash = mkOptionDefault (if config.secret != null then (builtins.hashString "sha1" config.secret) else throw "secret is not defined for secret ${secretName}");1213 stablePublicPath = mkOptionDefault "/run/secrets/public-stable-${secretName}";14 publicPath = mkOptionDefault "/run/secrets/public-${config.publicHash}-${secretName}";15 publicHash = mkOptionDefault (if config.public != null then (builtins.hashString "sha1" config.public) else throw "public is not defined for secret ${secretName}");16 };17 options = {18 public = mkOption {19 type = types.nullOr types.str;20 description = "Secret public data";21 default = null;22 };23 secret = mkOption {24 type = types.nullOr types.str;25 description = "Encrypted secret data";26 default = null;27 };28 mode = mkOption {29 type = types.str;30 description = "Secret mode";31 default = "0440";32 };33 owner = mkOption {34 type = types.str;35 description = "Owner of the secret";36 default = "root";37 };38 group = mkOption {39 type = types.str;40 description = "Group of the secret";41 default = sysConfig.users.users.${config.owner}.group;42 };4344 secretHash = mkOption {45 type = types.str;46 description = "Hash of .secret field";47 };48 publicHash = mkOption {49 type = types.str;50 description = "Hash of .public field";51 };5253 stableSecretPath = mkOption {54 type = types.str;55 description = ''56 Use this, if target process supports re-reading of secret from disk,57 and doesn't needs to be restarted when secret is updated in file58 '';59 };60 secretPath = mkOption {61 type = types.str;62 description = "Path to decrypted secret, suffixed with contents hash";63 };6465 stablePublicPath = mkOption {66 type = types.str;67 description = ''68 Use this, if target process supports re-reading of secret from disk,69 and doesn't needs to be restarted when secret is updated in file70 '';71 };72 publicPath = mkOption {73 type = types.str;74 description = "Path to the public part of secret";75 };76 };77 });78 secretsFile = pkgs.writeTextFile {79 name = "secrets.json";80 text = builtins.toJSON (mapAttrs (_: value: rec {81 inherit (value) group mode owner secret public;82 publicPath = if public != null then value.publicPath else "/missingno";83 stablePublicPath = if public != null then value.stablePublicPath else "/missingno";84 secretPath = if secret != null then value.secretPath else "/missingno";85 stableSecretPath = if secret != null then value.stableSecretPath else "/missingno";86 }) config.secrets);87 };88in89{90 options = {91 secrets = mkOption {92 type = types.attrsOf secretType;93 default = { };94 description = "Host-local secrets";95 };96 };97 config = {98 environment.systemPackages = with pkgs; [pkgs.fleet-install-secrets];99 system.activationScripts.decryptSecrets = stringAfter [ "users" "groups" "specialfs" ] ''100 1>&2 echo "setting up secrets"101 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}102 '';103 };104}