summaryrefslogtreecommitdiff
path: root/hosts/surtr/email/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/surtr/email/default.nix')
-rw-r--r--hosts/surtr/email/default.nix230
1 files changed, 230 insertions, 0 deletions
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix
new file mode 100644
index 00000000..49f156eb
--- /dev/null
+++ b/hosts/surtr/email/default.nix
@@ -0,0 +1,230 @@
1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 postfix_map = tableType: tableName: "${tableType}:/run/postfix/maps/${tableName}";
7 postfix_hash = postfix_map "hash";
8in {
9 options = {
10 services.postfix.mapFilesRun = mkOption {
11 type = types.attrsOf (types.either types.path (types.submodule {
12 options = {
13 type = mkOption {
14 type = types.str;
15 default = "hash";
16 };
17
18 path = mkOption {
19 type = types.nullOr types.path;
20 default = null;
21 };
22
23 text = mkOption {
24 type = types.nullOr types.lines;
25 default = null;
26 };
27 };
28 }));
29 default = {};
30 };
31 };
32
33 config = {
34 services.postfix = {
35 enable = true;
36 hostname = "surtr.yggdrasil.li";
37 recipientDelimiter = "+";
38 setSendmail = true;
39 postmasterAlias = ""; rootAlias = ""; extraAliases = "";
40 destination = [];
41 sslCert = "/run/credentials/postfix.service/surtr.yggdrasil.li.pem";
42 sslKey = "/run/credentials/postfix.service/surtr.yggdrasil.li.key.pem";
43 networks = ["127.0.0.0/8" "[::ffff:127.0.0.0]/104" "[::1]/128" "10.141.0.0/16"];
44 mapFilesRun = {
45 "relay_ccert" = { text = ""; };
46 "sni" = { text = ''
47 bouncy.email /run/credentials/postfix.service/bouncy.email.sni.pem
48 mailin.bouncy.email /run/credentials/postfix.service/mailin.bouncy.email.sni.pem
49 mailsub.bouncy.email /run/credentials/postfix.service/mailsub.bouncy.email.sni.pem
50 .bouncy.email /run/credentials/postfix.service/bouncy.email.sni.pem
51 '';};
52 "esmtp_access" = { type = "cidr"; text = ''
53 # Allow DSN requests from local subnet only
54 192.168.0.0/16 silent-discard
55 172.16.0.0/12 silent-discard
56 10.0.0.0/8 silent-discard
57 0.0.0.0/0 silent-discard, dsn
58 fd00::/8 silent-discard
59 ::/0 silent-discard, dsn
60 '';};
61 };
62 config = {
63 #the dh params
64 smtpd_tls_dh1024_param_file = toString config.security.dhparams.params."postfix-1024".path;
65 smtpd_tls_dh512_param_file = toString config.security.dhparams.params."postfix-512".path;
66 #enable ECDH
67 smtpd_tls_eecdh_grade = "strong";
68 #enabled SSL protocols, don't allow SSLv2 and SSLv3
69 smtpd_tls_protocols = ["!SSLv2" "!SSLv3" "!TLSv1" "!TLSv1.1" "!TLSv1.2"];
70 smtpd_tls_mandatory_protocols = ["!SSLv2" "!SSLv3" "!TLSv1" "!TLSv1.1" "!TLSv1.2"];
71 #allowed ciphers for smtpd_tls_security_level=encrypt
72 smtpd_tls_mandatory_ciphers = "high";
73 #allowed ciphers for smtpd_tls_security_level=may
74 #smtpd_tls_ciphers = high
75 #enforce the server cipher preference
76 tls_preempt_cipherlist = true;
77 #disable following ciphers for smtpd_tls_security_level=encrypt
78 smtpd_tls_mandatory_exclude_ciphers = ["aNULL" "MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL"];
79 #disable following ciphers for smtpd_tls_security_level=may
80 smtpd_tls_exclude_ciphers = ["aNULL" "MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL"];
81 #enable TLS logging to see the ciphers for inbound connections
82 smtpd_tls_loglevel = "1";
83 #enable TLS logging to see the ciphers for outbound connections
84 smtp_tls_loglevel = "1";
85
86 smtpd_tls_ask_ccert = true;
87 smtpd_tls_CAfile = toString ./ca/ca.crt;
88
89 smtp_tls_security_level = "dane";
90 smtp_dns_support_level = "dnssec";
91
92 tls_server_sni_maps = postfix_hash "sni";
93
94 local_recipient_maps = "";
95
96 # 10 GiB
97 message_size_limit = "10737418240";
98 # 10 GiB
99 mailbox_size_limit = "10737418240";
100
101 smtpd_delay_reject = true;
102 smtpd_helo_required = true;
103 smtpd_helo_restrictions = "permit";
104
105 smtpd_recipient_restrictions = [
106 "reject_unauth_pipelining"
107 "reject_non_fqdn_recipient"
108 "reject_unknown_recipient_domain"
109 "permit_mynetworks"
110 "check_ccert_access ${postfix_hash "relay_ccert"}"
111 "reject_non_fqdn_helo_hostname"
112 "reject_invalid_helo_hostname"
113 "reject_unauth_destination"
114 "reject_unknown_recipient_domain"
115 "reject_unverified_recipient"
116 ];
117
118 smtpd_relay_restrictions = [
119 "permit_mynetworks"
120 "check_ccert_access ${postfix_hash "relay_ccert"}"
121 "reject_unauth_destination"
122 ];
123
124 propagate_unmatched_extensions = ["canonical" "virtual" "alias"];
125 smtpd_authorized_verp_clients = "$authorized_verp_clients";
126 authorized_verp_clients = "$mynetworks";
127
128 milter_default_action = "accept";
129 smtpd_milters = [config.services.opendkim.socket];
130 non_smtpd_milters = [config.services.opendkim.socket];
131
132 alias_maps = "";
133
134 queue_run_delay = "10s";
135 minimal_backoff_time = "1m";
136 maximal_backoff_time = "10m";
137 maximal_queue_lifetime = "100m";
138 bounce_queue_lifetime = "20m";
139
140 smtpd_discard_ehlo_keyword_address_maps = postfix_map "cidr" "esmtp_access";
141
142 sender_canonical_maps = "tcp:localhost:${toString config.services.postsrsd.forwardPort}";
143 sender_canonical_classes = "envelope_sender";
144 recipient_canonical_maps = "tcp:localhost:${toString config.services.postsrsd.reversePort}";
145 recipient_canonical_classes = ["envelope_recipient" "header_recipient"];
146 };
147 masterConfig = {
148 smtps = {
149 type = "inet";
150 command = "smtpd";
151 args = [
152 "-o" "smtpd_tls_wrappermode=yes"
153 "-o" "smtpd_tls_req_ccert=yes"
154 "-o" "smtpd_client_restrictions=permit_tls_all_clientcerts,reject"
155 "-o" "smtpd_recipient_restrictions=reject_unauth_pipelining,reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_tls_all_clientcerts,reject"
156 ];
157 };
158 };
159 };
160
161 services.postsrsd = {
162 enable = true;
163 domain = "srs.surtr.yggdrasil.li";
164 separator = "+";
165 excludeDomains = [ "surtr.yggdrasil.li"
166 ".bouncy.email" "bouncy.email"
167 ];
168 };
169
170 services.opendkim = {
171 enable = true;
172 # user = "postfix"; group = "postfix";
173 # socket = "local:/run/opendkim/opendkim.sock";
174 domains = ''csl:${concatStringsSep "," ["surtr.yggdrasil.li" "bouncy.email"]}'';
175 selector = "surtr";
176 configFile = builtins.toFile "opendkim.conf" ''
177 Syslog true
178 MTACommand ${config.security.wrapperDir}/sendmail
179 LogResults true
180 '';
181 };
182
183 security.dhparams = {
184 params = {
185 "postfix-512".bits = 512;
186 "postfix-1024".bits = 2048;
187 };
188 };
189
190 security.acme.domains = let
191 mkSNI = ''
192 cat key.pem full.pem > sni.pem
193 '';
194 in {
195 "bouncy.email" = {
196 certCfg.postRun = mkSNI;
197 };
198 "mailin.bouncy.email" = {
199 certCfg.postRun = mkSNI;
200 };
201 "mailsub.bouncy.email" = {
202 certCfg.postRun = mkSNI;
203 };
204 "surtr.yggdrasil.li" = {};
205 };
206
207 systemd.services.postfix = {
208 preStart = concatStringsSep "\n" (mapAttrsToList (to: from: let
209 cont = {type, path, text}: assert !(isNull path && isNull text); let
210 path' = if isNull path then pkgs.writeText to text else path;
211 in ''
212 ln -sf ${path'} /run/postfix/maps/${to}
213 postmap ${type}:/run/postfix/maps/${to}
214 '';
215 in if builtins.isPath from then cont { path = from; } else cont from
216 ) config.services.postfix.mapFilesRun);
217
218 serviceConfig = {
219 RuntimeDirectory = ["postfix/maps"];
220 LoadCredential = [
221 "surtr.yggdrasil.li.key.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/key.pem"
222 "surtr.yggdrasil.li.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/fullchain.pem"
223 "bouncy.email.sni.pem:${config.security.acme.certs."bouncy.email".directory}/sni.pem"
224 "mailin.bouncy.email.sni.pem:${config.security.acme.certs."mailin.bouncy.email".directory}/sni.pem"
225 "mailsub.bouncy.email.sni.pem:${config.security.acme.certs."mailsub.bouncy.email".directory}/sni.pem"
226 ];
227 };
228 };
229 };
230}