From 12fd7ebc41f8647fdda34b74e8bdaa225e7ea19b Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 20 Apr 2023 09:43:39 +0000 Subject: [PATCH] email: split dovecot config out of postfix config --- .../by-name/servo/services/email/default.nix | 31 +++++++ .../by-name/servo/services/email/dovecot.nix | 81 +++++++++++++++++ .../by-name/servo/services/email/postfix.nix | 91 +------------------ 3 files changed, 114 insertions(+), 89 deletions(-) create mode 100644 hosts/by-name/servo/services/email/dovecot.nix diff --git a/hosts/by-name/servo/services/email/default.nix b/hosts/by-name/servo/services/email/default.nix index 10d99436..c2b46173 100644 --- a/hosts/by-name/servo/services/email/default.nix +++ b/hosts/by-name/servo/services/email/default.nix @@ -1,6 +1,37 @@ +# nix configs to reference: +# - +# - +# - postfix / dovecot / rspamd / stalwart-jmap / sogo +# +# rspamd: +# - nixos: +# - guide: +# - non-nixos example: +# +# +# my rough understanding of the pieces: +# - postfix handles SMTP protocol with the rest of the world. +# - dovecot implements IMAP protocol. +# - client auth (i.e. validate that user@uninsane.org is who they claim) +# - "folders" (INBOX, JUNK) are internal to dovecot? +# or where do folders live, on-disk? +# +# - non-local clients (i.e. me) interact with BOTH postfix and dovecot, but primarily dovecot: +# - mail reading is done via IMAP (so, dovecot) +# - mail sending is done via SMTP/submission port (so, postfix) +# - but postfix delegates authorization of that outgoing mail to dovecot, on the server side +# +# - local clients (i.e. sendmail) interact only with postfix + { ... }: { imports = [ + ./dovecot.nix ./postfix.nix ]; + + + #### SPAM FILTERING + # services.rspamd.enable = true; + # services.rspamd.postfix.enable = true; } diff --git a/hosts/by-name/servo/services/email/dovecot.nix b/hosts/by-name/servo/services/email/dovecot.nix new file mode 100644 index 00000000..7c59f75f --- /dev/null +++ b/hosts/by-name/servo/services/email/dovecot.nix @@ -0,0 +1,81 @@ +# dovecot config options: +{ config, ... }: +{ + networking.firewall.allowedTCPPorts = [ + # exposed over non-vpn imap.uninsane.org + 143 # IMAP + 993 # IMAPS + ]; + + # exists only to manage certs for dovecot + services.nginx.virtualHosts."imap.uninsane.org" = { + enableACME = true; + }; + + sane.services.trust-dns.zones."uninsane.org".inet = { + CNAME."imap" = "native"; + }; + + sops.secrets."dovecot_passwd" = { + owner = config.users.users.dovecot2.name; + # TODO: debug why mail can't be sent without this being world-readable + mode = "0444"; + }; + + # inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/ + services.dovecot2.enable = true; + services.dovecot2.mailboxes = { + # special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash" + # RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html + # how these boxes are treated is 100% up to the client and server to decide. + # client behavior: + # iOS + # - Drafts: ? + # - Sent: works + # - Trash: works + # - Junk: ? + # aerc + # - Drafts: works + # - Sent: works + # - Trash: no; deleted messages are actually deleted + # use `:move trash` instead + # - Junk: ? + # Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side. + Drafts = { specialUse = "Drafts"; auto = "create"; }; + Sent = { specialUse = "Sent"; auto = "create"; }; + Trash = { specialUse = "Trash"; auto = "create"; }; + Junk = { specialUse = "Junk"; auto = "create"; }; + }; + services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem"; + services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem"; + services.dovecot2.enablePAM = false; + services.dovecot2.extraConfig = + let + passwdFile = config.sops.secrets.dovecot_passwd.path; + in + '' + passdb { + driver = passwd-file + args = ${passwdFile} + } + userdb { + driver = passwd-file + args = ${passwdFile} + } + + # allow postfix to query our auth db + service auth { + unix_listener auth { + mode = 0660 + user = postfix + group = postfix + } + } + auth_mechanisms = plain login + + + mail_debug = yes + auth_debug = yes + # verbose_ssl = yes + ''; +} diff --git a/hosts/by-name/servo/services/email/postfix.nix b/hosts/by-name/servo/services/email/postfix.nix index cdb7b9a6..946a6f30 100644 --- a/hosts/by-name/servo/services/email/postfix.nix +++ b/hosts/by-name/servo/services/email/postfix.nix @@ -1,18 +1,6 @@ -# DOCS: -# - postfix config options: -# - dovecot config: -# - rspamd nixos: -# - rspamd guide: -# -# nix configs to reference: -# - -# - -# - postfix / dovecot / rspamd / stalwart-jmap / sogo +# postfix config options: -# TODO: -# - rspamd integration: - -{ config, lib, ... }: +{ lib, ... }: let submissionOptions = { @@ -41,20 +29,12 @@ in ]; networking.firewall.allowedTCPPorts = [ - # exposed over non-vpn imap.uninsane.org - 143 # IMAP - 993 # IMAPS - # exposed over vpn mx.uninsane.org 25 # SMTP 465 # SMTPS 587 # SMTPS/submission ]; - # exists only to manage certs for dovecot - services.nginx.virtualHosts."imap.uninsane.org" = { - enableACME = true; - }; # exists only to manage certs for Postfix services.nginx.virtualHosts."mx.uninsane.org" = { enableACME = true; @@ -65,7 +45,6 @@ in MX."@" = "10 mx.uninsane.org."; # XXX: RFC's specify that the MX record CANNOT BE A CNAME A."mx" = "185.157.162.178"; - CNAME."imap" = "native"; # Sender Policy Framework: # +mx => mail passes if it originated from the MX @@ -164,62 +143,6 @@ in UMask = lib.mkForce "0011"; }; - # inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/ - services.dovecot2.enable = true; - services.dovecot2.mailboxes = { - # special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash" - # RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html - # how these boxes are treated is 100% up to the client and server to decide. - # client behavior: - # iOS - # - Drafts: ? - # - Sent: works - # - Trash: works - # - Junk: ? - # aerc - # - Drafts: works - # - Sent: works - # - Trash: no; deleted messages are actually deleted - # use `:move trash` instead - # - Junk: ? - # Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side. - Drafts = { specialUse = "Drafts"; auto = "create"; }; - Sent = { specialUse = "Sent"; auto = "create"; }; - Trash = { specialUse = "Trash"; auto = "create"; }; - Junk = { specialUse = "Junk"; auto = "create"; }; - }; - services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem"; - services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem"; - services.dovecot2.enablePAM = false; - services.dovecot2.extraConfig = - let - passwdFile = config.sops.secrets.dovecot_passwd.path; - in - '' - passdb { - driver = passwd-file - args = ${passwdFile} - } - userdb { - driver = passwd-file - args = ${passwdFile} - } - - # allow postfix to query our auth db - service auth { - unix_listener auth { - mode = 0660 - user = postfix - group = postfix - } - } - auth_mechanisms = plain login - - - mail_debug = yes - auth_debug = yes - # verbose_ssl = yes - ''; #### OUTGOING MESSAGE REWRITING: services.postfix.enableHeaderChecks = true; @@ -241,14 +164,4 @@ in # pattern = "/^Subject:.*activate your account/"; # } ]; - - #### SPAM FILTERING - # services.rspamd.enable = true; - # services.rspamd.postfix.enable = true; - - sops.secrets."dovecot_passwd" = { - owner = config.users.users.dovecot2.name; - # TODO: debug why mail can't be sent without this being world-readable - mode = "0444"; - }; }