summaryrefslogtreecommitdiff
path: root/env/users
diff options
context:
space:
mode:
Diffstat (limited to 'env/users')
-rw-r--r--env/users/default.nix126
-rw-r--r--env/users/mailbox.nix163
-rw-r--r--env/users/users.nix1
-rw-r--r--env/users/virtual.nix1
4 files changed, 291 insertions, 0 deletions
diff --git a/env/users/default.nix b/env/users/default.nix
new file mode 100644
index 0000000..3602630
--- /dev/null
+++ b/env/users/default.nix
@@ -0,0 +1,126 @@
+{ config, lib, ... }:
+with lib; let
+ cfg = config.local;
+ inherit (config.networking) domain;
+in
+{
+ imports = [
+ ./mailbox.nix
+ ];
+
+ options.local = with types; {
+ sysadmin = mkOption {
+ type = str;
+ };
+
+ users = mkOption {
+ default = { };
+
+ type = attrsOf (submodule ({ config, ... }: {
+ options = {
+ uid = mkOption {
+ type = int;
+ };
+
+ gid = mkOption {
+ type = int;
+ };
+
+ gecos = mkOption {
+ type = str;
+ default = "";
+ };
+
+ sysadmin = mkOption {
+ type = bool;
+ default = false;
+ };
+
+ groups = mkOption {
+ type = listOf str;
+ default = [ ];
+ };
+
+ allowLogin = mkOption {
+ type = bool;
+ default = true;
+ };
+
+ hardAliases = mkOption {
+ type = listOf str;
+ default = [ ];
+ };
+ };
+
+ config.groups = mkBefore (optional config.sysadmin "wheel");
+ }));
+ };
+
+ virtual = mkOption {
+ default = { };
+
+ type = attrsOf (submodule ({ name, ... }: {
+ options = {
+ aliases = mkOption {
+ type = attrsOf (listOf str);
+ default = { };
+ };
+
+ rules = mkOption {
+ default = [ ];
+
+ type = listOf (submodule {
+ options = {
+ pattern = mkOption {
+ type = str;
+ };
+
+ targets = mkOption {
+ type = listOf str;
+ };
+ };
+ });
+ };
+
+ users = mkOption {
+ type = attrsOf (submodule { });
+ default = { };
+ };
+ };
+
+ config.aliases =
+ let
+ sysadmin = mkDefault [ "sysadmin@${name}" ];
+ in
+ {
+ abuse = sysadmin;
+ security = sysadmin;
+ webmaster = sysadmin;
+ hostmaster = sysadmin;
+ postmaster = sysadmin;
+
+ sysadmin = mkDefault [ "sysadmin@${domain}" ];
+ };
+ }));
+ };
+ };
+
+ config.local = mkMerge [
+ {
+ users = import ./users.nix;
+ virtual = import ./virtual.nix;
+
+ sysadmin =
+ (findSingle
+ (user: user.value.sysadmin)
+ (throw "no user is declared as sysadmin")
+ (throw "more than one user is declared as sysadmin")
+ (mapAttrsToList nameValuePair cfg.users)
+ ).name;
+ }
+
+ {
+ virtual.${domain}.aliases.sysadmin = [ cfg.sysadmin ];
+ }
+ ];
+}
diff --git a/env/users/mailbox.nix b/env/users/mailbox.nix
new file mode 100644
index 0000000..e603214
--- /dev/null
+++ b/env/users/mailbox.nix
@@ -0,0 +1,163 @@
+{ config, lib, pkgs, ... }:
+with lib; let
+ cfg = config.local;
+in
+{
+ options.local.mailHost = with types; {
+ enable = mkEnableOption "mailbox host service";
+
+ mdaListen = mkOption {
+ type = str;
+ };
+
+ saslPort = mkOption {
+ type = port;
+ };
+
+ lmtpPort = mkOption {
+ type = port;
+ };
+ };
+
+ config =
+ let
+ imapHostname = cfg.domains.imap.main;
+ in
+ mkIf cfg.mailHost.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}
+ '';
+
+ localEntries = concatStrings
+ (flatten (mapAttrsToList
+ (canonical: user:
+ map (localEntry canonical) ([ canonical ] ++ user.hardAliases))
+ cfg.users));
+
+ localMailboxes = pkgs.writeText "local-mailboxes" localEntries;
+
+ vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
+ in
+ ''
+ auth_mechanisms = plain login external
+
+ # 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.mailHost.saslPort}
+ address = ${cfg.mailHost.mdaListen}
+ }
+ }
+
+ service lmtp {
+ inet_listener mta-lmtp {
+ port = ${toString cfg.mailHost.lmtpPort}
+ address = ${cfg.mailHost.mdaListen}
+ }
+ }
+
+ # Esto enfuerza user@domain.tld
+ auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@invalid}}
+
+ # 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 = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ }
+
+ passdb {
+ driver = passwd-file
+ args = ${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
+ }
+ '';
+ };
+
+ security = {
+ # Necesario debido a 'enablePAM = false'
+ pam.services.dovecot2 = { };
+
+ #acme.certs.${imapHostname} = {
+ # inherit (config.services.dovecot2) group;
+ #};
+ };
+
+ users = {
+ users.${config.services.dovecot2.mailUser}.uid = 995;
+ groups.${config.services.dovecot2.mailGroup}.gid = 993;
+ };
+
+ #networking.firewall.allowedTCPPorts = [ 143 993 ];
+
+ #local.certs.imap.enable = true;
+ };
+}
diff --git a/env/users/users.nix b/env/users/users.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/env/users/users.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/env/users/virtual.nix b/env/users/virtual.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/env/users/virtual.nix
@@ -0,0 +1 @@
+# This file has been lustrated.