From 10ca56c064064be56d131528833541c8003db1cb Mon Sep 17 00:00:00 2001 From: Gonne Date: Sun, 2 Mar 2025 11:44:08 +0100 Subject: [PATCH] Enable DKIM signing --- nixos/machines/nyarlathotep/configuration.nix | 12 +++++ nixos/machines/nyarlathotep/dkim.keys.yaml | 40 +++++++++++++++ nixos/modules/mail.nix | 50 +++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 nixos/machines/nyarlathotep/dkim.keys.yaml diff --git a/nixos/machines/nyarlathotep/configuration.nix b/nixos/machines/nyarlathotep/configuration.nix index 39fd189..762224c 100644 --- a/nixos/machines/nyarlathotep/configuration.nix +++ b/nixos/machines/nyarlathotep/configuration.nix @@ -75,6 +75,18 @@ group = "stalwart-mail"; mode = "0440"; }; + "dkim_rsa" = { + sopsFile = ./dkim.keys.yaml; + owner = "stalwart-mail"; + group = "stalwart-mail"; + mode = "0440"; + }; + "dkim_ed25519" = { + sopsFile = ./dkim.keys.yaml; + owner = "stalwart-mail"; + group = "stalwart-mail"; + mode = "0440"; + }; # password for https://stalw.art/docs/auth/authorization/administrator/#fallback-administrator encoded to be supplied in the basic auth header stalwartAdmin = { sopsFile = ./stalwartAdmin.secrets.yaml; diff --git a/nixos/machines/nyarlathotep/dkim.keys.yaml b/nixos/machines/nyarlathotep/dkim.keys.yaml new file mode 100644 index 0000000..a923ce2 --- /dev/null +++ b/nixos/machines/nyarlathotep/dkim.keys.yaml @@ -0,0 +1,40 @@ +dkim_rsa: ENC[AES256_GCM,data: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,iv:QbZVXp5FQhmYZvXxXNxWKrNm5GqM+2P3a5pPk499mlc=,tag:F+KNoPRnoLLhOpEj6Czj6Q==,type:str] +dkim_ed25519: ENC[AES256_GCM,data:cZHm7bVpQ/VhYLt2CnNk9364k+J5ybgSLrR7Vm1GsCU6JcAvHl8Y5R7mqwgS+gTnHX7K02GuIGXa8909/aEotE0ZMY5irKJ25SGJqTaqQafbiMOz65CRQh5trtcMBF4s4wRYOkDGgz09KkELbkDHyQZFcrGqvgM=,iv:p9ROj/epqR3xtrimXF1onJJHH9JUqNG9z1MxKVu9uPg=,tag:m53rXkcu+ernS5JX+k8YcA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1rasjnr2tlv9y70sj0z0hwpgpxdc974wzg5umtx2pnc6z0p05u3js6r8sln + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6VnhvWHdsZWNHemlueFo4 + L0xCTGp4NlRuU3YwRWJiSHFBbmtURTNMQkVRCnlSbFc0Q2xINjRvU2tQeStQc1U5 + VElxcTVuNm9MUm01RkpGYytrYWg0czgKLS0tIHZqUWhkMGRNNjJvUTQrOHBpZXVS + NlpjeDQxbVZIRHFCcmNtT1JSVHp1K2sKSNcC0fcOar/KKzs1twaozB8wfdFT9OdB + 4quV/ycNpJpfs6+2r0RTLBxYFyusybu1swosAni+PJsRXS82+PTXHQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1epz92k2rkp43hkrg3u0jgkzhnkwx8y43kag7rvfzwl9wcddelvusyetxl7 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsUTUzYzZuMkYvcTlrUmRK + aStnak5IWitFUSt0eVBQOHIzcTlrMFRFTjA4CmlYUTdobXFUK2tYMWtFekNqNnhp + R2RRRFdHc1p6bFVjYU9lbTRBeEM3Y2sKLS0tIHdsRW1wR25pVkZIYU1yMm9sQXpr + NFhiN0pyaHVWT1h5eVFXMWZDb0sxUGMKIVkYYheD8F9aaAyCA+m9ZGlV8vKbAW4r + H6FUe+ats30abxoYfHZfMJv17BxJtpodksSxWjnPYm0dfRf/EF/vSQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1ktwclxa640l89le6yecm8v2z6hmwr4lusd6x9gyzamhv57887szqtqp59a + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvU3NzY0Uxc0NhY2xJZyti + TCtTS1crV3hzMXZNV3k4cm0zUFNuY2tBL0dNCnNpYytoaUI1eERhdG1PUlZ2eE5C + R2UrVlBwcXR2L1VNR3RJL1lEQmlTSDgKLS0tIFJyLzhZeG5zejFmL2VkYy8xVEM1 + U3QwOXlRdU8yd3ozL2hUVzRXNGE0bDQKT7SLAqICsbFmRUF+3s2avpBt0dLUbHLX + AgQzx5v6GpMMNwCkCrOnpFX6al7zkRSYHe7hbn03BBORz9mPHek5ew== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-03-02T07:58:00Z" + mac: ENC[AES256_GCM,data:OvERjDFfHTJbTfwq9BmXBQy6pjeyIhao6zP4we0KeYL3skbw4+aaMixjUFzjauby0C7nJjEPBSk6pwK3lN+rScS5g7J8tTNtmhfEDQbfsS5zNDKzIQjYxbUbDr2cTPWwCA73gRGMwLbyNvdfuEp46jNV8OJ8km/y2nyG9lDcBb4=,iv:0RSU2MdZWiYEapwXGzevP9/vc/Sk1MS6a0MnCRQyIs8=,tag:vvngXS2IRzH999yzo4JyFQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.4 diff --git a/nixos/modules/mail.nix b/nixos/modules/mail.nix index 2791b74..391778f 100644 --- a/nixos/modules/mail.nix +++ b/nixos/modules/mail.nix @@ -108,6 +108,15 @@ in { iprev.verify = "relaxed"; spf.verify.ehlo = "relaxed"; spf.verify.mail-from = "relaxed"; + + # Sign *our* outgoing mails with the configured signatures. + dkim.sign = [ + { + "if" = "is_local_domain('', sender_domain) || sender_domain == 'lists.mathebau.de'"; + "then" = "['rsa-' + sender_domain, 'ed25519-' + sender_domain]"; + } + {"else" = false;} + ]; }; # Forward outgoing mail to HRZ or mail VMs. @@ -202,12 +211,53 @@ in { sieve.trusted.from-addr = "sender"; # set the from-address to the original sender as specified in the MAIL FROM. sieve.trusted.from-name = "sender"; sieve.trusted.return-path = "sender"; + # If we are the sender, we sign the message with DKIM. Else we leave it alone. + sieve.trusted.sign = [ + { + "if" = "is_local_domain('', sender_domain) || sender_domain == 'lists.mathebau.de'"; + "then" = "['rsa-' + sender_domain, 'ed25519-' + sender_domain]"; + } + {"else" = false;} + ]; sieve.trusted.limits = { redirects = 50; out-messages = 50; }; session.data.script = "'redirects'"; + # See https://stalw.art/docs/smtp/authentication/dkim/sign + # We need two blocks per domain because the domain setting in the blocks does not accept variables like `sender_domain`. + signature = let + signatureTemplate = domain: { + "rsa-${domain}" = { + private-key = "%{file:/run/secrets/dkim_rsa}%"; + domain = "${domain}"; + selector = "rsa-default"; + headers = ["From" "To" "Cc" "Date" "Subject" "Message-ID" "Organization" "MIME-Version" "Content-Type" "In-Reply-To" "References" "List-Id" "User-Agent" "Thread-Topic" "Thread-Index"]; + algorithm = "rsa-sha256"; + canonicalization = "relaxed/relaxed"; + }; + "ed25519-${domain}" = { + private-key = "%{file:/run/secrets/dkim_ed25519}%"; + domain = "${domain}"; + selector = "ed-default"; + headers = ["From" "To" "Cc" "Date" "Subject" "Message-ID" "Organization" "MIME-Version" "Content-Type" "In-Reply-To" "References" "List-Id" "User-Agent" "Thread-Topic" "Thread-Index"]; + algorithm = "ed25519-sha256"; + canonicalization = "relaxed/relaxed"; + }; + }; + in + map signatureTemplate (["lists.mathebau.de"] ++ (map ({domain, ...}: domain) cfg.domains)); + + # Sign *our* outgoing mails with the configured signatures. + auth.dkim.sign = [ + { + "if" = "is_local_domain('', sender_domain) || sender_domain == 'lists.mathebau.de'"; + "then" = "['rsa-' + sender_domain, 'ed25519-' + sender_domain]"; + } + {"else" = false;} + ]; + authentication.fallback-admin = { user = "admin"; # see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH