difftreelog
feat ensure shared generators
in: trunk
2 files changed
modules/nixos.nixdiffbeforeafterboth--- a/modules/nixos.nix
+++ b/modules/nixos.nix
@@ -21,7 +21,7 @@
options = {
nixos = mkOption {
description = ''
- Nixos configuration for all hosts.
+ Shared nixos configuration module for all hosts.
'';
type = deferredModule;
};
@@ -76,6 +76,7 @@
nixosHosts = mapAttrs (_: value: value.nixos_unchecked.config) config.hosts;
hosts = config.hosts;
host = hostArgs.config;
+ fleetConfiguration = config;
};
};
nixos_unchecked = hostArgs.config.nixos.extendModules {
modules/nixos/secrets.nixdiffbeforeafterboth1{2 lib,3 fleetLib,4 config,5 pkgs,6 ...7}:8let9 inherit (builtins)10 hashString11 toJSON12 ;13 inherit (lib.stringsWithDeps) stringAfter;14 inherit (lib.options) mkOption literalExpression;15 inherit (lib.lists) optional;16 inherit (lib.attrsets) mapAttrs;17 inherit (lib.modules) mkIf;18 inherit (lib.types)19 submodule20 str21 attrsOf22 unspecified23 uniq24 functionTo25 package26 ;27 inherit (fleetLib.strings) decodeRawSecret;2829 sysConfig = config;30 secretPartType =31 secretName:32 submodule (33 { config, ... }:34 let35 partName = config._module.args.name;36 in37 {38 options = {39 hash = mkOption {40 type = str;41 description = "Hash of secret in encoded format";42 };43 path = mkOption {44 type = str;45 description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";46 };47 stablePath = mkOption {48 type = str;49 description = "Path to secret part, stable path (users are expected to watch for file changes/re-read secret on demand)";50 };51 data = mkOption {52 type = str;53 description = "Secret public data (only available for plaintext)";54 };55 raw = mkOption {56 type = str;57 description = "Raw (encoded/encrypted secret part data)";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 {70 config,71 ...72 }:73 let74 secretName = config._module.args.name;75 in76 {77 options = {78 parts = mkOption {79 type = uniq (attrsOf (secretPartType secretName));80 description = "Definition of secret parts";81 };82 generator = mkOption {83 type = uniq (functionTo package);84 description = "Derivation to evaluate for secret generation";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 };103 config = {104 # C api is broken in regard to thunks105 # https://github.com/NixOS/nix/issues/12800106 parts = let 107 hostName = sysConfig.networking.hostName;108 generator = config.generator;109 in builtins.deepSeq [110 hostName111 secretName112 generator113 ] (builtins.fleetEnsureHostSecret114 hostName115 secretName116 generator);117 };118 }119 );120 secretsFile = pkgs.writeTextFile {121 name = "secrets.json";122 text = toJSON config.system.secretsData;123 };124 useSysusers =125 (config.systemd ? sysusers && config.systemd.sysusers.enable)126 || (config ? userborn && config.userborn.enable);127in128{129 options = {130 secrets = mkOption {131 type = attrsOf secretType;132 default = { };133 apply = mapAttrs (_: secret: secret.parts // {definition = secret;});134 description = "Host-local secrets";135 };136 system.secretsData = mkOption {137 type = unspecified;138 default = mapAttrs (_: s:139 (removeAttrs s.definition ["generator"]) // {140 parts = mapAttrs (_: part: removeAttrs part ["data"]) s.definition.parts;141 }142 ) config.secrets;143 description = "secrets.json contents";144 };145 };146 config = {147 environment.systemPackages = [ pkgs.fleet-install-secrets ];148149 systemd.services.fleet-install-secrets = mkIf useSysusers {150 wantedBy = [ "sysinit.target" ];151 after = [ "systemd-sysusers.service" ];152 restartTriggers = [153 secretsFile154 ];155 aliases = [156 "sops-install-secrets"157 "agenix-install-secrets"158 ];159160 unitConfig.DefaultDependencies = false;161162 serviceConfig = {163 Type = "oneshot";164 RemainAfterExit = true;165 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";166 };167 };168 system.activationScripts.decryptSecrets = mkIf (!useSysusers) (169 stringAfter170 (171 [172 # secrets are owned by user/group, thus we need to refer to those173 "users"174 "groups"175 "specialfs"176 ]177 # nixos-impermanence compatibility: secrets are encrypted by host-key,178 # but with impermanence we expect that the host-key is installed by179 # persist-file activation script.180 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")181 )182 ''183 1>&2 echo "setting up secrets"184 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}185 ''186 );187 };188}1{2 lib,3 fleetLib,4 config,5 pkgs,6 fleetConfiguration,7 ...8}:9let10 inherit (builtins)11 hashString12 toJSON13 ;14 inherit (lib.stringsWithDeps) stringAfter;15 inherit (lib.options) mkOption literalExpression;16 inherit (lib.lists) optional;17 inherit (lib.attrsets) mapAttrs mapAttrsToList;18 inherit (lib.modules) mkIf;19 inherit (lib.types)20 submodule21 str22 attrsOf23 unspecified24 uniq25 functionTo26 package27 bool28 enum29 either30 ;31 inherit (fleetLib.strings) decodeRawSecret;3233 sysConfig = config;34 secretPartType =35 secretName:36 submodule (37 { config, ... }:38 let39 partName = config._module.args.name;40 in41 {42 options = {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, stable path (users are expected to watch for file changes/re-read secret on demand)";54 };55 data = mkOption {56 type = str;57 description = "Secret public data (only available for plaintext)";58 };59 raw = mkOption {60 type = str;61 description = "Raw (encoded/encrypted secret part data)";62 };63 };64 config = {65 hash = hashString "sha1" config.raw;66 data = decodeRawSecret config.raw;67 path = "/run/secrets/${secretName}/${config.hash}-${partName}";68 stablePath = "/run/secrets/${secretName}/${partName}";69 };70 }71 );72 secretType = submodule (73 {74 config,75 ...76 }:77 let78 secretName = config._module.args.name;79 literal = l: enum [l];80 in81 {82 options = {83 parts = mkOption {84 type = uniq (attrsOf (secretPartType secretName));85 description = "Definition of secret parts";86 };87 generator = mkOption {88 type = either (functionTo package) (literal "shared");89 description = "Derivation to evaluate for secret generation";90 };91 mode = mkOption {92 type = str;93 description = "Secret mode";94 default = "0440";95 };96 owner = mkOption {97 type = str;98 description = "Owner of the secret";99 default = "root";100 };101 group = mkOption {102 type = str;103 description = "Group of the secret";104 default = sysConfig.users.users.${config.owner}.group;105 defaultText = literalExpression "config.users.users.$${owner}.group";106 };107 };108 config = {109 # C api is broken in regard to thunks110 # https://github.com/NixOS/nix/issues/12800111 parts = let 112 hostName = sysConfig.networking.hostName;113 generator = config.generator;114 in builtins.deepSeq [115 hostName116 secretName117 generator118 ] (builtins.fleetEnsureHostSecret119 hostName120 secretName121 generator);122 };123 }124 );125 secretsFile = pkgs.writeTextFile {126 name = "secrets.json";127 text = toJSON config.system.secretsData;128 };129 useSysusers =130 (config.systemd ? sysusers && config.systemd.sysusers.enable)131 || (config ? userborn && config.userborn.enable);132in133{134 options = {135 secrets = mkOption {136 type = attrsOf secretType;137 default = { };138 apply = mapAttrs (_: secret: secret.parts // {definition = secret;});139 description = "Host-local secrets";140 };141 system.secretsData = mkOption {142 type = unspecified;143 default = mapAttrs (_: s:144 (removeAttrs s.definition ["generator"]) // {145 parts = mapAttrs (_: part: removeAttrs part ["data"]) s.definition.parts;146 }147 ) config.secrets;148 description = "secrets.json contents";149 };150 };151 config = {152 environment.systemPackages = [ pkgs.fleet-install-secrets ];153154 assertions = mapAttrsToList (name: secret: let155 hasSharedDefinition = fleetConfiguration.secrets ? name;156 in {157 assertion = (secret.definition.generator == "shared") == hasSharedDefinition;158 message = if hasSharedDefinition then"secret ${name} has host-specific secret generator, secrets with host-specific generators can not have shared generator in fleet configuration"159 else "secret ${name} is declared as shared, for shared secret fleet configuration should include shared secret generator";160 }) config.secrets;161162 systemd.services.fleet-install-secrets = mkIf useSysusers {163 wantedBy = [ "sysinit.target" ];164 after = [ "systemd-sysusers.service" ];165 restartTriggers = [166 secretsFile167 ];168 aliases = [169 "sops-install-secrets"170 "agenix-install-secrets"171 ];172173 unitConfig.DefaultDependencies = false;174175 serviceConfig = {176 Type = "oneshot";177 RemainAfterExit = true;178 ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";179 };180 };181 system.activationScripts.decryptSecrets = mkIf (!useSysusers) (182 stringAfter183 (184 [185 # secrets are owned by user/group, thus we need to refer to those186 "users"187 "groups"188 "specialfs"189 ]190 # nixos-impermanence compatibility: secrets are encrypted by host-key,191 # but with impermanence we expect that the host-key is installed by192 # persist-file activation script.193 ++ (optional (config.system.activationScripts ? "persist-files") "persist-files")194 )195 ''196 1>&2 echo "setting up secrets"197 ${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}198 ''199 );200 };201}