Mail machine #47

Open
Gonne wants to merge 3 commits from Gonne/nixConfig:kaalut into main
7 changed files with 78 additions and 215 deletions
Showing only changes of commit bbea28a6cf - Show all commits

View file

@ -1,4 +1,8 @@
allowlistPassKoMa: ENC[AES256_GCM,data:TGFyk/kVc5+EFtjJXUVTNEk=,iv:QQDiOK81JDQXnuzgrcDHVtu+Pm2Ki7H2sEBuNMSKY9U=,tag:mgd/jPMl7fjl+dH6d2sKTg==,type:str] allowlistPass:
matheball: ENC[AES256_GCM,data:4y83ZJ4=,iv:+B1hTSGs5cskmUA9gLpRHPjhxzvwOrplB+lIbNUKtz4=,tag:ZsKA2A4ltbI3px1Z16EgvA==,type:str]
mathebau: ENC[AES256_GCM,data:D8Ri3fI=,iv:usZ6UktgqOGqtWrJjeZsYhHo/01IzT0aw9Nxgmfe35o=,tag:2tQfIcDd9rPFW/7779HSNw==,type:str]
mathechor: ENC[AES256_GCM,data:3EILes4=,iv:e3Tjlk+BBi2GyPLvhUeshbL3IqKPKlqSjT6+CrgnjYQ=,tag:R5cpo1+2vxI+HfdOvu2WRw==,type:str]
koma: ENC[AES256_GCM,data:bB7px1n5q1+++sctsmIMJg==,iv:DIJGpC9+JyFv3SU9dBVLdnEkRlZzY7DBRAL4zXSbpec=,tag:WaZUGvYtm+5ys2RsBNILog==,type:str]
sops: sops:
kms: [] kms: []
gcp_kms: [] gcp_kms: []
@ -41,8 +45,8 @@ sops:
bDdvdHc3Y1NmeE5WUzl3cXVRc3pmOUkK+9WueS1wDQDJlenec4jJCfynbPnuOFYR bDdvdHc3Y1NmeE5WUzl3cXVRc3pmOUkK+9WueS1wDQDJlenec4jJCfynbPnuOFYR
HFsWmvEZJ+XhH6N9Q0phCHQgZGiR67FH6CHkCblmb6ZfZcWSEe1oTg== HFsWmvEZJ+XhH6N9Q0phCHQgZGiR67FH6CHkCblmb6ZfZcWSEe1oTg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2024-11-23T09:05:51Z" lastmodified: "2024-12-14T15:53:00Z"
mac: ENC[AES256_GCM,data:/OUhbhrO36jEdQUc2+fPfYc13Qezbedo534r+dtULWNR3upzIkP1EnZmTe//TQcKe6GYE/AIWOCIdmfj5+TdXZfoFGZ4YjjFof2HYvDjNKHq7m0F5PFmmzNNkpzUdwHBj5N1usPRoPbsYIpfV74AUJJEeBSTpE76vIATNuE21Js=,iv:Rnh+uIDOPW0vdHPhjqyce9xl7MtURMTrp9kYoWZ6zOA=,tag:jONUKe1pXReqHjtnqCOTjw==,type:str] mac: ENC[AES256_GCM,data:q+Ad2f5ALcBK4/krvmOGXVfNS05vv138Qo4CqNO2hxzryUEzBe5PGYPcx2yExEOEopsv8NGcugNoGQ4nCgaMc7q+t1Feja6dWI85INUt+sE39ws7QAh9IFa2O06AX1WEsUEpnwl3xLWxyCHgKDoaaTfcUENEcPTSVnMwDr/HiwY=,iv:Z+hh06JAm6yfVkclRFfaPZhg0Gjbz0kFdPlYpvMWr+s=,tag:0QUt2WBubt1kKU0pRykfWQ==,type:str]
pgp: [] pgp: []
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.9.1 version: 3.9.2

View file

@ -1,48 +0,0 @@
allowlistPassMatheball: ENC[AES256_GCM,data:cnYmhQ+2sNMR,iv:hSn9JbDce2NZdzptY1Miik4+VFh0i6ehQAGxcd9dJWg=,tag:XI1bE6Z84ppIxPYOasNO/w==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1rasjnr2tlv9y70sj0z0hwpgpxdc974wzg5umtx2pnc6z0p05u3js6r8sln
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHS2ZFM3JQcGx4VFo2M1Fy
T3pnNFg5dEhiaEI4SkNFbDNmV0Y4cDZHa0ZJCjd2SmRwMWtod2pxbEZkY2ZhbWhT
cEFJVHVyU2R0dncvekNFdzNpODlCMDgKLS0tIDRLSGFISXpXMUlzdGdDK1pBb3JX
N3RJVUpsdFZySTVWYlkwbStCaWVRZzgKInXWOMB5LX87zIKcdllGcOBc1CJHcSWP
htTOydt1XQGlZ809yT1Ovnsenk7SIFrtUGCgpSvju4C68FyS8fgJKQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1epz92k2rkp43hkrg3u0jgkzhnkwx8y43kag7rvfzwl9wcddelvusyetxl7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDdk1qdTBZRWYvMFgyZ3NN
QkZpb3BjSnVqRFJzeElCYVp1NDlyQitITGp3ClRtbVhBQnFvU0t5cUZGK0MveExJ
c1RtT2lRZm4ybkgxQ2VmV290SFRId1UKLS0tIEttRFFqTWJHbW54MUxCMHZ2NVA5
NkFnM3R4eTEvdm85TzE5WFJLUTZMclUKpyGsJAAlqRagy13dH3AyeNi9v3oP8R6C
UayJeCPN89IyDsaIsrgAJk67+t92N8wTRIpOzfLEBQzz1WVBYCTPhA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1dhzugelagj6vge5jjxwwn0522ngf7fhxn04sxy2tm8557rtme5tstprwnj
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOT012TTQ1V1ZlMnZycVB6
empqdFc1SE13b1NNSCsyNkRMUWZ2aUdIRlc0CmEwYnp6WVI4SmRaVWRqTUZ5cWJJ
SXpUb3JLT2hNalc2ZlBhOTc2YWdDMkUKLS0tIGFPdW1OS0xFYjF3K01YcVh0bDQr
TjcxNTM3cjZrNnN1RThYUW56WHQ1RzAKvNCz1CW4VwI/YPqzpYfhpvhukbhE3g3Q
31JZhyUViS/tutNy3rUpP+6zS2sY4yKhoavBTmMwI8W9I0JSZaVc5Q==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ktwclxa640l89le6yecm8v2z6hmwr4lusd6x9gyzamhv57887szqtqp59a
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzQytnV3hWODAva0JGdFF4
MC84UmdaKzd1MVloK0dXL1NjS3pGaGY5RGw4CnF5NjlvSUU1N0ZlMHMxVXlhekxH
QkJJR3MzQVdJd2ZrT0t0S3FKMFZaOW8KLS0tICt6SEhEcm1QR0MwQjJ1YllRSlY2
QlZ3Zk1hdkxpNllwSTNxRlZrZWtuVEUK65FpDbLv+S+MvF5+rpTyhjfi9xOUekTP
WupHKoeMMzAFxRK7DcH8bREib731JgBPbZEl8QZcY+xZDORnv1XZhg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-11-23T09:05:51Z"
mac: ENC[AES256_GCM,data:qA7d/k9vSQIvtdHOx20yfi98s5jgdGPYsP2c1rNrX4MeZnJ4RE+KR8wR37A54AvgOURUnTJUSfDNKGuTIPxioRC1j8iNlo/y0IefkbTaO2CBoh+BHurlh6wweTKI3LRUk8V0i5Qn/5INYc+DEzfsiA2g+QcbT5d0fU98+x7V/yY=,iv:xcgMXDFDN0Vo15rr2Eo6QV/Y5+X0t0mvAfuFmN1NDXY=,tag:PywW0L+VspBh2pZGXbM+sA==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.9.1

View file

@ -1,48 +0,0 @@
allowlistPassMathebau: ENC[AES256_GCM,data:DuCBcWAC61JW,iv:g0zYvVmTjsJESTq3kkWtaiypYPLIE6zkFyYLeOp/qhw=,tag:pyK6KMuPLkhLSTPAzbVxdQ==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1rasjnr2tlv9y70sj0z0hwpgpxdc974wzg5umtx2pnc6z0p05u3js6r8sln
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaaWhNaDFEREcrejY2ejhI
L0tnOEtTWktNVDVoK1JQd3pBY1BndTY1NUFjCjFFSEd2Nkc2TVVMYzlwRXhyenVq
WmlCZkc4VWtFS1drNDRjRXR6SEVoYVEKLS0tIDRCQjJkdUM0V1BGV0hVNUtNQ1d4
M2J2TEtPTjRVVG8yOHd6WThRNm5SU2MKVIAU8GCGklXvqNf0bpahJ4SsvIQxMged
m6mznRxcK9QPMApHayOBgw+8T+3IQkaEKGRuhI1y9UXahGSr8yxPYA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1epz92k2rkp43hkrg3u0jgkzhnkwx8y43kag7rvfzwl9wcddelvusyetxl7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRTkNiVWo3SWFmaFlENm5C
cDlJdHM0OXBnTFdYV1NtTHFmTndndTdwQWhRCitMTVJIcnpiRzEvL3JzMTZJMW9p
NTlIREJ5VVpLTVplWVNhSFFDMlVpNTQKLS0tIFkvMjYvVy9DZUZSVDVvQTkzck1F
ZHM5M2tRVUVIYmR5L1FsR3VxNUZSdW8KWIq5Cjbd12SqQfXRZDpUxTnUZGCyMVb+
XxCixIFoGYZRTBc15k/Z6yM5OxYnSv3tbioF68PYtPaaRJrw0ICDxQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1dhzugelagj6vge5jjxwwn0522ngf7fhxn04sxy2tm8557rtme5tstprwnj
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLUWVHME1JN0gvZlNDQkFt
YTFsRG12UWlLckVLanNGQlozSXFaVGhMQWdzCndPdnRnNFU2dUpQangxUGU1RGVG
Z0Z5SmxZVG1jYW91YW5Jc1UwY25yOEkKLS0tIDJ1U2w1RzhpUk5WR0JUbzhRSStE
VnZpWUFwaHFMa2V6NlpQR285RGU0L2cKeN08hqlFz4re9iVwKmp2THEs1vZFqNXg
uK9Em5IeCx3pBjd5nnguAM751vR9X5O91ntA/R3MoL2bxGhbXHbOmA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ktwclxa640l89le6yecm8v2z6hmwr4lusd6x9gyzamhv57887szqtqp59a
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXYStiSFpMWjh3M0EydEU4
YlBpcFNYRXJTN0k4MWQ3blFmdW4zTHR6MWhrCmtsVkpGNFlIT0xBQU9SSG45czhU
NzlKSm9RMStFZXpselNBa3NpNGM5SzAKLS0tIDh0LzI0SkdlM0hONmF4RndCV2Q2
VmwxWjcxVG5Kd1pPYUdpWDJCZkU3Q00Kbc8dYrQ2AiRAUfzXl6Bdj1mlbwlHSKzS
6B/wzrIB3yws4QXCdZsIifxsGqJh/74UdQSXEab0VNwaHqsyXecIjw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-11-23T09:05:51Z"
mac: ENC[AES256_GCM,data:JLCK4mH4yS4YMhrmI821s/TfONkCyEx8x+pFHD/QOoU4KHyhDIggEhTYo31JFpWIQdDZMPbeFaUN+IvQwh1pqD1V92XfJVC0zHPiwhG7W2kI8WFAONVqI/bbMJ/ne4am5w/koGpQNPiM2RIo+9/9BKOkyLJLB7XTqPBY/FNW2n0=,iv:JiHwaSbPJSJYofiFABjn/AehSKyRrlOKHXBs1DGZcFQ=,tag:ajR0zYdHWxQcY2DhAuAzAw==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.9.1

View file

@ -1,48 +0,0 @@
allowlistPassMathechor: ENC[AES256_GCM,data:CuLKFiBN6JwB,iv:cwiwShPKrGjjfuglRttmG/AB+qblJ/6ZLyD88mAsZ30=,tag:JIJjHJ4it077RSD3pSOBgg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1rasjnr2tlv9y70sj0z0hwpgpxdc974wzg5umtx2pnc6z0p05u3js6r8sln
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnQzBXNVFObnk5OWtaemNz
UlFDTFpGRmJ6N0xYUmx3dllzS3hyWmNURmxRCm1CbmpSNWRkVHR5M21ibmJ4ZzNJ
elZQQ0UyN3lOTmRwQ2tnL1lHUFF5djgKLS0tIFUvRUkwSW0wSFhCMFByTkI0eEo4
emdnN2JoMDVOb3FUTmZhZFIxWFhxZEkKDWFrvxDHjybQ2b9hORThAG2TihGdvaK0
EHrzz0h1NVEO/nLUJSXRugGJ+J1GqThgOG1WCwJ+2Fk4Hm+q040DWQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1epz92k2rkp43hkrg3u0jgkzhnkwx8y43kag7rvfzwl9wcddelvusyetxl7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkbmQ3ZXdhZkV2VTMxTUFK
eHM5aXAyNXdtV2ZkRVZKTC9GdWtDWUJtdFFFCkdBMWs3OFltRjFLVU1rSG52NGo2
Q0dnS1V2c01EdVRuRGlsZ0lQT1JtUG8KLS0tIHErblZ6U01HTm1FUVJTZjdGQ2RB
bE90R0NsdkQ2UWNrbXZydjR5YTNGVWcK46c5ec7plT6X1874abnSSryG+cUZq/QT
3LpgQs26dc9nIARiZUk/2UTPiUwxFesi7e4I87bWh5A+mQOHNfRAyw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1dhzugelagj6vge5jjxwwn0522ngf7fhxn04sxy2tm8557rtme5tstprwnj
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrUmJXMlFlb0pUbkduWkJK
SWhlUXNqZ0FQeFlEMFppUWR6MHFyS282emhJCkNLMDdaQ2JXRExLT3F2Y094VE90
bTdmNGIvV0JHNlVldTVxUmdueTllYWsKLS0tIDAvNlhRQnFKSW5JT004WDFhSGEv
M0hKbWxuWjRlUWlRaHBQQUpkVlM4dTQKm4vPZTHMIfk79dTOO7mP9IZaJZbu3hx8
J/y5xwUFVakqPaX144YZXjjStsjp6H71jE+z3EWeqvW3hwI8XAOv/w==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ktwclxa640l89le6yecm8v2z6hmwr4lusd6x9gyzamhv57887szqtqp59a
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0ZGFsenFjQkRBTCtsVXRI
VnpQZmVld0VFZ09hWTdlSjNzczA1T1VhWkZrCkpRUml1UFJrU2laQ1FEVi9USEg2
Y3J5VlZCVG83UUh0bnRVbkZRVWVMMlUKLS0tIEl1VUFPQ3NvMm40clFTMHcwRzlC
dENsZ2ttbFI1aGdFYlZ0M1crZGlRek0KWF+sAOdOGf7GKkY3ZlfPkXGGDwSf89Lk
uvSkh+2Y9RIkQ7HRUvWxPBPi4vBUUhM7y5+lA8sNi+lLMzPyzVeKaQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-11-23T09:05:51Z"
mac: ENC[AES256_GCM,data:4LMhli417gbzauxvsx+cSA0VfCt5+dr1lsGdzVqNts/ELcCxlH2599V/xPdgZJYvbvY/AUDEVc6/7vodqtxsI9d99P9AD9IRaETqHkQ2RmPfyUHLJL8kgLdcql6zBdlZTpy05438Bs53sOQMWCcUmE2TohH9jlvmwpqCaRgfYf0=,iv:BkfHGIFAdlSIjdLvqOeaeoIkBaMQ5yXqYBFgGBrzMjk=,tag:7+vgwa89KxeXWNvfbiKSsg==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.9.1

View file

@ -1,4 +1,4 @@
{ {config, ...}: {
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
../../modules/mail.nix ../../modules/mail.nix
@ -10,26 +10,29 @@
# System configuration here # System configuration here
services.mathebau-mail = { services.mathebau-mail = {
enable = true; enable = true;
stalwartAdmin = config.sops.secrets.stalwartAdmin.path;
# see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH
stalwartAdminHash = "$argon2i$v=19$m=4096,t=3,p=1$d0hYOTkzclpzSmFTZUplWnhVeWE$I7q9uB19RWL0oZKaPlMPSlGfFp6FQ/vrx80FFKCsalg";
domains = [ domains = [
# lists.mathebau.de is forwarded to another VM and does not need to be listed here. # lists.mathebau.de is forwarded to another VM and does not need to be listed here.
{ {
domain = "matheball.de"; domain = "matheball.de";
allowlistPass = "/run/secrets/allowlistPassMatheball"; allowlistPass = config.sops.secrets."allowlistPass/matheball".path;
} }
{ {
domain = "mathebau.de"; domain = "mathebau.de";
allowlistPass = "/run/secrets/allowlistPassMathebau"; allowlistPass = config.sops.secrets."allowlistPass/mathebau".path;
virt_aliases = "/run/secrets/mathebau.aliases"; virt_aliases = config.sops.secrets."mathebau.aliases".path;
} }
{ {
domain = "mathechor.de"; domain = "mathechor.de";
allowlistPass = "/run/secrets/allowlistPassMathechor"; allowlistPass = config.sops.secrets."allowlistPass/mathechor".path;
virt_aliases = "/run/secrets/mathechor.aliases"; virt_aliases = config.sops.secrets."mathechor.aliases".path;
} }
{ {
domain = "koma89.tu-darmstadt.de"; domain = "koma89.tu-darmstadt.de";
allowlistPass = "/run/secrets/allowlistPassKoMa"; allowlistPass = config.sops.secrets."allowlistPass/koma".path;
virt_aliases = "/run/secrets/koma.aliases"; virt_aliases = config.sops.secrets."koma.aliases".path;
} }
]; ];
}; };
@ -38,32 +41,19 @@
vmNetwork.ipv4 = "192.168.0.17"; vmNetwork.ipv4 = "192.168.0.17";
system.stateVersion = "24.05"; system.stateVersion = "24.05";
sops.secrets = { sops.secrets = let
allowlistSops = {
sopsFile = ./allowlistPass.yaml;
owner = "stalwart-mail";
group = "stalwart-mail";
mode = "0400";
};
in {
# Password for the HRZ API that gets a list of mailaddresses that we serve # Password for the HRZ API that gets a list of mailaddresses that we serve
allowlistPassMatheball = { "allowlistPass/matheball" = allowlistSops;
sopsFile = ./allowlistPassMatheball.yaml; "allowlistPass/mathebau" = allowlistSops;
owner = "stalwart-mail"; "allowlistPass/mathechor" = allowlistSops;
group = "stalwart-mail"; "allowlistPass/koma" = allowlistSops;
mode = "0400";
};
allowlistPassMathebau = {
sopsFile = ./allowlistPassMathebau.yaml;
owner = "stalwart-mail";
group = "stalwart-mail";
mode = "0400";
};
allowlistPassMathechor = {
sopsFile = ./allowlistPassMathechor.yaml;
owner = "stalwart-mail";
group = "stalwart-mail";
mode = "0400";
};
allowlistPassKoMa = {
sopsFile = ./allowlistPassKoMa.yaml;
owner = "stalwart-mail";
group = "stalwart-mail";
mode = "0400";
};
# Virtual alias file # Virtual alias file
"mathebau.aliases" = { "mathebau.aliases" = {
sopsFile = ./mathebau.aliases.yaml; sopsFile = ./mathebau.aliases.yaml;

View file

@ -1,7 +1,9 @@
/* /*
* Building: For some reason, stalwart is not served by cache.nixos.org and thus needs to be built locally. * Building: For some reason, stalwart is not served by cache.nixos.org and thus needs to be built locally.
Gonne marked this conversation as resolved
Review

ufff

ufff
* 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 12Gb RAM and a few Gb free space in /tmp.
Gonne marked this conversation as resolved
Review

double uff

double uff
* Forwarding mails: Update the Sops-secrets in the machine directory, rebuild and deploy. * If you only want to deploy configuration changes and no software updates, consider building on the target VM.
* It has stalwart in its nix store and does not need to rebuild it.
* 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. * 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 * Using the web admin interface: Set your SSH to do portforwarding of some local port to port 80 of the VM and
Gonne marked this conversation as resolved
Review

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
Review

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.
* and use your personal admin account or create one using the fallback admin password. * and use your personal admin account or create one using the fallback admin password.
@ -22,24 +24,34 @@
mkEnableOption mkEnableOption
mkOption mkOption
; ;
inherit (lib.types) listOf str; inherit (lib.types) listOf strMatching str path;
cfg = config.services.mathebau-mail; cfg = config.services.mathebau-mail;
in { in {
options.services.mathebau-mail = { options.services.mathebau-mail = {
enable = mkEnableOption "mathebau mail service"; enable = mkEnableOption "mathebau mail service";
stalwartAdmin = mkOption {
type = path;
description = "Path to a file that contains the stalwart fallback admin password encoded for HTTP Basic Auth";
};
stalwartAdminHash = mkOption {
type = str;
description = "String containing the hashed fallback admin password";
};
domains = mkOption { domains = mkOption {
type = listOf (lib.types.submodule { type = listOf (lib.types.submodule {
options = { options = {
domain = mkOption { domain = mkOption {
type = str; description = "Domain name that we serve. We also push its addresses to HRZ.";
type = strMatching "^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$"; #Regex from https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch08s15.html
}; };
allowlistPass = mkOption { allowlistPass = mkOption {
# Password for the HRZ API that gets a list of mailaddresses that we serve description = "Password file for the HRZ API that gets a list of mailaddresses that we serve";
type = str; type = path;
}; };
virt_aliases = mkOption { virt_aliases = mkOption {
type = str; description = "File path to a virtual alias file applicable for this domain";
default = ""; type = path;
default = "/dev/null"; # there might not be an alias file and reading an empty one works with our implementation
}; };
}; };
}); });
@ -47,8 +59,6 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [pkgs.alias-to-sieve]; # install converter from alias files to sieve scripts
services = { services = {
stalwart-mail = { stalwart-mail = {
enable = true; enable = true;
@ -57,12 +67,13 @@ in {
server = { server = {
lookup.default.hostname = "fb04184.mathematik.tu-darmstadt.de"; # Because the DNS PTR of 130.83.2.184 is this and this should be used in SMTP EHLO. lookup.default.hostname = "fb04184.mathematik.tu-darmstadt.de"; # Because the DNS PTR of 130.83.2.184 is this and this should be used in SMTP EHLO.
listener = { listener = {
# Do not enable JMAP until https://github.com/stalwartlabs/mail-server/issues/618 is resolved!
# Luckily, this bug does not apply to IMAP.
"smtp" = { "smtp" = {
bind = ["[::]:25"]; bind = ["[::]:25"];
protocol = "smtp"; protocol = "smtp";
}; };
"submissions" = { "submissions" = {
Gonne marked this conversation as resolved
Review

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
# Enabling sending from these domains privately blocked on https://github.com/stalwartlabs/mail-server/issues/618
bind = ["[::]:465"]; bind = ["[::]:465"];
protocol = "smtp"; protocol = "smtp";
tls.implicit = true; tls.implicit = true;
@ -73,7 +84,11 @@ in {
tls.implicit = true; tls.implicit = true;
}; };
"management" = { "management" = {
bind = ["[::]:80"]; # This must also bind publically for ACME to work. # Cthulhu forwards requests for http://fb04184.mathematik.tu-darmstadt.de/.well-known/acme-challenge/ http://imap.mathebau.de/.well-known/acme-challenge/ and http://smtp.mathebau.de/.well-known/acme-challenge/
# for TLS certificate challenge validation
# whereas the rest of the management interface is not available publically.
# It can be reached via SSH and portforwarding.
bind = ["[::]:80"];
protocol = "http"; protocol = "http";
}; };
}; };
@ -111,6 +126,7 @@ in {
{"else" = "'hrz'";} {"else" = "'hrz'";}
]; ];
tls = { tls = {
# we only talk to HRZ and our own VMs anyway
mta-sts = "disable"; mta-sts = "disable";
dane = "disable"; dane = "disable";
starttls = "optional"; # e.g. Lobon does not offer starttls starttls = "optional"; # e.g. Lobon does not offer starttls
@ -120,13 +136,13 @@ in {
address = "mailout.hrz.tu-darmstadt.de"; address = "mailout.hrz.tu-darmstadt.de";
port = 25; port = 25;
protocol = "smtp"; protocol = "smtp";
tls.implicit = false; # somehow this is needed here tls.implicit = false; # Don't assume TLS on this port but use STARTTLS
}; };
remote."mailman" = { remote."mailman" = {
address = "lobon.mathebau.de"; # must be created in DNS as a MX record because this field does not accept ip addresses. address = "lobon.mathebau.de"; # must be created in DNS as a MX record because this field does not accept ip addresses.
port = 25; port = 25;
protocol = "smtp"; protocol = "smtp";
tls.implicit = false; # somehow this is needed here tls.implicit = false; # Don't assume TLS on this port but use STARTTLS
}; };
session.rcpt = { session.rcpt = {
@ -142,6 +158,12 @@ in {
{"else" = false;} {"else" = false;}
]; ];
}; };
# 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
# because only TOML-based keys may use macros to load files from disk.
# We want this to be able to load our sieve-script for mail forwarding.
config.local-keys = config.local-keys =
[ [
Gonne marked this conversation as resolved
Review

comment is outdated

comment is outdated
"store.*" "store.*"
@ -165,9 +187,9 @@ in {
authentication.fallback-admin = { authentication.fallback-admin = {
user = "admin"; user = "admin";
secret = "$argon2i$v=19$m=4096,t=3,p=1$d0hYOTkzclpzSmFTZUplWnhVeWE$I7q9uB19RWL0oZKaPlMPSlGfFp6FQ/vrx80FFKCsalg"; # see machine secret for plaintext # see passwd on azathoth for plaintext or machine secret in encoded format for HTTP Basic AUTH
secret = cfg.stalwartAdminHash;
}; };
tracer.stdout.level = "debug";
}; };
}; };
}; };
@ -201,12 +223,13 @@ in {
... ...
}: '' }: ''
echo "process ${domain}" echo "process ${domain}"
# Get the mail addresses' local-part # 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 $(</run/secrets/stalwartAdmin)" http://localhost/api/principal | ${pkgs.gnugrep}/bin/grep -o -e "[A-Za-z0-9.!#\$%&'*+-/=?^_{|}~]*@${domain}" | tee /tmp/addresses ${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. ${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 # Post local-parts to HRZ, see https://www-cgi.hrz.tu-darmstadt.de/mail/index.php?bereich=whitelist_upload
${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 ${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
# Cleanup # Cleanup submission file
rm /tmp/addresses rm /tmp/addresses
''; '';
in in
@ -241,17 +264,7 @@ in {
}; };
"virt-aliases-generator" = { "virt-aliases-generator" = {
description = "Virtual Aliases Generator: Generate a sieve script from the virtual alias file"; description = "Virtual Aliases Generator: Generate a sieve script from the virtual alias file";
script = let script = lib.strings.concatStringsSep "" (["${pkgs.alias-to-sieve}/bin/alias_to_sieve "] ++ map (x: "${x.virt_aliases} ${x.domain} ") cfg.domains ++ ["> /tmp/virt_aliases"]);
scriptTemplate = {
domain,
virt_aliases,
...
}:
if virt_aliases != ""
then "${virt_aliases} ${domain} "
else "";
in
lib.strings.concatStringsSep "" (["${pkgs.alias-to-sieve}/bin/alias_to_sieve "] ++ map scriptTemplate cfg.domains ++ ["> /tmp/virt_aliases"]);
wantedBy = ["stalwart-mail.service"]; # Rerun on stalwart restart because forwardings may have changed. wantedBy = ["stalwart-mail.service"]; # Rerun on stalwart restart because forwardings may have changed.
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";

View file

@ -35,7 +35,7 @@ in {
proxy_interfaces = "130.83.2.184"; proxy_interfaces = "130.83.2.184";
smtputf8_enable = "no"; # HRZ does not know SMTPUTF8 smtputf8_enable = "no"; # HRZ does not know SMTPUTF8
}; };
relayHost = "192.168.0.24"; # Relay to eihort which relays to HRZ (see https://www.hrz.tu-darmstadt.de/services/it_services/email_infrastruktur/index.de.jsp) relayHost = "mathebau.de"; # Relay to mail vm which relays to HRZ (see https://www.hrz.tu-darmstadt.de/services/it_services/email_infrastruktur/index.de.jsp)
}; };
mailman = { mailman = {
enable = true; enable = true;
@ -64,9 +64,9 @@ in {
systemd.timers."mailAllowlist" = { systemd.timers."mailAllowlist" = {
wantedBy = ["timers.target"]; wantedBy = ["timers.target"];
timerConfig = { timerConfig = {
OnBootSec = "5m"; # Run every 5 minutes OnBootSec = "1h"; # Run every hour
OnUnitActiveSec = "5m"; OnUnitActiveSec = "1h";
RandomizedDelaySec = "2m"; # prevent overload on regular intervals RandomizedDelaySec = "10m"; # prevent overload on regular intervals
Unit = "mailAllowlist.service"; Unit = "mailAllowlist.service";
}; };
}; };