nixos/applications/email.nix

173 lines
4 KiB
Nix

{ config, pkgs, lib, ...}: with lib;
let
cfg = config.services.skynet_email;
# 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) );
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;
default = "skynet.ie";
description = lib.mdDoc "domaino";
};
sub = mkOption {
type = types.str;
default = "mail";
description = lib.mdDoc "mailserver subdomain";
};
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";
};
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
"mail A ${cfg.host.ip}"
# SPF record
''${cfg.domain}. IN TXT "v=spf1 a:${cfg.sub}.${cfg.domain} -all"''
# DKIM
''mail._domainkey.${cfg.domain}. IN TXT "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl8ptSASx37t5sfmU2d2Y6yi9AVrsNFBZDmJ2uaLa4NuvAjxGQCw4wx+1Jui/HOuKYLpntLsjN851wgPR+3i51g4OblqBDvcHn9NYgWRZfHj9AASANQjdsaAbkXuyKuO46hZqeWlpESAcD6a4Evam4fkm+kiZC0+rccb4cWgsuLwIDAQAB"''
# DMARC
''_dmarc.${cfg.domain}. IN TXT "v=DMARC1; p=none"''
];
skynet_dns.records.reverse = [
"${builtins.substring 9 3 cfg.host.ip} IN PTR ${cfg.sub}.${cfg.domain}."
];
mailserver = {
enable = true;
fqdn = "${cfg.sub}.${cfg.domain}";
domains = [
cfg.domain
];
# 20MB max size
messageSizeLimit = 20000000;
ldap = {
enable = true;
uris = cfg.ldap.hosts;
bind = {
dn = cfg.ldap.bind_dn;
passwordFile = config.age.secrets.ldap_pw.path;
};
searchBase = cfg.ldap.searchBase;
searchScope = "sub";
dovecot = {
userFilter = "(skMail=%u)";
# accept emails in, but only allow access to paid up members
passFilter = "(&(|${create_filter cfg.groups})(skMail=%u))";
};
postfix = {
filter = "(|(skMail=%s)(uid=%s))";
uidAttribute = "skMail";
mailAttribute = "skMail";
};
};
# 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
}
'';
*/
};
}