]> git.immae.eu Git - perso/Immae/Config/Nix.git/blob - modules/private/mail/relay.nix
Postfix common aliases
[perso/Immae/Config/Nix.git] / modules / private / mail / relay.nix
1 { lib, pkgs, config, nodes, name, ... }:
2 let all_domains = config.myEnv.mail.postfix.additional_mailbox_domains
3 ++ lib.remove null (lib.flatten (map
4 (zone: map
5 (e: if e.receive
6 then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}"
7 else null
8 )
9 (zone.withEmail or [])
10 )
11 config.myEnv.dns.masterZones
12 ));
13 in
14 {
15 config = lib.mkIf config.myServices.mailBackup.enable {
16 security.acme.certs."mail" = config.myServices.certificates.certConfig // {
17 postRun = ''
18 systemctl restart postfix.service
19 '';
20 domain = config.hostEnv.fqdn;
21 extraDomainNames = let
22 zonesWithMx = builtins.filter (zone:
23 lib.attrsets.hasAttr "withEmail" zone && lib.lists.length zone.withEmail > 0
24 ) config.myEnv.dns.masterZones;
25 mxs = map (zone: "${config.myEnv.servers."${name}".mx.subdomain}.${zone.name}") zonesWithMx;
26 in mxs;
27 };
28 secrets.keys = {
29 "postfix/mysql_alias_maps" = {
30 user = config.services.postfix.user;
31 group = config.services.postfix.group;
32 permissions = "0440";
33 text = ''
34 # We need to specify that option to trigger ssl connection
35 tls_ciphers = TLSv1.2
36 user = ${config.myEnv.mail.postfix.mysql.user}
37 password = ${config.myEnv.mail.postfix.mysql.password}
38 hosts = ${config.myEnv.mail.postfix.mysql.remoteHost}
39 dbname = ${config.myEnv.mail.postfix.mysql.database}
40 query = SELECT DISTINCT 1
41 FROM forwardings
42 WHERE
43 ((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s'))
44 AND active = 1
45 AND '%s' NOT IN
46 (
47 SELECT source
48 FROM forwardings_blacklisted
49 WHERE source = '%s'
50 ) UNION
51 SELECT 'devnull@immae.eu'
52 FROM forwardings_blacklisted
53 WHERE source = '%s'
54 '';
55 };
56 "postfix/ldap_mailboxes" = {
57 user = config.services.postfix.user;
58 group = config.services.postfix.group;
59 permissions = "0440";
60 text = ''
61 server_host = ldaps://${config.myEnv.mail.dovecot.ldap.host}:636
62 search_base = ${config.myEnv.mail.dovecot.ldap.base}
63 query_filter = ${config.myEnv.mail.dovecot.ldap.postfix_mailbox_filter}
64 bind_dn = ${config.myEnv.mail.dovecot.ldap.dn}
65 bind_pw = ${config.myEnv.mail.dovecot.ldap.password}
66 result_attribute = immaePostfixAddress
67 result_format = dummy
68 version = 3
69 '';
70 };
71 "postfix/sympa_mailbox_maps" = {
72 user = config.services.postfix.user;
73 group = config.services.postfix.group;
74 permissions = "0440";
75 text = ''
76 hosts = ${config.myEnv.mail.sympa.postgresql.host}
77 user = ${config.myEnv.mail.sympa.postgresql.user}
78 password = ${config.myEnv.mail.sympa.postgresql.password}
79 dbname = ${config.myEnv.mail.sympa.postgresql.database}
80 query = SELECT DISTINCT 1 FROM list_table WHERE '%s' IN (
81 CONCAT(name_list, '@', robot_list),
82 CONCAT(name_list, '-request@', robot_list),
83 CONCAT(name_list, '-editor@', robot_list),
84 CONCAT(name_list, '-unsubscribe@', robot_list),
85 CONCAT(name_list, '-owner@', robot_list),
86 CONCAT('sympa-request@', robot_list),
87 CONCAT('sympa-owner@', robot_list),
88 CONCAT('sympa@', robot_list),
89 CONCAT('listmaster@', robot_list),
90 CONCAT('bounce@', robot_list),
91 CONCAT('abuse-feedback-report@', robot_list)
92 )
93 '';
94 };
95 "postfix/ldap_ejabberd_users_immae_fr" = {
96 user = config.services.postfix.user;
97 group = config.services.postfix.group;
98 permissions = "0440";
99 text = ''
100 server_host = ldaps://${config.myEnv.jabber.ldap.host}:636
101 search_base = ${config.myEnv.jabber.ldap.base}
102 query_filter = ${config.myEnv.jabber.postfix_user_filter}
103 domain = immae.fr
104 bind_dn = ${config.myEnv.jabber.ldap.dn}
105 bind_pw = ${config.myEnv.jabber.ldap.password}
106 result_attribute = immaeXmppUid
107 result_format = ejabberd@localhost
108 version = 3
109 '';
110 };
111 };
112
113 networking.firewall.allowedTCPPorts = [ 25 ];
114
115 users.users."${config.services.postfix.user}".extraGroups = [ "keys" ];
116 services.filesWatcher.postfix = {
117 restart = true;
118 paths = [
119 config.secrets.fullPaths."postfix/mysql_alias_maps"
120 config.secrets.fullPaths."postfix/sympa_mailbox_maps"
121 config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"
122 config.secrets.fullPaths."postfix/ldap_mailboxes"
123 ];
124 };
125 services.postfix = {
126 mapFiles = let
127 recipient_maps = let
128 name = n: i: "relay_${n}_${toString i}";
129 pair = n: i: m: lib.attrsets.nameValuePair (name n i) (
130 if m.type == "hash"
131 then pkgs.writeText (name n i) m.content
132 else null
133 );
134 pairs = n: v: lib.imap1 (i: m: pair n i m) v.recipient_maps;
135 in lib.attrsets.filterAttrs (k: v: v != null) (
136 lib.attrsets.listToAttrs (lib.flatten (
137 lib.attrsets.mapAttrsToList pairs config.myEnv.mail.postfix.backup_domains
138 ))
139 );
140 relay_restrictions = lib.attrsets.filterAttrs (k: v: v != null) (
141 lib.attrsets.mapAttrs' (n: v:
142 lib.attrsets.nameValuePair "recipient_access_${n}" (
143 if lib.attrsets.hasAttr "relay_restrictions" v
144 then pkgs.writeText "recipient_access_${n}" v.relay_restrictions
145 else null
146 )
147 ) config.myEnv.mail.postfix.backup_domains
148 );
149 virtual_map = {
150 virtual = let
151 cfg = config.myEnv.monitoring.email_check.eldiron;
152 address = "${cfg.mail_address}@${cfg.mail_domain}";
153 aliases = config.myEnv.mail.postfix.common_aliases;
154 in pkgs.writeText "postfix-virtual" (
155 builtins.concatStringsSep "\n" (
156 [ "${address} 1"
157 ] ++
158 map (a: "${a} 1") config.myEnv.mail.postfix.other_aliases ++
159 lib.attrsets.mapAttrsToList (
160 n: v: lib.optionalString v.external ''
161 script_${n}@mail.immae.eu 1
162 ''
163 ) config.myEnv.mail.scripts
164 ++ lib.lists.flatten (map (domain: map (alias: "${alias}@${domain} 1") aliases) all_domains)
165 )
166 );
167 };
168 in
169 recipient_maps // relay_restrictions // virtual_map;
170 config = {
171 ### postfix module overrides
172 readme_directory = "${pkgs.postfix}/share/postfix/doc";
173 smtp_tls_CAfile = lib.mkForce "";
174 smtp_tls_cert_file = lib.mkForce "";
175 smtp_tls_key_file = lib.mkForce "";
176
177 message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited"
178 mailbox_size_limit = "1073741825"; # Workaround, local delivered mails should all go through scripts
179 alias_database = "\$alias_maps";
180
181 ### Relay domains
182 relay_domains = let
183 backups = lib.flatten (lib.attrsets.mapAttrsToList (n: v: v.domains or []) config.myEnv.mail.postfix.backup_domains);
184 virtual_domains = config.myEnv.mail.postfix.additional_mailbox_domains
185 ++ lib.remove null (lib.flatten (map
186 (zone: map
187 (e: if e.receive
188 then "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}"
189 else null
190 )
191 (zone.withEmail or [])
192 )
193 config.myEnv.dns.masterZones
194 ));
195 in
196 backups ++ virtual_domains;
197 relay_recipient_maps = let
198 backup_recipients = lib.flatten (lib.attrsets.mapAttrsToList (n: v:
199 lib.imap1 (i: m: "${m.type}:/etc/postfix/relay_${n}_${toString i}") v.recipient_maps
200 ) config.myEnv.mail.postfix.backup_domains);
201 virtual_alias_maps = [
202 "hash:/etc/postfix/virtual"
203 "mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}"
204 "ldap:${config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"}"
205 ];
206 virtual_mailbox_maps = [
207 "ldap:${config.secrets.fullPaths."postfix/ldap_mailboxes"}"
208 "pgsql:${config.secrets.fullPaths."postfix/sympa_mailbox_maps"}"
209 ];
210 in
211 backup_recipients ++ virtual_alias_maps ++ virtual_mailbox_maps;
212 smtpd_relay_restrictions = [
213 "defer_unauth_destination"
214 ] ++ lib.flatten (lib.attrsets.mapAttrsToList (n: v:
215 if lib.attrsets.hasAttr "relay_restrictions" v
216 then [ "check_recipient_access hash:/etc/postfix/recipient_access_${n}" ]
217 else []
218 ) config.myEnv.mail.postfix.backup_domains);
219
220 ### Additional smtpd configuration
221 smtpd_tls_received_header = "yes";
222 smtpd_tls_loglevel = "1";
223
224 ### Email sending configuration
225 smtp_tls_security_level = "may";
226 smtp_tls_loglevel = "1";
227
228 ### Force ip bind for smtp
229 smtp_bind_address = builtins.head config.myEnv.servers."${name}".ips.main.ip4;
230 smtp_bind_address6 = builtins.head config.myEnv.servers."${name}".ips.main.ip6;
231
232 smtpd_milters = [
233 "unix:${config.myServices.mail.milters.sockets.opendkim}"
234 "unix:${config.myServices.mail.milters.sockets.openarc}"
235 "unix:${config.myServices.mail.milters.sockets.opendmarc}"
236 ];
237 };
238 enable = true;
239 enableSmtp = true;
240 enableSubmission = false;
241 destination = ["localhost"];
242 # This needs to reverse DNS
243 hostname = config.hostEnv.fqdn;
244 setSendmail = false;
245 sslCert = "/var/lib/acme/mail/fullchain.pem";
246 sslKey = "/var/lib/acme/mail/key.pem";
247 recipientDelimiter = "+";
248 };
249 };
250 }
251