diff --git a/hosts/elisabeth/secrets/vaultwarden/generated/maddyPasswd.age b/hosts/elisabeth/secrets/vaultwarden/generated/maddyPasswd.age new file mode 100644 index 0000000..cd92789 Binary files /dev/null and b/hosts/elisabeth/secrets/vaultwarden/generated/maddyPasswd.age differ diff --git a/hosts/elisabeth/secrets/vaultwarden/vaultwarden-env.age b/hosts/elisabeth/secrets/vaultwarden/vaultwarden-env.age index 43b954a..a546320 100644 Binary files a/hosts/elisabeth/secrets/vaultwarden/vaultwarden-env.age and b/hosts/elisabeth/secrets/vaultwarden/vaultwarden-env.age differ diff --git a/modules/config/default.nix b/modules/config/default.nix index 00deb00..e542515 100644 --- a/modules/config/default.nix +++ b/modules/config/default.nix @@ -22,6 +22,7 @@ ../meta.nix ../smb-mounts.nix ../deterministic-ids.nix + ../distributed-config.nix ../optional/iwd.nix ./impermanence diff --git a/modules/distributed-config.nix b/modules/distributed-config.nix new file mode 100644 index 0000000..c1f8d2a --- /dev/null +++ b/modules/distributed-config.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + nodes, + ... +}: let + inherit + (lib) + attrNames + concatMap + concatStringsSep + foldl' + getAttrFromPath + mkMerge + mkOption + mkOptionType + optionals + recursiveUpdate + setAttrByPath + types + ; + + nodeName = config.node.name; + mkForwardedOption = path: + mkOption { + type = mkOptionType { + name = "Same type that the receiving option `${concatStringsSep "." path}` normally accepts."; + merge = _loc: defs: + builtins.filter + (x: builtins.isAttrs x -> ((x._type or "") != "__distributed_config_empty")) + (map (x: x.value) defs); + }; + default = {_type = "__distributed_config_empty";}; + description = '' + Anything specified here will be forwarded to `${concatStringsSep "." path}` + on the given node. Forwarding happens as-is to the raw values, + so validity can only be checked on the receiving node. + ''; + }; + + forwardedOptions = [ + ["age" "secrets"] + ["services" "maddy" "ensureCredentials"] + ]; + + attrsForEachOption = f: (foldl' (acc: path: recursiveUpdate acc (setAttrByPath path (f path))) {} forwardedOptions); +in { + options.nodes = mkOption { + description = "Options forwareded to the given node."; + default = {}; + type = types.attrsOf (types.submodule { + options = attrsForEachOption mkForwardedOption; + }); + }; + + config = let + mergeConfigFromOthers = let + getConfig = path: otherNode: let + cfg = nodes.${otherNode}.config.nodes.${nodeName} or null; + in + optionals (cfg != null) (getAttrFromPath path cfg); + in + path: mkMerge (concatMap (getConfig path) (attrNames nodes)); + in + attrsForEachOption mergeConfigFromOthers; +} diff --git a/modules/services/vaultwarden.nix b/modules/services/vaultwarden.nix index f281847..1600528 100644 --- a/modules/services/vaultwarden.nix +++ b/modules/services/vaultwarden.nix @@ -1,6 +1,7 @@ { config, lib, + nodes, ... }: let vaultwardenDomain = "pw.${config.secrets.secrets.global.domains.web}"; @@ -51,6 +52,29 @@ in { ]; }; }; + age.secrets.maddyPasswd = { + generator.script = "alnum"; + group = "vaultwarden"; + }; + + nodes.maddy = { + age.secrets.vaultwardenPasswd = { + inherit (config.age.secrets.maddyPasswd) rekeyFile; + inherit (nodes.maddy.config.services.maddy) group; + mode = "640"; + }; + services.maddy.ensureCredentials = { + "vaultwarden@${config.secrets.secrets.global.domains.mail_public}".passwordFile = nodes.maddy.config.age.secrets.vaultwardenPasswd.path; + }; + }; + system.activationScripts.systemd_env_smtp_passwd = { + text = '' + echo "SMTP_PASSWORD=$(< ${lib.escapeShellArg config.age.secrets.maddyPasswd.path})" > /run/vaultwarden_smtp_passwd + ''; + deps = ["agenix"]; + }; + + systemd.services.vaultwarden.serviceConfig.EnvironmentFile = ["/run/vaultwarden_smtp_passwd"]; services.vaultwarden = { enable = true; @@ -71,9 +95,12 @@ in { invitationOrgName = "Vaultwarden"; domain = "https://${vaultwardenDomain}"; - smtpEmbedImages = true; - smtpSecurity = "force_tls"; + smtpHost = "smtp.${config.secrets.secrets.global.domains.mail_public}"; + smtpFrom = "vaultwarden@${config.secrets.secrets.global.domains.mail_public}"; smtpPort = 465; + smtpSecurity = "force_tls"; + smtpUsername = "vaultwarden@${config.secrets.secrets.global.domains.mail_public}"; + smtpEmbedImages = true; }; environmentFile = config.age.secrets.vaultwarden-env.path; };