Mail machine #47

Merged
Gonne merged 9 commits from Gonne/nixConfig:nyarlathotep into main 2025-02-27 15:59:49 +00:00
Owner

A general replacement of Eihort with software that probably allows for easier DKIM and DMARC setup

TODO list:

  • reinstall kaalut after bricking on full disk
  • fix admin login that somehow does not work
  • sync alias files from eihort
  • include correct passwords for HRZ allowlist
  • …?

Optional for deployment:

  • fix collection of local mail accounts for HRZ API
  • refactor sieve generation from first try
  • DKIM
  • DMARC
  • …?
A general replacement of Eihort with software that probably allows for easier DKIM and DMARC setup TODO list: - [x] reinstall kaalut after bricking on full disk - [x] fix admin login that somehow does not work - [x] sync alias files from eihort - [x] include correct passwords for HRZ allowlist - [ ] …? Optional for deployment: - [x] fix collection of local mail accounts for HRZ API - [x] refactor sieve generation from first try - [ ] DKIM - [ ] DMARC - [ ] …?
Gonne added 2 commits 2024-11-22 21:28:45 +00:00
requested review from Server-Minions 2024-11-22 21:29:09 +00:00
Gonne force-pushed nyarlathotep from 84e613f0b0 to 044326ad38 2024-11-23 08:40:23 +00:00 Compare
Gonne force-pushed nyarlathotep from 044326ad38 to 597f4d365c 2024-11-23 09:15:35 +00:00 Compare
Gonne force-pushed nyarlathotep from 597f4d365c to 85131d6f36 2024-11-23 20:56:13 +00:00 Compare
Gonne changed title from WIP: Mail machine to Mail machine 2024-11-23 20:59:23 +00:00
Gonne force-pushed nyarlathotep from 85131d6f36 to e3006b8e03 2024-11-25 20:31:40 +00:00 Compare
Gonne force-pushed nyarlathotep from e3006b8e03 to b3aac99ca7 2024-11-26 18:26:13 +00:00 Compare
Gonne force-pushed nyarlathotep from b3aac99ca7 to 3bb4dcb120 2024-11-27 12:42:07 +00:00 Compare
Gonne force-pushed nyarlathotep from 3bb4dcb120 to 42102bb1a0 2024-11-29 10:46:15 +00:00 Compare
Gonne force-pushed nyarlathotep from 42102bb1a0 to d2ab4d8eea 2024-12-02 19:55:14 +00:00 Compare
Gonne reviewed 2024-12-13 17:29:29 +00:00
flake-module.nix Outdated
@ -56,0 +56,4 @@
overlays = [
(_: _: {
alias-to-sieve = inputs.alias-to-sieve.packages.x86_64-linux.default; # add custom package to convert alias files to sieve scripts on the stalwart machine
Author
Owner

The package selection should depend on system, and is there a reason we overlay like this and not
just use flake-inputs.alias-to-sieve... in the system config?

The package selection should depend on system, and is there a reason we overlay like this and not just use `flake-inputs.alias-to-sieve...` in the system config?
Author
Owner

The flake-inputs parameter is not available as a module parameter while pkgs is supplied by the nix module system.

The `flake-inputs ` parameter is not available as a module parameter while `pkgs` is supplied by the nix module system.
Gonne marked this conversation as resolved
@ -0,0 +41,4 @@
sops.secrets = {
# Password for the HRZ API that gets a list of mailaddresses that we serve
allowlistPassMatheball = {
sopsFile = ./allowlistPassMatheball.yaml;
Author
Owner

The passwords can be in one yaml file and still be exposed as different secrets by sops. This can
be managed by the yaml structure

The passwords can be in one yaml file and still be exposed as different secrets by sops. This can be managed by the yaml structure
Gonne marked this conversation as resolved
@ -0,0 +1,301 @@
/*
* Building: For some reason, stalwart is not served by cache.nixos.org and thus needs to be built locally.
Author
Owner

ufff

ufff
Gonne marked this conversation as resolved
@ -0,0 +1,301 @@
/*
* Building: For some reason, stalwart is not served by cache.nixos.org and thus needs to be built locally.
* Be aware that this needs some hours, about 12Gb RAM and a few Gb free space in /tmp.
Author
Owner

double uff

double uff
Gonne marked this conversation as resolved
@ -0,0 +2,4 @@
* Building: For some reason, stalwart is not served by cache.nixos.org and thus needs to be built locally.
* Be aware that this needs some hours, about 12Gb RAM and a few Gb free space in /tmp.
* Forwarding mails: Update the Sops-secrets in the machine directory, rebuild and deploy.
* Everything else should happen automatically but new redirects might take up to two hours due HRZ infrastructure.
Author
Owner

isn't really a problem, this means we have time to rebuild stalwart to deploy the new alias

isn't really a problem, this means we have time to rebuild stalwart to deploy the new alias
Gonne marked this conversation as resolved
@ -0,0 +5,4 @@
* Everything else should happen automatically but new redirects might take up to two hours due HRZ infrastructure.
* Using the web admin interface: Set your SSH to do portforwarding of some local port to port 80 of the VM and
* and use your personal admin account or create one using the fallback admin password.
* Create users with mail boxes: Go to the admin interface and create them.
Author
Owner

if the mailboxes are data on the machine, maybe the aliases should be too. This would also spare us to rebuild stalwart to update an alias

if the mailboxes are data on the machine, maybe the aliases should be too. This would also spare us to rebuild stalwart to update an alias
Author
Owner

If only aliases are changed rebuilds on the VM itself are fast and lean.

If only aliases are changed rebuilds on the VM itself are fast and lean.
Gonne marked this conversation as resolved
@ -0,0 +31,4 @@
type = listOf (lib.types.submodule {
options = {
domain = mkOption {
type = str;
Author
Owner

did you think about a more specialized type, non empty string? string matching regex? something like this?

did you think about a more specialized type, non empty string? string matching regex? something like this?
Gonne marked this conversation as resolved
@ -0,0 +47,4 @@
};
config = mkIf cfg.enable {
environment.systemPackages = [pkgs.alias-to-sieve]; # install converter from alias files to sieve scripts
Author
Owner

does this need to be a system wide package or can we just call it in the right places?

does this need to be a system wide package or can we just call it in the right places?
Author
Owner

There is no need for system wide.

There is no need for system wide.
Gonne marked this conversation as resolved
@ -0,0 +62,4 @@
protocol = "smtp";
};
"submissions" = {
# Enabling sending from these domains privately blocked on https://github.com/stalwartlabs/mail-server/issues/618
Author
Owner

???

???
Gonne marked this conversation as resolved
@ -0,0 +73,4 @@
tls.implicit = true;
};
"management" = {
bind = ["[::]:80"]; # This must also bind publically for ACME to work.
Author
Owner

maybe a comment what cthulhu should forward to us, and on which connections it handles tls

maybe a comment what cthulhu should forward to us, and on which connections it handles tls
Gonne marked this conversation as resolved
@ -0,0 +87,4 @@
};
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
Author
Owner

lol

can we do it?

lol can we do it?
Gonne marked this conversation as resolved
@ -0,0 +110,4 @@
}
{"else" = "'hrz'";}
];
tls = {
Author
Owner

this is fine because we only talk to vms and hrz which are "trusted" entities

this is fine because we only talk to vms and hrz which are "trusted" entities
Gonne marked this conversation as resolved
@ -0,0 +120,4 @@
address = "mailout.hrz.tu-darmstadt.de";
port = 25;
protocol = "smtp";
tls.implicit = false; # somehow this is needed here
Author
Owner

I HATE starttls can we burn down the hrz already?

I HATE starttls can we burn down the hrz already?
Gonne marked this conversation as resolved
@ -0,0 +132,4 @@
session.rcpt = {
# In order to accept mail that we only forward
# without having to generate an account.
# Invalid addresses are filtered by DFN beforehand.
Author
Owner

I love how we kind of abuse being in a shielded environment

I love how we kind of abuse being in a shielded environment
Gonne marked this conversation as resolved
@ -0,0 +142,4 @@
{"else" = false;}
];
};
config.local-keys =
Author
Owner

this needs a comment!

this needs a comment!
Gonne marked this conversation as resolved
@ -0,0 +165,4 @@
authentication.fallback-admin = {
user = "admin";
secret = "$argon2i$v=19$m=4096,t=3,p=1$d0hYOTkzclpzSmFTZUplWnhVeWE$I7q9uB19RWL0oZKaPlMPSlGfFp6FQ/vrx80FFKCsalg"; # see machine secret for plaintext
Author
Owner

comment is outdated

comment is outdated
Gonne marked this conversation as resolved
@ -0,0 +167,4 @@
user = "admin";
secret = "$argon2i$v=19$m=4096,t=3,p=1$d0hYOTkzclpzSmFTZUplWnhVeWE$I7q9uB19RWL0oZKaPlMPSlGfFp6FQ/vrx80FFKCsalg"; # see machine secret for plaintext
};
tracer.stdout.level = "debug";
Author
Owner

in production?

in production?
Gonne marked this conversation as resolved
@ -0,0 +202,4 @@
}: ''
echo "process ${domain}"
# Get the mail addresses' local-part
${pkgs.curl}/bin/curl -s --header "authorization: Basic $(</run/secrets/stalwartAdmin)" http://localhost/api/principal | ${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&'*+-/=?^_{|}~]*@${domain}" | tee /tmp/addresses
Author
Owner

This line needs explanation. A LOT OF IT

This line needs explanation. A LOT OF IT
Gonne marked this conversation as resolved
@ -0,0 +205,4 @@
${pkgs.curl}/bin/curl -s --header "authorization: Basic $(</run/secrets/stalwartAdmin)" http://localhost/api/principal | ${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&'*+-/=?^_{|}~]*@${domain}" | tee /tmp/addresses
${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.
# Post local-parts to HRZ
${pkgs.curl}/bin/curl -s https://www-cgi.hrz.tu-darmstadt.de/mail/whitelist-update.php -F emaildomain=${domain} -F password=$(cat ${allowlistPass}) -F emailliste=@/tmp/addresses -F meldungen=voll
Author
Owner

A linkt to hrz docu, so we can look at it if something breaks

A linkt to hrz docu, so we can look at it if something breaks
Gonne marked this conversation as resolved
Gonne added 1 commit 2024-12-14 16:31:55 +00:00
Gonne force-pushed nyarlathotep from d89b132fa1 to 6dbd7d6a80 2024-12-15 08:32:28 +00:00 Compare
Author
Owner

We may also want to manage mailboxes in config

We may also want to manage mailboxes in config
Gonne force-pushed nyarlathotep from 6dbd7d6a80 to bbea28a6cf 2024-12-16 19:00:38 +00:00 Compare
Gonne force-pushed nyarlathotep from bbea28a6cf to 1160081e82 2025-01-05 14:04:26 +00:00 Compare
Gonne added 2 commits 2025-01-12 20:32:56 +00:00
Gonne force-pushed nyarlathotep from a15b0ee5d6 to 6fee31dcf1 2025-02-20 15:44:40 +00:00 Compare
nerf changed title from Mail machine to WIP: Mail machine 2025-02-20 16:01:33 +00:00
Gonne added 1 commit 2025-02-21 19:08:46 +00:00
Gonne added 1 commit 2025-02-23 21:24:17 +00:00
Gonne added 1 commit 2025-02-24 09:09:45 +00:00
Gonne added 1 commit 2025-02-24 21:47:47 +00:00
Gonne force-pushed nyarlathotep from 00c753debc to 5f2ded90f5 2025-02-25 13:27:08 +00:00 Compare
Gonne force-pushed nyarlathotep from 5f2ded90f5 to 86e1841131 2025-02-25 13:37:12 +00:00 Compare
Gonne force-pushed nyarlathotep from 86e1841131 to f5374c3e80 2025-02-25 17:36:31 +00:00 Compare
Gonne force-pushed nyarlathotep from f5374c3e80 to f6f3464582 2025-02-25 17:42:40 +00:00 Compare
Gonne changed title from WIP: Mail machine to Mail machine 2025-02-25 17:55:49 +00:00
Gonne force-pushed nyarlathotep from f6f3464582 to 8f8ed254f9 2025-02-26 11:30:59 +00:00 Compare
Gonne force-pushed nyarlathotep from 8f8ed254f9 to 70b3a694c4 2025-02-26 11:34:52 +00:00 Compare
Gonne added 1 commit 2025-02-26 13:37:39 +00:00
Gonne force-pushed nyarlathotep from d34eae7e13 to 73441141d0 2025-02-26 13:38:58 +00:00 Compare
nerf requested changes 2025-02-26 17:04:35 +00:00
Dismissed
nerf left a comment
Owner

Take this more as request for comments than actual request for changes, but I don't have this button

Take this more as request for comments than actual request for changes, but I don't have this button
@ -1,19 +1,25 @@
{
Owner

can we separate flake updates in the future, that makes reviewing less painful

can we separate flake updates in the future, that makes reviewing less painful
Gonne marked this conversation as resolved
@ -37,3 +61,2 @@
"locked": {
"lastModified": 1727649413,
"narHash": "sha256-FA53of86DjFdeQzRDVtvgWF9o52rWK70VHGx0Y8fElQ=",
"lastModified": 1737831083,
Owner

maybe we should read this: https://github.com/nix-community/impermanence/pull/242
does this change how we want to handle machine-id files?

maybe we should read this: https://github.com/nix-community/impermanence/pull/242 does this change how we want to handle machine-id files?
Author
Owner

Moved to #51

Moved to https://gitea.mathebau.de/Fachschaft/nixConfig/issues/51
Gonne marked this conversation as resolved
@ -38,2 +62,2 @@
"lastModified": 1727649413,
"narHash": "sha256-FA53of86DjFdeQzRDVtvgWF9o52rWK70VHGx0Y8fElQ=",
"lastModified": 1737831083,
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
Owner

and does this fix our bind mount problems https://github.com/nix-community/impermanence/issues/237 ?

and does this fix our bind mount problems https://github.com/nix-community/impermanence/issues/237 ?
Gonne marked this conversation as resolved
@ -10,2 +5,2 @@
nixpkgs.follows = "";
};
alias-to-sieve = {
url = "git+https://gitea.mathebau.de/fachschaft/alias_to_sieve";
Owner

not sure if this should be in its own repo or just in this one

not sure if this should be in its own repo or just in this one
Author
Owner

Feels like its own project to me.

Feels like its own project to me.
Gonne marked this conversation as resolved
@ -0,0 +1,52 @@
allowlistPass:
Owner

Is there a reason why the secrets are in different files? If yes we probably want to mention the reason somewhere

Is there a reason why the secrets are in different files? If yes we probably want to mention the reason somewhere
Author
Owner

They feel large enough to me that different files are easier to navigate. But I don't mind.

They feel large enough to me that different files are easier to navigate. But I don't mind.
Owner

I understand this for the alias files, but why don't pool the rest?

I understand this for the alias files, but why don't pool the rest?
@ -0,0 +6,4 @@
* Forwarding mails: Update the Sops-secrets in the machine directory, rebuild on the VM and deploy.
* Everything else should happen automatically but new redirects might take up to two hours due HRZ infrastructure.
* Using the web admin interface: Set your SSH to do portforwarding of some local port to port 80 of the VM and
* and use your personal admin account or create one using the fallback admin password.
Owner

This should either move somewhere closer to main documentation or should have a reference at least a reference.
This seems important and I probably wouldn't look here first to find this information.

This should either move somewhere closer to main documentation or should have a reference at least a reference. This seems important and I probably wouldn't look here first to find this information.
Author
Owner

I think its intuitive here and will wait for specific suggestions.

I think its intuitive here and will wait for specific suggestions.
Owner

I think we should open an issue, to start a doc folder. I also want to write a document for people to get started. I kind of think the README has outgrown this purpose.

I think we should open an issue, to start a doc folder. I also want to write a document for people to get started. I kind of think the README has outgrown this purpose.
@ -0,0 +34,4 @@
description = "Path to a file that contains the stalwart fallback admin password encoded for HTTP Basic Auth";
};
stalwartAdminHash = mkOption {
type = str;
Owner

nonempty?

nonempty?
Gonne marked this conversation as resolved
@ -0,0 +98,4 @@
domains = ["fb04184.mathematik.tu-darmstadt.de" "imap.mathebau.de" "smtp.mathebau.de"];
default = true;
};
spam.header.is-spam = "Dummyheader"; # disable moving to spam which would conflict with forwarding
Owner

maybe make a note here, so we find this again after we have DKIM and DMARC

maybe make a note here, so we find this again after we have DKIM and DMARC
Gonne marked this conversation as resolved
@ -0,0 +100,4 @@
};
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
Owner
https://www.hrz.tu-darmstadt.de/hrz_aktuelles/news_details_177024.en.jsp Maybe parts of this are now?
Author
Owner

I would like to evaluate this in production based on logs.

I would like to evaluate this in production based on logs.
Owner

Fine by me, that should be an easy fix

Fine by me, that should be an easy fix
@ -0,0 +126,4 @@
tls = {
# we only talk to HRZ and our own VMs anyway
mta-sts = "disable";
dane = "disable";
Owner

I'm sad about the state of DANE. I like it.

I'm sad about the state of DANE. I like it.
Gonne marked this conversation as resolved
@ -0,0 +127,4 @@
# we only talk to HRZ and our own VMs anyway
mta-sts = "disable";
dane = "disable";
starttls = "optional"; # e.g. Lobon does not offer starttls
Owner

Is there a domain specific option? then we could only disable this for mailman and else require it.

Is there a domain specific option? then we could only disable this for mailman and else require it.
Author
Owner

The documentation mentions no such thing.

The documentation mentions no such thing.
Owner

sad, is this an issue for upstream?

sad, is this an issue for upstream?
Author
Owner

Only if someone cares enough to write one. I don't.

Only if someone cares enough to write one. I don't.
@ -0,0 +150,4 @@
catch-all = true;
relay = [
{
"if" = "!is_empty(authenticated_as) || rcpt_domain == 'lists.mathebau.de' || starts_with(remote_ip, '192.168.0.')"; #TODO restrict trust by IP
Owner

does this only work for local ipv4 connections? That might change at some point, right?

does this only work for local ipv4 connections? That might change at some point, right?
Author
Owner

Yes, but we probably want to give credentials to the VMs and remove the trust by IP anyways.

Yes, but we probably want to give credentials to the VMs and remove the trust by IP anyways.
Owner

Fine by me, but we will need to document somewhere how this is done. Else people after us will be lost

Fine by me, but we will need to document somewhere how this is done. Else people after us will be lost
@ -0,0 +157,4 @@
];
};
# Stalwart gets its configuration from two places: A TOML configuration file that we control in this module
Owner

Ok, so in the TOML file there is a list of options that defines which options are set in the remainder of the TOML file. I didn't read that from this comment. (And maybe my understanding is still wrong)

Ok, so in the TOML file there is a list of options that defines which options are set in the remainder of the TOML file. I didn't read that from this comment. (And maybe my understanding is still wrong)
Gonne marked this conversation as resolved
@ -0,0 +185,4 @@
authentication.fallback-admin = {
user = "admin";
# see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH
Owner

I think we need a note of the places that we need to touch when we need to update this password

I think we need a note of the places that we need to touch when we need to update this password
Gonne marked this conversation as resolved
@ -0,0 +188,4 @@
# see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH
secret = cfg.stalwartAdminHash;
};
store = {
Owner

should we run a centralized postgres?
This database will handle mailboxes, some DKIM keys and stuff.

should we run a centralized postgres? This database will handle mailboxes, some DKIM keys and stuff.
Author
Owner

Out of scope.

Out of scope.
Gonne marked this conversation as resolved
@ -0,0 +226,4 @@
}: ''
echo "process ${domain}"
# This line gets the available mailboxes from stalwart's Rest API, searches for their addresses and collects them to a file for submission.
${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
Owner

can we have a comment for this regex?

can we have a comment for this regex?
Gonne marked this conversation as resolved
@ -0,0 +228,4 @@
# This line gets the available mailboxes from stalwart's Rest API, searches for their addresses and collects them to a file for submission.
${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
# 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.
Owner

and this one? is it the same?

and this one? is it the same?
Gonne marked this conversation as resolved
@ -0,0 +239,4 @@
serviceConfig = {
Type = "oneshot";
User = "stalwart-mail";
NoNewPrivileges = true;
Owner

I put my trust in you, that these are good

I put my trust in you, that these are good
Gonne marked this conversation as resolved
@ -0,0 +260,4 @@
RestrictSUIDSGID = true;
};
};
"stalwart-mail" = {
Owner

Can we make a comment that this is only an extension of the existing service?

Can we make a comment that this is only an extension of the existing service?
Gonne marked this conversation as resolved
@ -0,0 +271,4 @@
serviceConfig = {
Type = "oneshot";
User = "stalwart-mail";
NoNewPrivileges = true;
Owner

again I just trust you here

again I just trust you here
Gonne marked this conversation as resolved
@ -0,0 +307,4 @@
# We don't want this in order to not need to persist borg cache and simplify new deployments.
BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = "yes";
};
repo = "borg@192.168.1.11:kaluut"; # TODO for https://gitea.mathebau.de/Fachschaft/nixConfig/issues/33
Owner

nyarlathotep

nyarlathotep
Gonne marked this conversation as resolved
Gonne force-pushed nyarlathotep from 73441141d0 to 361eed84af 2025-02-26 17:04:56 +00:00 Compare
Gonne added 1 commit 2025-02-27 12:23:24 +00:00
nerf approved these changes 2025-02-27 15:36:14 +00:00
Dismissed
nerf left a comment
Owner

I want to have an answer if we want to put in an upstream feature request. And I opened another documentation issue, but else I think this is ready to merge.

I want to have an answer if we want to put in an upstream feature request. And I opened another documentation issue, but else I think this is ready to merge.
Gonne force-pushed nyarlathotep from 274412b604 to cc91339f80 2025-02-27 15:55:25 +00:00 Compare
Gonne dismissed nerf's review 2025-02-27 15:55:25 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

Gonne merged commit cc91339f80 into main 2025-02-27 15:59:49 +00:00
Gonne deleted branch nyarlathotep 2025-02-27 15:59:49 +00:00
nerf added this to the Mail is just working milestone 2025-03-19 12:41:01 +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#47
No description provided.