2023-06-16 22:18:53 +00:00
|
|
|
{ config, pkgs, lib, ...}: with lib;
|
|
|
|
let
|
|
|
|
cfg = config.services.skynet_email;
|
2023-07-04 20:53:24 +00:00
|
|
|
|
|
|
|
# create teh new strings
|
|
|
|
create_filter_array = map (x: "(memberOf=cn=${x},ou=groups,${cfg.ldap.base})");
|
|
|
|
|
|
|
|
create_filter_join = (x: concatStringsSep "" x);
|
|
|
|
|
|
|
|
# thought you could escape racket?
|
|
|
|
create_filter = (groups: create_filter_join (create_filter_array groups) );
|
|
|
|
|
2023-06-16 22:18:53 +00:00
|
|
|
in {
|
|
|
|
|
|
|
|
imports = [
|
|
|
|
./dns.nix
|
|
|
|
];
|
|
|
|
|
|
|
|
/*
|
|
|
|
backups = [
|
|
|
|
"/var/vmail"
|
|
|
|
"/var/dkim"
|
|
|
|
];
|
|
|
|
*/
|
|
|
|
|
|
|
|
options.services.skynet_email = {
|
|
|
|
# options that need to be passed in to make this work
|
|
|
|
|
|
|
|
enable = mkEnableOption "Skynet Email";
|
|
|
|
|
|
|
|
host = {
|
|
|
|
ip = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
|
|
|
|
name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
domain = mkOption {
|
|
|
|
type = types.str;
|
2023-07-04 20:53:24 +00:00
|
|
|
default = "skynet.ie";
|
2023-06-16 22:18:53 +00:00
|
|
|
description = lib.mdDoc "domaino";
|
|
|
|
};
|
|
|
|
|
|
|
|
sub = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mail";
|
|
|
|
description = lib.mdDoc "mailserver subdomain";
|
|
|
|
};
|
|
|
|
|
2023-07-04 20:53:24 +00:00
|
|
|
groups = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [
|
|
|
|
# general skynet users
|
|
|
|
"skynet-users"
|
|
|
|
# C&S folsk get access
|
|
|
|
"skynet-cns"
|
|
|
|
# skynet service accounts
|
|
|
|
"skynet-service"
|
|
|
|
];
|
|
|
|
description = lib.mdDoc "Groups we want to allow access to the email";
|
|
|
|
};
|
|
|
|
|
2023-06-16 22:18:53 +00:00
|
|
|
ldap = {
|
|
|
|
hosts = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [
|
|
|
|
"ldaps://sso.skynet.ie"
|
|
|
|
];
|
|
|
|
description = lib.mdDoc "ldap domains";
|
|
|
|
};
|
|
|
|
|
|
|
|
base = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "dc=skynet,dc=ie";
|
|
|
|
description = lib.mdDoc "where to find users";
|
|
|
|
};
|
|
|
|
|
|
|
|
searchBase = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "ou=users,${cfg.ldap.base}";
|
|
|
|
description = lib.mdDoc "where to find users";
|
|
|
|
};
|
|
|
|
|
|
|
|
bind_dn = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "cn=admin,${cfg.ldap.base}";
|
|
|
|
description = lib.mdDoc "where to find users";
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
|
|
|
|
age.secrets.ldap_pw.file = ../secrets/ldap/pw.age;
|
|
|
|
|
|
|
|
# set up dns record for it
|
|
|
|
skynet_dns.records.external = [
|
|
|
|
# basic one
|
2023-06-17 00:28:55 +00:00
|
|
|
"mail A ${cfg.host.ip}"
|
2023-06-16 22:18:53 +00:00
|
|
|
|
|
|
|
# SPF record
|
2023-06-17 00:28:55 +00:00
|
|
|
''${cfg.domain}. IN TXT "v=spf1 a:${cfg.sub}.${cfg.domain} -all"''
|
2023-06-16 22:18:53 +00:00
|
|
|
|
|
|
|
# DKIM
|
2023-06-17 00:28:55 +00:00
|
|
|
''mail._domainkey.${cfg.domain}. IN TXT "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl8ptSASx37t5sfmU2d2Y6yi9AVrsNFBZDmJ2uaLa4NuvAjxGQCw4wx+1Jui/HOuKYLpntLsjN851wgPR+3i51g4OblqBDvcHn9NYgWRZfHj9AASANQjdsaAbkXuyKuO46hZqeWlpESAcD6a4Evam4fkm+kiZC0+rccb4cWgsuLwIDAQAB"''
|
2023-06-16 22:18:53 +00:00
|
|
|
|
|
|
|
# DMARC
|
2023-06-17 00:28:55 +00:00
|
|
|
''_dmarc.${cfg.domain}. IN TXT "v=DMARC1; p=none"''
|
2023-06-16 22:18:53 +00:00
|
|
|
];
|
|
|
|
|
2023-06-16 23:59:22 +00:00
|
|
|
skynet_dns.records.reverse = [
|
|
|
|
"${builtins.substring 9 3 cfg.host.ip} IN PTR ${cfg.sub}.${cfg.domain}."
|
|
|
|
];
|
|
|
|
|
2023-06-16 22:18:53 +00:00
|
|
|
mailserver = {
|
|
|
|
enable = true;
|
|
|
|
fqdn = "${cfg.sub}.${cfg.domain}";
|
|
|
|
domains = [
|
|
|
|
cfg.domain
|
|
|
|
];
|
|
|
|
|
2023-07-04 20:53:24 +00:00
|
|
|
# 20MB max size
|
|
|
|
messageSizeLimit = 20000000;
|
2023-06-16 22:18:53 +00:00
|
|
|
|
|
|
|
ldap = {
|
|
|
|
enable = true;
|
|
|
|
uris = cfg.ldap.hosts;
|
|
|
|
bind = {
|
|
|
|
dn = cfg.ldap.bind_dn;
|
|
|
|
passwordFile = config.age.secrets.ldap_pw.path;
|
|
|
|
};
|
2023-07-04 20:53:24 +00:00
|
|
|
|
2023-06-16 22:18:53 +00:00
|
|
|
searchBase = cfg.ldap.searchBase;
|
|
|
|
searchScope = "sub";
|
|
|
|
|
|
|
|
dovecot = {
|
2023-06-18 11:50:23 +00:00
|
|
|
userFilter = "(skMail=%u)";
|
2023-06-16 22:18:53 +00:00
|
|
|
|
2023-07-04 20:53:24 +00:00
|
|
|
# accept emails in, but only allow access to paid up members
|
|
|
|
passFilter = "(&(|${create_filter cfg.groups})(skMail=%u))";
|
2023-06-16 22:18:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
postfix = {
|
2023-07-04 22:14:58 +00:00
|
|
|
filter = "(|(skMail=%s)(uid=%s))";
|
2023-06-16 22:18:53 +00:00
|
|
|
uidAttribute = "skMail";
|
2023-06-18 11:50:23 +00:00
|
|
|
mailAttribute = "skMail";
|
2023-06-16 22:18:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
# feckin spammers
|
|
|
|
rejectRecipients = [
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
# tune the spam filter
|
|
|
|
/*
|
|
|
|
services.rspamd.extraConfig = ''
|
|
|
|
actions {
|
|
|
|
reject = null; # Disable rejects, default is 15
|
|
|
|
add_header = 7; # Add header when reaching this score
|
|
|
|
greylist = 4; # Apply greylisting when reaching this score
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
*/
|
|
|
|
};
|
|
|
|
}
|