From 4925d958d1b66de2487de15ffbe37044e371093b Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 18 Sep 2023 15:32:43 +0200 Subject: [PATCH] add sendmail (OpenSMTPD) and journalwatch --- .gitignore | 1 + hive.nix | 43 +++++++++++++ hosts/yodaTab/configuration.nix | 2 + hosts/yodaTux/configuration.nix | 2 + hosts/yodaYoga/configuration.nix | 2 + modules/journalwatch.nix | 105 +++++++++++++++++++++++++++++++ modules/sendmail-mta.nix | 90 ++++++++++++++++++++++++++ secrets/.gitkeep | 0 8 files changed, 245 insertions(+) create mode 100644 modules/journalwatch.nix create mode 100644 modules/sendmail-mta.nix create mode 100644 secrets/.gitkeep diff --git a/.gitignore b/.gitignore index 1105930..73d13ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.idea/ +/secrets/ /result diff --git a/hive.nix b/hive.nix index cfab144..72b4bb0 100644 --- a/hive.nix +++ b/hive.nix @@ -1,3 +1,4 @@ +# Import nixpkgs with niv. https://dataswamp.org/~solene/2022-01-12-nix-niv-shell.html#_Create_a_shell.nix_file let sources = import ./nix/sources.nix; in @@ -23,6 +24,20 @@ in # Import the per-host configuration file. imports = [ ./hosts/${name}/configuration.nix ]; + deployment.keys.smtpd = { + # When non-null, contents of the specified file will be deployed to the specified key on the target machine. + # https://github.com/NixOS/nixops/blob/fc9b55c55da62f949028143b974f67fdc7f40c8b/nix/keys.nix#L58 + keyFile = ./secrets/smtpd; + + destDir = "/secrets"; # Default: /run/keys + # smtpd user. https://github.com/NixOS/nixpkgs/blob/360a7d31c30abefdc490d203f80e3221b7a24af2/nixos/modules/services/mail/opensmtpd.nix#L93C7-L93C12 + user = "smtpd"; # Default: root + #group = "smtpd"; # Default: root + permissions = "0400"; # Default: 0600 + + uploadAt = "pre-activation"; # Default: pre-activation, Alternative: post-activation + }; + deployment = { # Local deployment. allowLocalDeployment = true; @@ -34,6 +49,20 @@ in # Import the per-host configuration file. imports = [ ./hosts/${name}/configuration.nix ]; + deployment.keys.smtpd = { + # When non-null, contents of the specified file will be deployed to the specified key on the target machine. + # https://github.com/NixOS/nixops/blob/fc9b55c55da62f949028143b974f67fdc7f40c8b/nix/keys.nix#L58 + keyFile = ./secrets/smtpd; + + destDir = "/secrets"; # Default: /run/keys + # smtpd user. https://github.com/NixOS/nixpkgs/blob/360a7d31c30abefdc490d203f80e3221b7a24af2/nixos/modules/services/mail/opensmtpd.nix#L93C7-L93C12 + user = "smtpd"; # Default: root + #group = "smtpd"; # Default: root + permissions = "0400"; # Default: 0600 + + uploadAt = "pre-activation"; # Default: pre-activation, Alternative: post-activation + }; + deployment = { # Local deployment. allowLocalDeployment = true; @@ -49,6 +78,20 @@ in # Import the per-host configuration file. imports = [ ./hosts/${name}/configuration.nix ]; + deployment.keys.smtpd = { + # When non-null, contents of the specified file will be deployed to the specified key on the target machine. + # https://github.com/NixOS/nixops/blob/fc9b55c55da62f949028143b974f67fdc7f40c8b/nix/keys.nix#L58 + keyFile = ./secrets/smtpd; + + destDir = "/secrets"; # Default: /run/keys + # smtpd user. https://github.com/NixOS/nixpkgs/blob/360a7d31c30abefdc490d203f80e3221b7a24af2/nixos/modules/services/mail/opensmtpd.nix#L93C7-L93C12 + user = "smtpd"; # Default: root + #group = "smtpd"; # Default: root + permissions = "0400"; # Default: 0600 + + uploadAt = "pre-activation"; # Default: pre-activation, Alternative: post-activation + }; + deployment = { # SSH deployment. targetHost = "p1st.de"; diff --git a/hosts/yodaTab/configuration.nix b/hosts/yodaTab/configuration.nix index 52cbf79..ce74727 100644 --- a/hosts/yodaTab/configuration.nix +++ b/hosts/yodaTab/configuration.nix @@ -48,6 +48,8 @@ in #../../modules/podman.nix #../../modules/docker.nix ../../modules/lid-switch-handling.nix + ../../modules/sendmail-mta.nix + ../../modules/journalwatch.nix ]; networking.hostName = "yodaTab"; diff --git a/hosts/yodaTux/configuration.nix b/hosts/yodaTux/configuration.nix index c33bd1e..eb8e61e 100644 --- a/hosts/yodaTux/configuration.nix +++ b/hosts/yodaTux/configuration.nix @@ -48,6 +48,8 @@ in #../../modules/podman.nix ../../modules/docker.nix ../../modules/lid-switch-handling.nix + ../../modules/sendmail-mta.nix + ../../modules/journalwatch.nix ]; networking.hostName = "yodaTux"; diff --git a/hosts/yodaYoga/configuration.nix b/hosts/yodaYoga/configuration.nix index 6b1f4f3..de46095 100644 --- a/hosts/yodaYoga/configuration.nix +++ b/hosts/yodaYoga/configuration.nix @@ -50,6 +50,8 @@ in #../../modules/podman.nix ../../modules/docker.nix ../../modules/lid-switch-handling.nix + ../../modules/sendmail-mta.nix + ../../modules/journalwatch.nix ]; networking.hostName = "yodaYoga"; diff --git a/modules/journalwatch.nix b/modules/journalwatch.nix new file mode 100644 index 0000000..bd8b59a --- /dev/null +++ b/modules/journalwatch.nix @@ -0,0 +1,105 @@ +{ config, pkgs, ... }: + +{ + # Write to Systemd Journal: + # echo 'hello' | systemd-cat -p emerg + # echo 'hello' | systemd-cat -t someapp -p emerg + + # View Systemd Journal. + # Filter by app: + # journalctl -b -t someapp + # Filter by priority: + # journalctl -b -p 5 + + # Manually execute journalwatch timer: + # sudo systemctl start journalwatch.service + + # Find a message and view its details + # journalctl -b -p5 -o json-pretty + # Then press "/" and enter a pattern, then press "Enter". + + assertions = [{ + assertion = config.services.opensmtpd.enable; + message = "journalwatch requires a configured sendmail MTA, see sendmail-mta.nix."; + }]; + + services.journalwatch = { + enable = true; + # TODO: Same as configured by sendmail MTA. + mailFrom = "langbein@mail.de"; + mailTo = "daniel+journalwatch@systemli.org"; + #interval = "hourly"; + + # Lowest priority of message to be considered. A value between 7 (“debug”), and 0 (“emerg”). Defaults to 6 (“info”). If you don’t care about anything with “info” priority, you can reduce this to e.g. 5 (“notice”) to considerably reduce the amount of messages without needing many filterBlocks. + priority = 5; + + # Default patterns: https://github.com/The-Compiler/journalwatch/blob/363725ac4b8aa841d87654fa8a63403a59ad1275/journalwatch.py#L71 + # If the value of `match` starts and ends with a slash, it is interpreted as a regular expression, if not, it's an exact match. + # `filters` are always regular expressions. + # All regular expressions have to match the full string! + filterBlocks = [ + { + filters = '' + .* + ''; + match = "_SYSTEMD_UNIT = bluetooth.service"; + } + { + filters = '' + .* + ''; + match = "_SYSTEMD_UNIT = cups.service"; + } + { # If the user `yoda` runs a command with `sudo`. + filters = '' + \s+yoda : TTY=pts/7 ; PWD=/.+ ; USER=root ; COMMAND=/.+ + ''; + match = "SYSLOG_IDENTIFIER = sudo"; + } + { + filters = '' + The system will suspend now! + ''; + match = "_SYSTEMD_UNIT = systemd-logind.service"; + } + { + filters = '' + Reexecuting. + finished switching to system configuration /nix/store/.+-nixos-system-.+-[0-9]+\.[0-9]+pre-git + ''; + match = "_SYSTEMD_UNIT = user@0.service"; + } + { + filters = '' + Reexecuting. + finished switching to system configuration /nix/store/.+-nixos-system-.+-[0-9]+\.[0-9]+pre-git + ''; + match = "_SYSTEMD_UNIT = user@1000.service"; + } + { + filters = '' + Reloading rules + Collecting garbage unconditionally... + Loading rules from directory /.+ + Finished loading, compiling and executing [0-9]+ rules + ''; + match = "_SYSTEMD_UNIT = polkit.service"; + } + { # yodaTux + filters = '' + .+ error name="org\.bluez\.MediaEndpoint1\.Error\.NotImplemented" .+ + ''; + match = "_SYSTEMD_USER_UNIT = dbus.service"; + } + { # yodaTux + filters = '' + ACPI: FW issue: working around C-state latencies out of order + # Kernel WiFi driver bug. + iwlwifi 0000:01:00.0: Unhandled alg: 0x707 + + ''; + match = "SYSLOG_IDENTIFIER = kernel"; + } + ]; + }; +} diff --git a/modules/sendmail-mta.nix b/modules/sendmail-mta.nix new file mode 100644 index 0000000..54a2dda --- /dev/null +++ b/modules/sendmail-mta.nix @@ -0,0 +1,90 @@ +{ config, pkgs, ... }: + +{ + # Many programs use the `sendmail` command to send email. + # Nullmailer and OpenSMTP create a symlink from `sendmail` to their binary - they are (to a certain degree) sendmail compatible. + # In the following, we configure and use OpenSMTPD. Nullmailer is an alternative. + + # Nullmailer: Send SMTP mail. Has a queue for storage of messages when offline. + # https://wiki.archlinux.org/title/Nullmailer + + # OpenSMTPD + # - Manages a local persistent queue of messages that aren't allowed to be lost + # - Schedules delivery with some retry logic in case of temporary failures + # https://www.opensmtpd.org/presentations/eurobsdcon2017-smtpd/eurobsdcon2017-opensmtpd.pdf + + # Verbose logging and deamon status + # sudo smtpctl log verbose + # systemctl status opensmtpd + # sudo smtpctl show status + # Send an email + # echo "Subject: hello" | sendmail -f langbein@mail.de daniel@systemli.org + # Queue handling + # sudo smtpctl show queue + # sudo smtpctl schedule all + # sudo smtpctl remove all + # Monitoring + # sudo smtpctl monitor + + # /secrets/smtpd is created by Colmena. + # It contains one line `upstream langbein@mail.de:the-actual-password`. + assertions = [{ + assertion = builtins.pathExists config.deployment.keys.smtpd.keyFile; + message = "Expected a keyfile to be deployed for smtpd, see hive.nix."; + }]; + + # Create file /etc/aliases. + # https://nixos.wiki/wiki/Msmtp#Aliases + environment.etc.aliases = { + text = '' + # Forward email from root to daniel@systemli.org + root: daniel@systemli.org + ''; + mode = "0644"; + }; + + services.opensmtpd = { + enable = true; + setSendmail = true; + + # Config documentation + # https://man.archlinux.org/man/smtpd.conf.5 + # Parts of the configuration were taken from exymple 1: + # This first example is similar to the default configuration (allows for mail from users and daemons on the local machine, as well as permitting email to remote servers), but all outgoing mail is forwarded to a remote SMTP server. + # https://man.archlinux.org/man/smtpd.conf.5#EXAMPLES + # Another config example + # https://xw.is/wiki/OpenSMTPD_forward_to_Google#How + serverConfiguration = '' + # System alias table. + # Provides a convenient way to send mail. + table aliases file:/etc/aliases + table secrets file:/secrets/smtpd + + # Only accept local mail + # -> In the example, they use lo0 + # -> In the default config of Arch Linux, they use localhost + # -> NixOS example config uses lo. https://search.nixos.org/options?channel=23.05&show=services.opensmtpd.serverConfiguration&from=0&size=50&sort=relevance&type=packages + # -> In the NUR, they use lo. https://github.com/nix-community/nur-combined/blob/2bfaab7c1ff891f540618370c2d184d0f000adb0/repos/priegger/modules/services/opensmtpd-relay/default.nix#L16C1-L16C17 + # -> `ip addr` returns `lo` on NixOS. + listen on lo + #listen on lo0 + #listen on localhost + + # Send local mail. + # + # mbox: Deliver the message to the user's mbox with mail.local(8). + # With mail.local: Reads the standard input up to an end-of-file and appends it to each user's mail file. + # With mail files being stored in: /var/mail/user + # maildir: Deliver the message to the maildir in pathname if specified, or by default to ~/Maildir. + action "local_mail" mbox alias + #action "local_mail" maildir alias + + # Send remote mail. + #action "outbound" relay host smtp+tls://upstream@smtp.mail.de auth mail-from langbein@mail.de + action "outbound" relay host smtps://upstream@smtp.mail.de auth mail-from langbein@mail.de + + match from local for local action "local_mail" + match from local for any action "outbound" + ''; + }; +} diff --git a/secrets/.gitkeep b/secrets/.gitkeep new file mode 100644 index 0000000..e69de29