nyarlathotep: cleanup after deployment #55

Merged
Gonne merged 22 commits from Gonne/nixConfig:nyarlathotep into main 2025-03-24 19:38:06 +00:00
Owner
No description provided.
Gonne added 9 commits 2025-03-02 10:49:10 +00:00
Gonne added 1 commit 2025-03-02 10:57:34 +00:00
requested review from Server-Minions 2025-03-02 11:01:47 +00:00
Gonne force-pushed nyarlathotep from 590ea741d0 to d7f4598be3 2025-03-02 12:39:18 +00:00 Compare
Gonne force-pushed nyarlathotep from d7f4598be3 to b3ac11ddc9 2025-03-02 13:06:28 +00:00 Compare
Gonne force-pushed nyarlathotep from b3ac11ddc9 to 9c26820b8f 2025-03-02 13:14:39 +00:00 Compare
Gonne force-pushed nyarlathotep from 9c26820b8f to c5849b8695 2025-03-02 19:38:05 +00:00 Compare
nerf requested changes 2025-03-03 10:38:07 +00:00
nerf left a comment
Owner

First few comments

First few comments
@ -187,0 +214,4 @@
++ ["sieve.trusted.*"]; #for macros to be able to include our redirection script
sieve.trusted = {
scripts.redirects.contents = "%{file:/tmp/virt_aliases}%"; # generated redirect script
trusted.from-addr = "sender"; # set the from-address to the original sender as specified in the MAIL FROM.
Owner

the trusted part is to much, also see the comment at from-name below

the `trusted` part is to much, also see the comment at `from-name` below
Gonne marked this conversation as resolved
@ -187,0 +215,4 @@
sieve.trusted = {
scripts.redirects.contents = "%{file:/tmp/virt_aliases}%"; # generated redirect script
trusted.from-addr = "sender"; # set the from-address to the original sender as specified in the MAIL FROM.
from-name = "sender";
Owner

I couldn't figure out what from-name or from-addr actually do. Reading the documentation I believe combined they
set the default value for the From: header of a generated mail. But I couldn't verify this in tests.
Maybe it does something different that has to do with the MAIL FROM: see comment below

I couldn't figure out what `from-name` or `from-addr` actually do. Reading the documentation I believe combined they set the default value for the `From:` header of a generated mail. But I couldn't verify this in tests. Maybe it does something different that has to do with the `MAIL FROM:` see comment below
Gonne marked this conversation as resolved
@ -187,0 +216,4 @@
scripts.redirects.contents = "%{file:/tmp/virt_aliases}%"; # generated redirect script
trusted.from-addr = "sender"; # set the from-address to the original sender as specified in the MAIL FROM.
from-name = "sender";
return-path = "sender";
Owner

This seems to do what we want, even though the documentation reads like it sets the Return-Path: header. But it seems to set the reverse path (which is the argument to the MAIL FROM: smtp command). Maybe it does both?

This seems to do what we want, even though the documentation reads like it sets the `Return-Path:` header. But it seems to set the reverse path (which is the argument to the `MAIL FROM:` smtp command). Maybe it does both?
Owner

This parameter seems to control the MAIL FROM: and with this all the headers we want to set.
The documentation reads to me as if it sets the Return-Path: header. I'm unsure if it actually does it.

This parameter seems to control the `MAIL FROM:` and with this all the headers we want to set. The documentation reads to me as if it sets the `Return-Path:` header. I'm unsure if it actually does it.
Gonne marked this conversation as resolved
Author
Owner

So we want this?

sieve.trusted = {
            # […]
#            from-addr = "sender";  # unset
#            from-name = "sender"; # unset
            return-path = "sender"; # set the outgoing MAIL FROM to the original sender as specified in the incoming MAIL FROM.
            # […]
          };
So we want this? ```nix sieve.trusted = { # […] # from-addr = "sender"; # unset # from-name = "sender"; # unset return-path = "sender"; # set the outgoing MAIL FROM to the original sender as specified in the incoming MAIL FROM. # […] }; ```
Gonne added 1 commit 2025-03-03 11:59:26 +00:00
Gonne added 1 commit 2025-03-03 13:50:06 +00:00
requested review from nerf 2025-03-03 14:46:05 +00:00
Gonne added 1 commit 2025-03-04 06:40:04 +00:00
Gonne force-pushed nyarlathotep from 4c946968e1 to 5e0cb9ebcc 2025-03-04 08:06:09 +00:00 Compare
Gonne force-pushed nyarlathotep from 5e0cb9ebcc to d27f4b942e 2025-03-04 08:20:42 +00:00 Compare
Gonne force-pushed nyarlathotep from d27f4b942e to c24757321e 2025-03-04 10:31:18 +00:00 Compare
Gonne force-pushed nyarlathotep from c24757321e to 6271e04c10 2025-03-05 20:01:04 +00:00 Compare
nerf changed title from nyarlathotep: cleanup after deployment to WIP: nyarlathotep: cleanup after deployment 2025-03-05 20:13:27 +00:00
nerf added the
Status
Blocked
label 2025-03-05 20:13:40 +00:00
refused to review 2025-03-05 20:14:16 +00:00
Gonne force-pushed nyarlathotep from 6271e04c10 to 19351ef316 2025-03-06 07:52:30 +00:00 Compare
Gonne force-pushed nyarlathotep from 19351ef316 to cb87976ce8 2025-03-17 15:03:16 +00:00 Compare
Gonne changed title from WIP: nyarlathotep: cleanup after deployment to nyarlathotep: cleanup after deployment 2025-03-17 15:03:26 +00:00
Gonne removed the
Status
Blocked
label 2025-03-18 08:28:31 +00:00
requested review from nerf 2025-03-18 08:32:08 +00:00
Gonne added 1 commit 2025-03-18 08:44:58 +00:00
Gonne force-pushed nyarlathotep from e05dde9ab3 to 67a9179216 2025-03-18 08:57:03 +00:00 Compare
Gonne force-pushed nyarlathotep from 67a9179216 to 23d85d5364 2025-03-18 09:23:43 +00:00 Compare
nerf requested changes 2025-03-18 09:43:41 +00:00
nerf left a comment
Owner

As the alias to sieve program is basically part of this config, it should end up under the same
moderation rules, right? So either integrate this as a package into this repo or at least do
branch protection on it. I'm fine with leaving it without until it is somewhat stable.

As the alias to sieve program is basically part of this config, it should end up under the same moderation rules, right? So either integrate this as a package into this repo or at least do branch protection on it. I'm fine with leaving it without until it is somewhat stable.
@ -74,2 +76,4 @@
mode = "0440";
};
"dkim_rsa" = {
sopsFile = ./dkim.keys.yaml;
Owner

see below

see below
Gonne marked this conversation as resolved
@ -76,0 +82,4 @@
mode = "0440";
};
"dkim_ed25519" = {
sopsFile = ./dkim.keys.yaml;
Owner

see below

see below
Gonne marked this conversation as resolved
@ -0,0 +1,40 @@
dkim_rsa: ENC[AES256_GCM,data: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,iv:QbZVXp5FQhmYZvXxXNxWKrNm5GqM+2P3a5pPk499mlc=,tag:F+KNoPRnoLLhOpEj6Czj6Q==,type:str]
Owner

can this file be called <something>.secrets.yaml?

can this file be called `<something>.secrets.yaml`?
Gonne marked this conversation as resolved
@ -153,2 +158,3 @@
session = {
ehlo.require = [
{
"if" = "!is_empty(authenticated_as) || rcpt_domain == 'lists.mathebau.de' || starts_with(remote_ip, '192.168.0.')"; #TODO restrict trust by IP
Owner

the diff is very confusing here, this line should be compared to 182 in green

the diff is very confusing here, this line should be compared to 182 in green
Gonne marked this conversation as resolved
@ -1,6 +1,6 @@
/*
* Building: We patch our version of stalwart and thus need to built it locally.
* Be aware that this needs some hours, about 12Gb RAM and a few Gb free space in /tmp.
* Be aware that this needs some hours, about 20Gb RAM and a few Gb free space in /tmp.
Owner

how did this went up from 12 to 20?

how did this went up from 12 to 20?
Author
Owner

I assume version updates from stalwart.

I assume version updates from stalwart.
Owner

sigh, no local builds for me anymore (except nixpkgs, starts to cache stalwart)

sigh, no local builds for me anymore (except nixpkgs, starts to cache stalwart)
nerf marked this conversation as resolved
@ -102,3 +102,3 @@
spam.header.is-spam = "Dummyheader"; # disable moving to spam which would conflict with forwarding
auth = {
# TODO check if HRZ conforms to these standards and we can validate them strictly
# TODO check if HRZ and our own VMs conform to these standards and we can validate them strictly
Owner

But Mailman shouldn't sign its mail, right? how do we solve that?

But Mailman shouldn't sign its mail, right? how do we solve that?
Author
Owner

Possibly by moving all submission from our other vms to a separate listener.

Possibly by moving all submission from our other vms to a separate listener.
Owner

I open an issue for later

I open an issue for later
nerf marked this conversation as resolved
@ -161,3 +191,3 @@
# Stalwart gets its configuration from two places: A TOML configuration file that we control in this module
# and from a database that can be configured from web management interface or via Rest API.
# We here define what comes from the TOML-file and especially add "sieve.trusted.scripts.*" to the default ones
# We here define what comes from the TOML-file and especially add "sieve.trusted.*" to the default ones
Owner

Is there still something left in the database that we could move here?

Is there still something left in the database that we could move here?
Author
Owner

The list of domains served by stalwart and the existence of catch-all accounts remains in the database, but I have not found out how do set them from config.

The list of domains served by stalwart and the existence of catch-all accounts remains in the database, but I have not found out how do set them from config.
Owner

I think we should move it to the config file, or do we need to dynamically change these?

I think we should move it to the config file, or do we need to dynamically change these?
Author
Owner

Yes, at least while we don't provide mail boxes. But I don't know how.

Yes, at least while we don't provide mail boxes. But I don't know how.
Owner

That mailboxes need some state attached to them is clear to me (not necessarily, which mail boxes but user generated sieve scripts for example). Maybe I should open another question in the stalwart discussion thing.

That mailboxes need some state attached to them is clear to me (not necessarily, which mail boxes but user generated sieve scripts for example). Maybe I should open another question in the stalwart discussion thing.
@ -186,1 +214,3 @@
session.data.script = "'redirects'";
++ ["sieve.trusted.*"]; #for macros to be able to include our redirection script
sieve.trusted = {
scripts.redirects.contents = "%{file:/tmp/virt_aliases}%"; # generated redirect script
Owner

maybe we should move this file from /tmp into the /run directory as this usually has proper
file access rights set up.

maybe we should move this file from `/tmp` into the `/run` directory as this usually has proper file access rights set up.
Author
Owner

There is also JoinsNamespaceOf for PrivateTmp of systemd service units (https://www.man7.org/linux/man-pages/man5/systemd.exec.5.html) but I didn't succeed setting it.

Reading https://lwn.net/Articles/436012/ I have no idea whether /run is a better place.

There is also `JoinsNamespaceOf` for `PrivateTmp` of systemd service units (https://www.man7.org/linux/man-pages/man5/systemd.exec.5.html) but I didn't succeed setting it. Reading https://lwn.net/Articles/436012/ I have no idea whether `/run` is a better place.
Owner

We don't care about the early boot discussion. So the question is, is it runtime date or temporary data, wherever the boundary between these two is. Putting things in /tmp is often a buggy mess as this directory is usually somewhat of a global dumpster fire, where there are no guarantees that this file does not already exist with some important information for some other process (though unlikely). PrivateTmp would save us here, but even the documentation says that one should not rely on this (and we would need to get it to work).

If we already follow Lennart's advice then we also should use mkstemp to generate files in /tmp which will
be very painful in a nix setting (as paths and filenames will only be available at runtime). Lennart also seems to think that /run is primarily for communication primitives (is this one?).
See his blogpost.

So after reading all of this maybe the cleanest option is to get the JoinNamespaceOf option to work?

We don't care about the early boot discussion. So the question is, is it runtime date or temporary data, wherever the boundary between these two is. Putting things in `/tmp` is often a buggy mess as this directory is usually somewhat of a global dumpster fire, where there are no guarantees that this file does not already exist with some important information for some other process (though unlikely). `PrivateTmp` would save us here, but even the documentation says that one should not rely on this (and we would need to get it to work). If we already follow Lennart's advice then we also should use `mkstemp` to generate files in `/tmp` which will be very painful in a nix setting (as paths and filenames will only be available at runtime). Lennart also seems to think that `/run` is primarily for communication primitives (is this one?). See [his blogpost](https://0pointer.net/blog/projects/tmp.html). So after reading all of this maybe the cleanest option is to get the `JoinNamespaceOf` option to work?
Author
Owner

I got the private /tmp with JoinsNamespaceOf working.

I got the private `/tmp` with `JoinsNamespaceOf` working.
Gonne marked this conversation as resolved
@ -187,0 +237,4 @@
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"];
Owner

I will just trust you on the header selection

I will just trust you on the header selection
Gonne marked this conversation as resolved
@ -33,4 +33,3 @@
transport_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
local_recipient_maps = ["hash:/var/lib/mailman/data/postfix_lmtp"];
proxy_interfaces = "130.83.2.184";
smtputf8_enable = "no"; # HRZ does not know SMTPUTF8
Owner

but we talk to us and not hrz, right?

but we talk to us and not hrz, right?
Author
Owner

Does the commit message explain your question?

Does the [commit message](https://gitea.mathebau.de/Fachschaft/nixConfig/pulls/55/commits/01951eadadcc19eb88b75e7341c5a40cd113c94c) explain your question?
Owner

no, my comment was attached to the smtputf8_enable line not the deleted one

no, my comment was attached to the `smtputf8_enable` line not the deleted one
Author
Owner

Ah, right. Let's test that.

Ah, right. Let's test that.
Author
Owner

Works

Works
Gonne marked this conversation as resolved
@ -9,3 +9,3 @@
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15ac54053752c25a0e545dd1953de716abcc80b12cfe0b6c2f2c1c73759d4f45"
+source = "git+https://gitea.mathebau.de/fachschaft/sieve-rs.git#71324550504c0f84fe3e814d05cbe22f90a3b228"
+source = "git+https://github.com/stalwartlabs/sieve.git#56450c6ccdf76f1de95931db24896599159efc53"
Owner

YaY, hopefully this can disappear soon

YaY, hopefully this can disappear soon
Gonne marked this conversation as resolved
Gonne added 1 commit 2025-03-18 10:14:09 +00:00
Gonne added 2 commits 2025-03-18 10:33:54 +00:00
nerf self-assigned this 2025-03-19 12:40:09 +00:00
nerf added this to the Mail is just working milestone 2025-03-19 12:40:24 +00:00
nerf reviewed 2025-03-19 12:55:27 +00:00
@ -186,1 +216,3 @@
session.data.script = "'redirects'";
++ ["sieve.trusted.*"]; #for macros to be able to include our redirection script
sieve.trusted = {
scripts.redirects.contents = "%{file:/tmp/virt_aliases}%"; # generated redirect script
Owner

where did the /tmp folder discussion disappeared to?

where did the `/tmp` folder discussion disappeared to?
Owner

ahh it got marked outdated

ahh it got marked outdated
nerf marked this conversation as resolved
Gonne added 1 commit 2025-03-24 09:45:12 +00:00
Gonne added 1 commit 2025-03-24 11:08:57 +00:00
Author
Owner

Apart from which code lives where, this config now has all features I can think of for now.

Apart from which code lives where, this config now has all features I can think of for now.
requested review from nerf 2025-03-24 11:14:19 +00:00
Gonne added 1 commit 2025-03-24 12:47:48 +00:00
Gonne added 1 commit 2025-03-24 13:40:06 +00:00
nerf approved these changes 2025-03-24 19:31:43 +00:00
@ -15,2 +15,2 @@
"rev": "c37b6ec8654db4c6e3d79acaeeccb577a9fb66ce",
"revCount": 21,
"rev": "3570db39fda3627d60fbd4ef9c6326b3de074eb8",
"revCount": 23,
Owner

at some point someone should review that script...

at some point someone should review that script...
Gonne marked this conversation as resolved
@ -231,2 +302,3 @@
# The regex searches for alphanumerics combined with some special characters as local paths and the right domain.
${pkgs.curl}/bin/curl -s --header "authorization: Basic $(<${cfg.stalwartAdmin})" http://localhost/api/principal | ${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&'*+-/=?^_{|}~]*@${domain}" | tee /tmp/addresses
# Exclude @domain.tld which is not a valid mail address but used for catch-all accounts.
${pkgs.curl}/bin/curl -s --header "authorization: Basic $(<${cfg.stalwartAdmin})" http://localhost/api/principal | ${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&*+-/=?^_{|}~]*@${domain}" | grep -v "@${domain}" | tee /tmp/addresses
Owner

The HRZ doesn't allow ' either so we don't loose anything (see the mails from the cert team, or read
our discussion in chat if you want to see the world burn)

The HRZ doesn't allow `'` either so we don't loose anything (see the mails from the cert team, or read our discussion in chat if you want to see the world burn)
Gonne marked this conversation as resolved
@ -233,2 +304,3 @@
${pkgs.curl}/bin/curl -s --header "authorization: Basic $(<${cfg.stalwartAdmin})" http://localhost/api/principal | ${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&*+-/=?^_{|}~]*@${domain}" | grep -v "@${domain}" | tee /tmp/addresses
# This line searches for available redirects and adds them to the submission file.
${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&'*+-/=?^_{|}~]*@${domain}" /tmp/virt_aliases >> /tmp/addresses # This doesn't catch all RFC conform local parts. Improve if you need.
${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&*+-/=?^_{|}~]*@${domain}" /tmp/virt_aliases >> /tmp/addresses # This doesn't catch all RFC conform local parts. Improve if you need.
Owner

See above. This parses a sieve script! That includes ' in its syntax so this would break anyway if we allowed ' in E-Mail addresses. Maybe we should parse the alias file instead. That has its own problems though.
We can discuss this in a separate issue.

See above. This parses a sieve script! That includes `'` in its syntax so this would break anyway if we allowed `'` in E-Mail addresses. Maybe we should parse the alias file instead. That has its own problems though. We can discuss this in a separate issue.
Gonne marked this conversation as resolved
@ -295,3 +344,1 @@
RestrictRealtime = true;
RestrictSUIDSGID = true;
};
#Generate a sieve script from the virtual alias file
Owner

smart

smart
Gonne marked this conversation as resolved
Gonne merged commit c078a05ad0 into main 2025-03-24 19:38:06 +00:00
Sign in to join this conversation.
No reviewers
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Fachschaft/nixConfig#55
No description provided.