Skip to content

Commit 0b768b8

Browse files
committed
Allow umbriel to send emails as nixos.org
Once this change is deployed, we should be able to start sending test emails from `@nixos.org` email addresses using `umbriel`. I updated our SPF record in a way such that it should allow `umbriel` without breaking our existing email sending capabilities with ImprovMX. This does *not* change our MX (yet): ImprovMX will still be receiving emails send to `nixos.org`. To verify that we can receive emails sent to `nixos.org` addresses, I plan to edit `/etc/hosts` on my personal mailserver and send some test emails. Do folks have better ideas for testing this out?
1 parent c6f24c9 commit 0b768b8

File tree

5 files changed

+80
-46
lines changed

5 files changed

+80
-46
lines changed
-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1 @@
11
# `umbriel`
2-
3-
## Provisioning
4-
5-
If you recreate `umbriel`, it will generate a new `DKIM` signature. That's ok to
6-
do, but you'll need to update the corresponding `mail._domainkey.*` `TXT` DNS
7-
record in `terraform/dns.tf` with the generated key in
8-
`/var/dkim/mail-test.nixos.org.mail.txt`.
9-
10-
TODO: declaratively manage the `DKIM` key once
11-
<https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/merge_requests/344>
12-
lands.

non-critical-infra/modules/mailserver/default.nix

+29-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,33 @@
99

1010
fqdn = config.networking.fqdn;
1111

12-
# TODO: change to `nixos.org` when ready
13-
domains = [ "mail-test.nixos.org" ];
12+
domains = [ "nixos.org" ];
13+
};
14+
15+
sops.secrets."nixos.org.mail.key" = {
16+
format = "binary";
17+
owner = "opendkim";
18+
group = "opendkim";
19+
mode = "0600";
20+
21+
# How to generate:
22+
#
23+
# ```console
24+
# cd non-critical-infra
25+
# DOMAIN=nixos.org
26+
# SELECTOR=mail
27+
# PRIVATE_KEY_PATH=secrets/$DOMAIN.$SELECTOR.key.umbriel
28+
# nix shell nixpkgs#opendkim --command opendkim-genkey --selector="$SELECTOR" --domain="$DOMAIN" --bits=1024
29+
# mv mail.private "$PRIVATE_KEY_PATH"
30+
# sops encrypt --in-place "$PRIVATE_KEY_PATH"
31+
# ```
32+
#
33+
# Next, look at `mail.txt` and update DNS accordingly.
34+
sopsFile = ../../secrets/nixos.org.mail.key.umbriel;
35+
36+
# Ensure the file gets symlinked to where Simple NixOS Mailserver expects
37+
# to find it.
38+
path = "${config.mailserver.dkimKeyDirectory}/nixos.org.mail.key";
1439
};
1540

