diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index 608f64a68fb0..f025932fa126 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -280,6 +280,17 @@ in description = "Whether to enable smtp submission."; }; + enableSubmissions = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable smtp submission via smtps. + + According to RFC 8314 this should be preferred + over STARTTLS for submission of messages by end user clients. + ''; + }; + submissionOptions = mkOption { type = types.attrs; default = { @@ -298,6 +309,29 @@ in description = "Options for the submission config in master.cf"; }; + submissionsOptions = mkOption { + type = types.attrs; + default = { + smtpd_sasl_auth_enable = "yes"; + smtpd_client_restrictions = "permit_sasl_authenticated,reject"; + milter_macro_daemon_name = "ORIGINATING"; + }; + example = { + smtpd_sasl_auth_enable = "yes"; + smtpd_sasl_type = "dovecot"; + smtpd_client_restrictions = "permit_sasl_authenticated,reject"; + milter_macro_daemon_name = "ORIGINATING"; + }; + description = '' + Options for the submission config via smtps in master.cf. + + smtpd_tls_security_level will be set to encrypt, if it is missing + or has one of the values "may" or "none". + + smtpd_tls_wrappermode with value "yes" will be added automatically. + ''; + }; + setSendmail = mkOption { type = types.bool; default = true; @@ -878,6 +912,23 @@ in command = "smtp"; args = [ "-o" "smtp_fallback_relay=" ]; }; + } // optionalAttrs cfg.enableSubmissions { + submissions = { + type = "inet"; + private = false; + command = "smtpd"; + args = let + mkKeyVal = opt: val: [ "-o" (opt + "=" + val) ]; + adjustSmtpTlsSecurityLevel = !(cfg.submissionsOptions ? smtpd_tls_security_level) || + cfg.submissionsOptions.smtpd_tls_security_level == "none" || + cfg.submissionsOptions.smtpd_tls_security_level == "may"; + submissionsOptions = cfg.submissionsOptions // { + smtpd_tls_wrappermode = "yes"; + } // optionalAttrs adjustSmtpTlsSecurityLevel { + smtpd_tls_security_level = "encrypt"; + }; + in concatLists (mapAttrsToList mkKeyVal submissionsOptions); + }; }; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 26ea0570f0fe..e13a5ee57f6f 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -268,6 +268,8 @@ in plasma5 = handleTest ./plasma5.nix {}; plotinus = handleTest ./plotinus.nix {}; podman = handleTestOn ["x86_64-linux"] ./podman.nix {}; + postfix = handleTest ./postfix.nix {}; + postfix-raise-smtpd-tls-security-level = handleTest ./postfix-raise-smtpd-tls-security-level.nix {}; postgis = handleTest ./postgis.nix {}; postgresql = handleTest ./postgresql.nix {}; postgresql-wal-receiver = handleTest ./postgresql-wal-receiver.nix {}; diff --git a/nixos/tests/postfix-raise-smtpd-tls-security-level.nix b/nixos/tests/postfix-raise-smtpd-tls-security-level.nix new file mode 100644 index 000000000000..bfe02865553f --- /dev/null +++ b/nixos/tests/postfix-raise-smtpd-tls-security-level.nix @@ -0,0 +1,44 @@ +let + certs = import ./common/acme/server/snakeoil-certs.nix; +in +import ./make-test-python.nix { + name = "postfix"; + + machine = { pkgs, ... }: { + imports = [ common/user-account.nix ]; + services.postfix = { + enable = true; + enableSubmissions = true; + submissionsOptions = { + smtpd_tls_security_level = "none"; + }; + }; + + environment.systemPackages = let + checkConfig = pkgs.writeScriptBin "check-config" '' + #!${pkgs.python3.interpreter} + import sys + + state = 1 + success = False + + with open("/etc/postfix/master.cf") as masterCf: + for line in masterCf: + if state == 1 and line.startswith("submissions"): + state = 2 + elif state == 2 and line.startswith(" ") and "smtpd_tls_security_level=encrypt" in line: + success = True + elif state == 2 and not line.startswith(" "): + state == 3 + if not success: + sys.exit(1) + ''; + + in [ checkConfig ]; + }; + + testScript = '' + machine.wait_for_unit("postfix.service") + machine.succeed("check-config") + ''; +} diff --git a/nixos/tests/postfix.nix b/nixos/tests/postfix.nix new file mode 100644 index 000000000000..0d677427d761 --- /dev/null +++ b/nixos/tests/postfix.nix @@ -0,0 +1,76 @@ +let + certs = import ./common/acme/server/snakeoil-certs.nix; +in +import ./make-test-python.nix { + name = "postfix"; + + machine = { pkgs, ... }: { + imports = [ common/user-account.nix ]; + services.postfix = { + enable = true; + enableSubmission = true; + enableSubmissions = true; + sslCACert = certs.ca.cert; + sslCert = certs."acme.test".cert; + sslKey = certs."acme.test".key; + submissionsOptions = { + smtpd_sasl_auth_enable = "yes"; + smtpd_client_restrictions = "permit"; + milter_macro_daemon_name = "ORIGINATING"; + }; + }; + + security.pki.certificateFiles = [ + certs.ca.cert + ]; + + networking.extraHosts = '' + 127.0.0.1 acme.test + ''; + + environment.systemPackages = let + sendTestMail = pkgs.writeScriptBin "send-testmail" '' + #!${pkgs.python3.interpreter} + import smtplib + + with smtplib.SMTP('acme.test') as smtp: + smtp.sendmail('root@localhost', 'alice@localhost', 'Subject: Test\n\nTest data.') + smtp.quit() + ''; + + sendTestMailStarttls = pkgs.writeScriptBin "send-testmail-starttls" '' + #!${pkgs.python3.interpreter} + import smtplib + import ssl + + ctx = ssl.create_default_context() + + with smtplib.SMTP('acme.test') as smtp: + smtp.ehlo() + smtp.starttls(context=ctx) + smtp.ehlo() + smtp.sendmail('root@localhost', 'alice@localhost', 'Subject: Test STARTTLS\n\nTest data.') + smtp.quit() + ''; + + sendTestMailSmtps = pkgs.writeScriptBin "send-testmail-smtps" '' + #!${pkgs.python3.interpreter} + import smtplib + import ssl + + ctx = ssl.create_default_context() + + with smtplib.SMTP_SSL(host='acme.test', context=ctx) as smtp: + smtp.sendmail('root@localhost', 'alice@localhost', 'Subject: Test SMTPS\n\nTest data.') + smtp.quit() + ''; + in [ sendTestMail sendTestMailStarttls sendTestMailSmtps ]; + }; + + testScript = '' + machine.wait_for_unit("postfix.service") + machine.succeed("send-testmail") + machine.succeed("send-testmail-starttls") + machine.succeed("send-testmail-smtps") + ''; +}