From 161dc84fce2c2de603d0b867d07e9a412897e51c Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Sun, 25 Aug 2024 14:24:15 +0200 Subject: Configure nullmailer on servers --- regenerate-secrets.sh | 7 ++ tw/services/files/nullmailer-remotes.enc | 13 ++++ tw/services/mail.scm | 107 +++++++++++++++++++++++++++++++ tw/system.scm | 7 +- 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 tw/services/files/nullmailer-remotes.enc create mode 100644 tw/services/mail.scm diff --git a/regenerate-secrets.sh b/regenerate-secrets.sh index b0c0c3fc..42b94282 100755 --- a/regenerate-secrets.sh +++ b/regenerate-secrets.sh @@ -66,3 +66,10 @@ EOF enc tw/services/files/personal-data-exporter/conso.json vin << EOF {"prm": "$(pass www/conso-api | sed -rn '/^prm: /s///p')", "api-token": "$(pass www/conso-api | head -1)"} EOF + +enc tw/services/files/nullmailer-remotes.enc lud vin << EOF +# https://www.mythic-beasts.com/support/hosting/mail/client#outgoing +smtp-auth.mythic-beasts.com smtp port=587 starttls \ + user='$(pass www/mythic-beasts/email/cron | sed -rn '/^username: /s///p')' \ + pass='$(pass www/mythic-beasts/email/cron | head -1)' +EOF diff --git a/tw/services/files/nullmailer-remotes.enc b/tw/services/files/nullmailer-remotes.enc new file mode 100644 index 00000000..c3ccc16a --- /dev/null +++ b/tw/services/files/nullmailer-remotes.enc @@ -0,0 +1,13 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHBESlBiZyBZV3Jx +akVwZVZ4NUNUQ2t3cXl6dnMrVEJVbDlZcURaWmwvWURKWHNzMEhjCklUNC85Z0E2 +NFdkbUUzM2s5WlAxWmx3cDRwQzN0QWJ0aFplNlZkM2c1LzQKLT4gc3NoLWVkMjU1 +MTkgL1NXSFVBIC84UmhrdHErZW9Bc1AvQVdjVGRGSUI1SVhQVUZMNTVveVk3UUhm +MW16QVEKVG1rcDNLWDBaU2hyL2FONi9VQ044SVhxenhRak5hdkFJSXZzY1NKOU52 +MAotLS0gNkFzSnhHR3BiNEhrdGpiUk1xbzhtTUl2SVNRRlpqQ0h6SGhwTWpPb1VD +dwr/aYp6f+xKLcgTBbszisXksl8E1E1Hmjrn2yKG7Bd9e4+paTlzeDIB/JgZtWZz +X3liFIPSsbtCdKQU53cGAiutPhOQiiO1ID6zr7UJ2K/f0vSuqqL1ZWGQOMk53Niv +qRrhlOUv9+yTOBK64kvcK6AT9CfiAaHhLSF5GpQ7b8i3NzU89Lhn7uKe/zqzOghp +z6aquV3F34claJUjZsgS/mJWT7FT6iN7vlhk1XsZCQ9io3QF78eKfjg/++EPltOR +p7EBtJkVcvTrMb/LlGY= +-----END AGE ENCRYPTED FILE----- diff --git a/tw/services/mail.scm b/tw/services/mail.scm new file mode 100644 index 00000000..2eb5c435 --- /dev/null +++ b/tw/services/mail.scm @@ -0,0 +1,107 @@ +(define-module (tw services mail) + #:use-module (gnu) + #:use-module ((gnu packages admin) #:select (shadow)) + #:use-module ((gnu packages mail) #:select (nullmailer)) + #:use-module (gnu services) + #:use-module (gnu services configuration) + #:use-module (gnu services shepherd) + #:use-module (gnu system privilege) + #:use-module (guix gexp) + #:use-module (guix modules) ; `source-module-closure' + #:use-module (guix records) + #:use-module (tw services secrets) + #:export (mta-configuration + mta-service-type)) + +(define-configuration/no-serialization mta-configuration + (host-name string "The system's host name, which is needed by nullmailer.") + (user (string "mail") "The UNIX user name to allocate for the MTA.") + (group (string "mail") "The UNIX user group to allocate for the MTA.")) + +(define (mta-accounts config) + (match-record config (user group) + (list (user-account + (name user) (group group) (system? #t) + (comment "Nullmailer daemon user") + (home-directory "/var/spool/nullmailer") + (shell (file-append shadow "/sbin/nologin"))) + (user-group (name group) (system? #t))))) + +(define (mta-secrets config) + (match-record config (user group) + (list (secret (encrypted-file (local-file "files/nullmailer-remotes.enc")) + (destination "/etc/nullmailer/remotes") + (user user) (group group))))) + +(define (mta-setuid-programs config) + ;; Allow any user to send mail. This also prevents annoying failures + ;; when root tries to send mail, since nullmailer-send cannot read the + ;; messages it puts in the queue with 0600 permissions. + (match-record config (user) + (map (lambda (prog) + (privileged-program + (program (file-append nullmailer prog)) + (setuid? #t) (user user))) + '("/sbin/sendmail" "/bin/mailq")))) + +(define (mta-shepherd-services config) + (match-record config (user group) + (list (shepherd-service + (documentation "Run a basic Mail Transfer Agent.") + (provision '(nullmailer)) + (start #~(make-forkexec-constructor + (list #$(file-append nullmailer "/sbin/nullmailer-send")) + #:user #$user #:group #$group)) + (stop #~(make-kill-destructor)))))) + +;; Ideally we'd use `etc-service-type' here, but that would install +;; /etc/nullmailer as a directory symlink pointing into /gnu/store, which +;; blocks installation of /etc/nullmailer/remotes later. +(define (mta-activation config) + (match-record config (host-name user) + (with-imported-modules (source-module-closure '((guix build utils))) + #~(begin + (use-modules ((srfi srfi-26) #:select (cut)) + ((guix build utils) #:select (mkdir-p))) + (define (rm-f path) + (false-if-exception (delete-file path))) + (define (mkdir-if-not-exist path) + (catch 'system-error (lambda () (mkdir path)) + (lambda args + (or (= EEXIST (system-error-errno args)) + (apply throw args))))) + + (rm-f "/etc/nullmailer") + (mkdir-p "/etc/nullmailer") + (for-each (lambda (source target) + (rm-f target) + (symlink source target)) + '(#$(plain-file "nm-me" host-name) + #$(plain-file "nm-adminaddr" "timo@twilken.net") + #$(plain-file "nm-allmailfrom" "cron@twilken.net")) + '("/etc/nullmailer/me" + "/etc/nullmailer/adminaddr" + "/etc/nullmailer/allmailfrom")) + + ;; Create nullmailer's data directories and socket. + ;; No idea why it doesn't do this itself. + (let ((dirs '("/var/spool/nullmailer/queue" + "/var/spool/nullmailer/failed" + "/var/spool/nullmailer/tmp")) + (trigger-path "/var/spool/nullmailer/trigger")) + (for-each mkdir-if-not-exist dirs) + (unless (file-exists? trigger-path) + (system* #$(file-append coreutils "/bin/mkfifo") "-m" "600" trigger-path)) + (let ((user (getpw #$user))) + (for-each (cut chown <> (passwd:uid user) (passwd:gid user)) + (cons trigger-path dirs)))))))) + +(define mta-service-type + (service-type + (name 'mta) + (description "Run the Mail Transfer Agent @code{nullmailer}, to forward system emails.") + (extensions (list (service-extension shepherd-root-service-type mta-shepherd-services) + (service-extension privileged-program-service-type mta-setuid-programs) + (service-extension account-service-type mta-accounts) + (service-extension activation-service-type mta-activation) + (service-extension secrets-service-type mta-secrets))))) diff --git a/tw/system.scm b/tw/system.scm index d9e33f0e..a66a9230 100644 --- a/tw/system.scm +++ b/tw/system.scm @@ -1,6 +1,5 @@ (define-module (tw system) #:use-module (ice-9 string-fun) - #:use-module (srfi srfi-26) #:use-module (gnu) #:use-module (gnu services) #:use-module (gnu system) @@ -10,6 +9,8 @@ #:use-module (tw packages catppuccin) #:use-module (tw packages scanner) #:use-module (tw services desktop) + #:use-module (tw services mail) + #:use-module (tw services secrets) #:use-module (tw services wireguard)) (use-package-modules acl admin android avahi backup certs cups curl disk @@ -114,6 +115,10 @@ (simple-service 'guix-gc mcron-service-type (list #~(job "0 2 * * *" "guix gc -d 2w"))) + (service mta-service-type + (mta-configuration + (host-name host-name))) + ;; Network setup (service dhcp-client-service-type) (service ntp-service-type) -- cgit v1.2.3