summaryrefslogtreecommitdiff
path: root/sys/mail/default.nix
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2024-07-20 22:35:52 -0600
committerAlejandro Soto <alejandro@34project.org>2024-07-21 00:19:10 -0600
commitb1f3d839adc88b024e3a79d09b54a1939b78edba (patch)
tree2287680392dd32e6bda4c7e2664dc607727d79c7 /sys/mail/default.nix
parentc88f8c51c90c1e48c75047849a42ae0ed6c4aa15 (diff)
net/fail2ban: initial commit
Diffstat (limited to 'sys/mail/default.nix')
-rw-r--r--sys/mail/default.nix357
1 files changed, 182 insertions, 175 deletions
diff --git a/sys/mail/default.nix b/sys/mail/default.nix
index 6d066eb..0a888e8 100644
--- a/sys/mail/default.nix
+++ b/sys/mail/default.nix
@@ -23,190 +23,197 @@ in
};
config = mkIf cfg.enable {
- services.dovecot2 =
- let
- cert = config.security.acme.certs.${imapHostname}.directory;
- in
- {
- enable = true;
- enablePAM = false;
- enableLmtp = true;
-
- sslServerKey = "${cert}/key.pem";
- sslServerCert = "${cert}/fullchain.pem";
-
- modules = [ pkgs.dovecot_pigeonhole ];
-
- mailUser = "vmail";
- mailGroup = "vmail";
- mailLocation = "maildir:~/mail";
- mailPlugins.perProtocol.lmtp.enable = [ "sieve" ];
-
- extraConfig =
- let
- inherit (config.networking) domain;
-
- # https://dovecot.org/list/dovecot/2019-March/115250.html
- # Otra solución posible (https://serverfault.com/a/1062274/980378):
- # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
- localEntry = canonical: username: ''
- ${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
- '';
-
- localMailboxes =
- pkgs.writeText "local-mailboxes"
- (concatStrings
- (flatten (mapAttrsToList
- (canonical: user:
- map (localEntry canonical) ([ canonical ] ++ user.hardAliases))
- users)));
-
- localCerts =
- flatten (mapAttrsToList
- (canonical: user:
- let
- certNames = {
- inherit canonical;
- logins = [ canonical ] ++ user.hardAliases;
- };
- in
- map (flip nameValuePair certNames) user.mail.certs)
- users);
-
- vmailCerts =
- flatten (flatten (mapAttrsToList
- (domain: virtual: mapAttrsToList
- (username: user:
+ services = {
+ dovecot2 =
+ let
+ cert = config.security.acme.certs.${imapHostname}.directory;
+ in
+ {
+ enable = true;
+ enablePAM = false;
+ enableLmtp = true;
+
+ sslServerKey = "${cert}/key.pem";
+ sslServerCert = "${cert}/fullchain.pem";
+
+ modules = [ pkgs.dovecot_pigeonhole ];
+
+ mailUser = "vmail";
+ mailGroup = "vmail";
+ mailLocation = "maildir:~/mail";
+ mailPlugins.perProtocol.lmtp.enable = [ "sieve" ];
+
+ extraConfig =
+ let
+ inherit (config.networking) domain;
+
+ # https://dovecot.org/list/dovecot/2019-March/115250.html
+ # Otra solución posible (https://serverfault.com/a/1062274/980378):
+ # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
+ localEntry = canonical: username: ''
+ ${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
+ '';
+
+ localMailboxes =
+ pkgs.writeText "local-mailboxes"
+ (concatStrings
+ (flatten (mapAttrsToList
+ (canonical: user:
+ map (localEntry canonical) ([ canonical ] ++ user.hardAliases))
+ users)));
+
+ localCerts =
+ flatten (mapAttrsToList
+ (canonical: user:
let
- address = "${username}@${domain}";
-
certNames = {
- canonical = address;
- logins = [ address ];
+ inherit canonical;
+ logins = [ canonical ] ++ user.hardAliases;
};
in
map (flip nameValuePair certNames) user.mail.certs)
- virtual.users)
- virtual));
-
- certLogins =
- pkgs.writeText "cert-logins"
- (concatStrings (flatten (mapAttrsToList
- (uuid: names: map
- (addr: ''
- ${uuid}.mail-client@nodomain,${addr}:::::::user=${names.canonical}
- '')
- names.logins)
- (listToAttrs (localCerts ++ vmailCerts)))));
-
- vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
- in
- ''
- auth_mechanisms = plain login external
-
- ssl_ca = <${config.local.pki.ca.mail.fullchain}
- ssl_require_crl = yes
- ssl_verify_client_cert = yes
-
- # Esto descarta @domain.tld de locales explícitos, pero lo exige para los demás.
- # Implicación: locales implícitos sin dominio fallan en autenticar
- auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}}
- auth_ssl_username_from_cert = yes
-
- # TODO: los defaults de nixpkgs dejan los sockets bajo
- # /run/dovecot2 con demasiados permisos rwx, arreglar
-
- service auth {
- inet_listener mta-sasl {
- port = ${toString cfg.saslPort}
- address = ${cfg.mdaListen}
+ users);
+
+ vmailCerts =
+ flatten (flatten (mapAttrsToList
+ (domain: virtual: mapAttrsToList
+ (username: user:
+ let
+ address = "${username}@${domain}";
+
+ certNames = {
+ canonical = address;
+ logins = [ address ];
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ virtual.users)
+ virtual));
+
+ certLogins =
+ pkgs.writeText "cert-logins"
+ (concatStrings (flatten (mapAttrsToList
+ (uuid: names: map
+ (addr: ''
+ ${uuid}.mail-client@nodomain,${addr}:::::::user=${names.canonical}
+ '')
+ names.logins)
+ (listToAttrs (localCerts ++ vmailCerts)))));
+
+ vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
+ in
+ ''
+ auth_mechanisms = plain login external
+
+ ssl_ca = <${config.local.pki.ca.mail.fullchain}
+ ssl_require_crl = yes
+ ssl_verify_client_cert = yes
+
+ # Esto descarta @domain.tld de locales explícitos, pero lo exige para los demás.
+ # Implicación: locales implícitos sin dominio fallan en autenticar
+ auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}}
+ auth_ssl_username_from_cert = yes
+
+ # TODO: los defaults de nixpkgs dejan los sockets bajo
+ # /run/dovecot2 con demasiados permisos rwx, arreglar
+
+ service auth {
+ inet_listener mta-sasl {
+ port = ${toString cfg.saslPort}
+ address = ${cfg.mdaListen}
+ }
+ }
+
+ service lmtp {
+ inet_listener mta-lmtp {
+ port = ${toString cfg.lmtpPort}
+ address = ${cfg.mdaListen}
+ }
+ }
+
+ # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
+ # falle para usuarios locales, pero todo lo demás sirve. Parece
+ # ser debido a que pam no puede enumerar.
+
+ passdb {
+ driver = static
+ args = nopassword
+
+ master = yes
+ mechanisms = external
+
+ result_success = continue-fail
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins}
+
+ mechanisms = external
+ override_fields = nopassword
+
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN ${localMailboxes}
+
+ # Esta es una forma de determinar si se encontró el usuario en
+ # el passwd-file por medio de nopassword sin realmente
+ # autenticarlo. Cuidado con result_success, porque si eso se
+ # configura mal se permite inicio de sesión con cualquier
+ # contraseña (!!!).
+ result_success = continue
+ result_failure = return-fail
+ result_internalfail = return-fail
+
+ username_filter = !*@*
+ }
+
+ passdb {
+ driver = pam
+ args = dovecot2
+ username_filter = !*@*
+ #TODO: algo como 'override_fields = allow_nets=...'
}
- }
- service lmtp {
- inet_listener mta-lmtp {
- port = ${toString cfg.lmtpPort}
- address = ${cfg.mdaListen}
+ userdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
}
- }
-
- # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
- # falle para usuarios locales, pero todo lo demás sirve. Parece
- # ser debido a que pam no puede enumerar.
-
- passdb {
- driver = static
- args = nopassword
-
- master = yes
- mechanisms = external
-
- result_success = continue-fail
- result_failure = return-fail
- result_internalfail = return-fail
- }
-
- passdb {
- driver = passwd-file
- args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins}
-
- mechanisms = external
- override_fields = nopassword
-
- result_failure = return-fail
- result_internalfail = return-fail
- }
-
- passdb {
- driver = passwd-file
- args = username_format=%Ln ${vmailPath}/passwd
- }
-
- passdb {
- driver = passwd-file
- args = scheme=PLAIN ${localMailboxes}
-
- # Esta es una forma de determinar si se encontró el usuario en
- # el passwd-file por medio de nopassword sin realmente
- # autenticarlo. Cuidado con result_success, porque si eso se
- # configura mal se permite inicio de sesión con cualquier
- # contraseña (!!!).
- result_success = continue
- result_failure = return-fail
- result_internalfail = return-fail
-
- username_filter = !*@*
- }
-
- passdb {
- driver = pam
- args = dovecot2
- username_filter = !*@*
- #TODO: algo como 'override_fields = allow_nets=...'
- }
-
- userdb {
- driver = passwd-file
- args = username_format=%Ln ${vmailPath}/passwd
- override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
- }
-
- userdb {
- driver = passwd-file
- args = ${localMailboxes}
-
- result_success = continue-ok
- result_internalfail = return-fail
- skip = found
- }
-
- userdb {
- driver = passwd
- args = blocking=no
- skip = notfound
- }
- '';
+
+ userdb {
+ driver = passwd-file
+ args = ${localMailboxes}
+
+ result_success = continue-ok
+ result_internalfail = return-fail
+ skip = found
+ }
+
+ userdb {
+ driver = passwd
+ args = blocking=no
+ skip = notfound
+ }
+ '';
+ };
+
+ fail2ban.jails.dovecot.settings = {
+ filter = "dovecot[mode=aggressive]";
+ maxretry = 3;
};
+ };
security = {
# Necesario debido a 'enablePAM = false'