summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2023-02-11 19:14:07 -0600
committerAlejandro Soto <alejandro@34project.org>2023-02-11 19:14:07 -0600
commit9596e0e75c6a49083167ef6e2edca9cc448695e1 (patch)
tree9262c44043d3a250e32a21d23fb3b37eb6efcccd
parentb8a62165e4f3dd6a35ebad0dcaea0971d4323735 (diff)
env/users: implement mail client certificates
Diffstat (limited to '')
-rw-r--r--env/users/default.nix21
-rw-r--r--env/users/mailbox.nix96
2 files changed, 105 insertions, 12 deletions
diff --git a/env/users/default.nix b/env/users/default.nix
index 3602630..0e77e0d 100644
--- a/env/users/default.nix
+++ b/env/users/default.nix
@@ -8,7 +8,19 @@ in
./mailbox.nix
];
- options.local = with types; {
+ options.local = with types; let
+ mailOption = mkOption {
+ default = { };
+
+ type = submodule {
+ options.certs = mkOption {
+ type = listOf str;
+ default = [ ];
+ };
+ };
+ };
+ in
+ {
sysadmin = mkOption {
type = str;
};
@@ -50,6 +62,8 @@ in
type = listOf str;
default = [ ];
};
+
+ mail = mailOption;
};
config.groups = mkBefore (optional config.sysadmin "wheel");
@@ -83,8 +97,11 @@ in
};
users = mkOption {
- type = attrsOf (submodule { });
default = { };
+
+ type = attrsOf (submodule {
+ options.mail = mailOption;
+ });
};
};
diff --git a/env/users/mailbox.nix b/env/users/mailbox.nix
index 9fe460e..8b2c4b2 100644
--- a/env/users/mailbox.nix
+++ b/env/users/mailbox.nix
@@ -56,19 +56,75 @@ in
${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
'';
- localEntries = concatStrings
- (flatten (mapAttrsToList
+ localMailboxes =
+ pkgs.writeText "local-mailboxes"
+ (concatStrings
+ (flatten (mapAttrsToList
+ (canonical: user:
+ map (localEntry canonical) ([ canonical ] ++ user.hardAliases))
+ cfg.users)));
+
+ localCerts =
+ flatten (mapAttrsToList
(canonical: user:
- map (localEntry canonical) ([ canonical ] ++ user.hardAliases))
- cfg.users));
-
- localMailboxes = pkgs.writeText "local-mailboxes" localEntries;
+ let
+ certNames = {
+ inherit canonical;
+ logins = [ canonical ] ++ user.hardAliases;
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ cfg.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)
+ cfg.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
+ #TODO: automatizar implantación de archivo de CA
+
+ # Orden de concatenación de mail-fullchain-crl.crt:
+ # - Issuing CA cert
+ # - Issuing CA CRL
+ # - Intermediate CA cert
+ # - Intermediate CA CRL
+ # - Root CA cert
+ # - Root CA CRL
+ ssl_ca = </var/trust/ca/mail-fullchain-crl.crt
+ 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
@@ -86,21 +142,41 @@ in
}
}
- # 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 = 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 = ${localMailboxes}
+ 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