1641
### Mailing lists go here ###
@@ -22,14 +47,14 @@
2247
# follow the instructions.
2348
mailing-lists = {
2449
# TODO: replace with the real `nixos.org` mailing lists.
25-
"test-list@mail-test.nixos.org" = {
50+
2651
forwardTo = [
2752
2853
../../secrets/jfly-email-address.umbriel
2954
3055
];
3156
};
32-
"test-sender@mail-test.nixos.org" = {
57+
3358
forwardTo = [ "[email protected]" ];
3459
loginAccount.encryptedHashedPassword = ../../secrets/test-sender-email-login.umbriel;
3560
};

non-critical-infra/packages/encrypt-email/encrypt-email.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def login(address_id: str, force: bool) -> None:
149149

150150
nix_code = dedent(
151151
f"""\
152-
"{address_id}@mail-test.nixos.org" = {{
152+
"{address_id}@nixos.org" = {{
153153
forwardTo = [
154154
# Add emails here
155155
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"data": "ENC[AES256_GCM,data:xzDS4Dzi5vDKnLRZCmaH/j5oI5rknLLSzm/BAcqVL3pReOW7rE6C7QGY2EoS99TfLQ3BxB1ckrB4f3/pefEH018KIgJ7UeaeWebmkBFsXF8r+4m/yOEiDWgnGKnsq1EIzbs67AvVYV4rcEPUmTrkeFYd6TOEqIhOSM/6DO6Lg6x+ioAGSEHK6eGgRVIFVjByOhvufhOib1exX2GEM6ayluutig6ToxdnE5jRGIY1gp1bOuwDSazD07RIZanAlS0sjZvMOASacLRvwwM0HC2NEsfHHjy1YMNr1WIbW3HWV/r/j0FTGEDI0W7IP9b0livuAX+K+EixZ6Cw+9ZMhUQMZzfLRcR/c8Zo+hgmc8SJtaPCwck1RlRqOXbqceH1oMIWpYxWmdLIhSQTNgoiMp6L4JzVz7flpnzzEB2U4tkIMwnEBpa8Jz0TAtgyw9clgdbgR+11T56CGzdykbDxPjkDFhnDjhpqmUDgq8rSRRh0fhGdi8FX2rUQXnOMVrYALV0zkAN4cg2Px5dIjlMBZmHkawR7U8phYMBfQRC2FRz9USIrYVTof+J+UImWbWJwa2zMDb5ogRwOF4XhI6NNolCdorlmCvbdG7nE0LbnIbdC1b5VEeVmo0YObnm5HcI11ctugirpXb1kIcfhpg7Zaq3s2iRCbaiy5UVqQNbcKmLktItdxfAzWPQQyyQqA5xA7vlr2jQvKYP7i86H2woKEUwum8htYJewYB3w91NsJaoPikuVLmrBe00hoMwXqb/MtstEhJbI6FN0SC9r+YE8OMvlyoTzmxrysq4/X5qxeXhpbH7fqUxY77UPtOjHfG/vA8cpYHNBnvjXiRGFQwB/P4/fTdtJA5UZiO+EwvNyepadazqmN6szXxHLOcEu+qnoEGsAcbQjjN+y2IUgTXTpje2qfH75141oqhG/DHT4DFDRkI6AMuwQAVtM+6Nqk4hTzJVua8AK+HS+UwBqap0GbtVg3inSuhmcq2wQQzezz6XNpajvEvFosSpIHBwxkBsY6gn/RiCEm7iHvdePhGzOBylX+kLRLp1/PatRLCBVnZ5uwpVGhzdIMvoz7i7+Grmify1XlLuY8hxcmjJzPVn3El5euSeSamDkgdGkaaWeDRaU33OIBo0aRLFnmQeNfm2wwKYba1moqCtuZxSBfze9wiOacAmicUZZ9i2fjcYa/ejtgxTl/k10S4Z6YVhxHvK1y4D5r2zzFA==,iv:lYv/cuI7dQnBq/UAOh0tP1e+GOPgMKzHc66+cmyjZXY=,tag:mEYrazYwd93xOV5Fw5vqHg==,type:str]",
3+
"sops": {
4+
"kms": null,
5+
"gcp_kms": null,
6+
"azure_kv": null,
7+
"hc_vault": null,
8+
"age": [
9+
{
10+
"recipient": "age15vcp7875xwtf64j4yshyld0a3hpgzv6n2kxky493s3q0swr9hdaqxugpv6",
11+
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBalpYcW9xYUZsTi9ZUDJV\nWEV0ZEZKWnMyNXdXUHBmRkkyS1gzaU81bGt3CkZoZVp4OUhmKzU0dkNmOHRFb1I5\nQjBacWVYYWdjSHh4NHFGQlhyNENmb2sKLS0tIGNmZFZjQ2dMYTQ1OFJnNFBLejNo\ndDJ0SUgwVHcvNjRTVVZ5Wis0NDZ1dWcKi2RTUzwVVg2x+9L+96QNwpA32IupkzV7\nmTfRtizJXHbzfUBSCUiuVis92bsk05PBRB9Zw5hQMY7K7ZAkctLprQ==\n-----END AGE ENCRYPTED FILE-----\n"
12+
},
13+
{
14+
"recipient": "age1j3mkgedmeru63vwww6m44zfw09tg8yw6xdzstaq7ejfkvgcau40qwakm8x",
15+
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoWFdCSWd4Z1VwOEU5L3or\nelpPcm9JcDE0eXB1L1hrcVFuaGxQRDN5b1V3CnlyZzhnbkNlVUswWUFLclBqOHdv\nSEwvbTN6R3oyMTc4aS8xSDhkcVFpNVUKLS0tIGh0ZWRuUkFMSEhvRjZuV05zbTNR\ncytkaXlIOG1vQ2RWVnZLaGtJOFQ2dDQK04Fq2wcKRINC9iTCWuDMbJY8QPQAknQk\nTOEvgZ4DRQa/MnG5WGZkoA0PygirZNQTJFge2RRa0YMY+wypQvQNgg==\n-----END AGE ENCRYPTED FILE-----\n"
16+
},
17+
{
18+
"recipient": "age1jrh8yyq3swjru09s75s4mspu0mphh7h6z54z946raa9wx3pcdegq0x8t4h",
19+
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMWUtZd2RzOEhKbnE4THZL\nOXRsMHhJVk9XancrTi9XbGF2SWl4SjU3bm1ZCjlDWlZ3WlU3bDZma0gvbUIwdk5P\nMGt6YVZjOVBGRkFnQ3ZVakl0Z2xjTTgKLS0tIFFzbWlDNi9rNloxUzJHbFd6Qlgr\neVVudjJFSThLeWMvVFozTUg1Yy9JSVkKH4gAq3XTuWVlylHxIOU5l4pbrsU0cFAA\nSAZUQk3TsBw427B02uocjjpTQByuxFxAf3hoV5WgFfEZf04gMlEUUQ==\n-----END AGE ENCRYPTED FILE-----\n"
20+
}
21+
],
22+
"lastmodified": "2025-03-11T08:24:47Z",
23+
"mac": "ENC[AES256_GCM,data:NpYf1LwINXQyuiN4jCkp95Q1UUnp+7M++k28GfGM1oWquOYtUH0wbRKEk1ooIABGSj8uz6qx5KBBGRh8eU6ldh7qwYqqTLDey2qeJ/5kt1ZTC5aOm9qtDWYWYzzb+lznOegSL25ny16d6ipOiKJeCdfcrgJBSr+Y6MCE+GxqGEg=,iv:pzx0e4ySgKmer/zF3wsrN4vVAzPMWE8RPPbkIkx0W5o=,tag:Smm0vqPToCcy2XHyHyVkUw==,type:str]",
24+
"pgp": null,
25+
"unencrypted_suffix": "_unencrypted",
26+
"version": "3.9.4"
27+
}
28+
}

terraform/dns.tf

+22-30
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,6 @@ locals {
206206
type = "TXT"
207207
value = "9e10a04a4b"
208208
},
209-
{
210-
hostname = "nixos.org"
211-
type = "TXT"
212-
value = "v=spf1 include:spf.improvmx.com ~all"
213-
},
214209
{
215210
# hetzner ax162-r 2548595
216211
hostname = "elated-minsky.builder.nixos.org"
@@ -410,29 +405,34 @@ locals {
410405
value = "2a01:4f9:c012:8178::"
411406
},
412407

413-
# Mailserver configuration for `mail-test.nixos.org`
408+
# Mailserver configuration for `nixos.org`
409+
# TODO: remove the 2 MX records for improvmx below in favor of this once
410+
# we're ready to switch to the new mailserver:
411+
# https://github.com/NixOS/infra/issues/485
412+
# {
413+
# hostname = "nixos.org"
414+
# type = "MX"
415+
# value = "umbriel.nixos.org"
416+
# },
414417
{
415-
hostname = "mail-test.nixos.org"
416-
type = "MX"
417-
value = "umbriel.nixos.org"
418-
},
419-
{
420-
hostname = "mail-test.nixos.org"
418+
hostname = "nixos.org"
421419
type = "TXT"
422-
value = "v=spf1 mx ~all"
420+
# TODO: simplify to just a `mx` rule once umbriel is our one and only
421+
# mailserver:
422+
# https://github.com/NixOS/infra/issues/485
423+
# value = "v=spf1 mx ~all"
424+
value = "v=spf1 include:spf.improvmx.com a:umbriel.nixos.org ~all"
423425
},
424426
{
425-
hostname = "mail._domainkey.mail-test.nixos.org"
427+
hostname = "mail._domainkey.nixos.org"
426428
type = "TXT"
427-
# From `/var/dkim/mail-test.nixos.org.mail.txt` on `umbriel`.
428-
value = "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG4Tx788TCAW/sv1h6JefVJChqbaot1yhycwEq0Uo5x9ZIyq43Dkxxl7LdsHIW75HMI7aTKQRru+5xQ26vQmwiIRFJlJlRSYzlZZ2xnFZPXQ27dXnFh7MxLGC7YEyQFksiA2xxgqtQSyIvwu1whm2WK0fXkoJf87SgTtVjjKjnkQIDAQAB"
429+
# See `nixos.org.mail.key` in `non-critical-infra/modules/mailserver/default.nix`.
430+
value = "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcgNq4+Y23GxN8Mdza437tL5DuJJZU1y6VzTCwSi6cBNLyBDci2cmqXx/gm1sA3yv7+h+8/OyJpEgcbCIW/Ygs1XLuECqvXVX8MU6Djn4KY+d2sU1tlUdqvNM86puoneQtjEv9rDsjf3HGqaeOcjetFnQW7H+qcNcaEShxyKztzQIDAQAB"
429431
},
430432
{
431-
hostname = "_dmarc.mail-test.nixos.org"
433+
hostname = "_dmarc.nixos.org"
432434
type = "TXT"
433-
# TODO: consider making this strict (`v=DMARC1; p=reject; adkim=s; aspf=s;`),
434-
# but make sure this doesn't break mailing lists: https://dmarcian.com/mailing-lists-dmarc/
435-
value = "v=DMARC1; p=none"
435+
value = "v=DMARC1; p=none"
436436
},
437437
]
438438
}
@@ -450,9 +450,9 @@ resource "netlify_dns_record" "nixos" {
450450
value = each.value.value
451451
}
452452

453+
### TODO: remove, see https://github.com/NixOS/infra/issues/485 ###
453454
# MX records both have the same hostname and type and would clash on the above
454455
# mapping.
455-
456456
resource "netlify_dns_record" "nixos_MX1" {
457457
zone_id = local.zone_id
458458
hostname = "nixos.org"
@@ -467,8 +467,6 @@ resource "netlify_dns_record" "nixos_MX2" {
467467
value = "mx2.improvmx.com"
468468
}
469469

470-
# additional records for improvmx for dkim & dmarc
471-
472470
resource "netlify_dns_record" "nixos_DKIM1" {
473471
zone_id = local.zone_id
474472
hostname = "dkimprovmx1._domainkey.nixos.org"
@@ -482,13 +480,7 @@ resource "netlify_dns_record" "nixos_DKIM2" {
482480
type = "CNAME"
483481
value = "dkimprovmx2.improvmx.com"
484482
}
485-
486-
resource "netlify_dns_record" "nixos_DMARC" {
487-
zone_id = local.zone_id
488-
hostname = "_dmarc.nixos.org"
489-
type = "TXT"
490-
value = "v=DMARC1; p=none;"
491-
}
483+
### END TODO: remove ###
492484

493485
resource "netlify_dns_record" "nixos_google_verification" {
494486
zone_id = local.zone_id

0 commit comments

Comments
 (0)