From 00a97b1d94658bfce060372c94b434c034ea7fbe Mon Sep 17 00:00:00 2001 From: root Date: Wed, 15 Jan 2020 11:24:11 -0600 Subject: [PATCH] Currently broken config... --- config/fudo/acme-for-hostname.nix | 61 ++++ config/fudo/authentication.nix | 67 ++++ config/fudo/common.nix | 16 + config/fudo/grafana.nix | 127 ++++++++ config/fudo/kdc.nix | 99 ++++++ config/fudo/ldap.nix | 11 +- config/{fudo.nix => fudo/local-network.nix} | 11 +- config/fudo/mail-container.nix | 256 +++++++++++++++ config/fudo/mail.nix | 170 ++++++++++ config/fudo/mail/clamav.nix | 28 ++ config/fudo/mail/dkim.nix | 114 +++++++ config/fudo/mail/dovecot.nix | 242 ++++++++++++++ .../mail/dovecot/imap_sieve/report-ham.sieve | 15 + .../mail/dovecot/imap_sieve/report-spam.sieve | 7 + .../mail/dovecot/pipe_bin/sa-learn-ham.sh | 3 + .../mail/dovecot/pipe_bin/sa-learn-spam.sh | 3 + config/fudo/mail/postfix.nix | 297 ++++++++++++++++++ config/fudo/mail/rspamd.nix | 88 ++++++ config/fudo/minecraft-server.nix | 60 ++++ config/fudo/node-exporter.nix | 58 ++++ config/fudo/postgres.nix | 197 ++++++++++++ config/fudo/profiles.nix | 32 ++ config/fudo/profiles/desktop.nix | 151 +++++++++ config/fudo/profiles/server.nix | 27 ++ config/fudo/prometheus.nix | 204 ++++++++++++ config/fudo/sites.nix | 79 +++++ config/local.nix | 21 ++ config/postgresql_11.nix | 63 ---- defaults.nix | 37 +-- fudo/alias-users.nix | 18 ++ fudo/email.nix | 39 +++ fudo/recipient-blacklist.nix | 3 + fudo/sender-blacklist.nix | 7 + fudo/system-users.nix | 5 + fudo/user-aliases.nix | 36 +++ fudo/users.nix | 8 + hosts/france.nix | 287 ++++++++++++++--- hosts/nostromo.nix | 15 +- networks/fudo.org.nix | 115 ++++++- packages/{acme-ca.nix => letsencrypt-ca.nix} | 2 - packages/local-packages.nix | 10 - ...{minecraft-server_1_15_1.nix => local.nix} | 10 + packages/options/postgresql_11.nix | 46 --- packages/postgresql_11_gssapi.nix | 10 - profiles/desktop.nix | 4 + profiles/server.nix | 10 +- profiles/services/heimdal_kdc.nix | 34 -- profiles/services/minecraft.nix | 19 -- profiles/services/postgres.nix | 65 ---- static/fudo_ca.pem | 36 +-- static/letsencryptauthorityx3.pem | 32 ++ 51 files changed, 2991 insertions(+), 364 deletions(-) create mode 100644 config/fudo/acme-for-hostname.nix create mode 100644 config/fudo/authentication.nix create mode 100644 config/fudo/common.nix create mode 100644 config/fudo/grafana.nix create mode 100644 config/fudo/kdc.nix rename config/{fudo.nix => fudo/local-network.nix} (91%) create mode 100644 config/fudo/mail-container.nix create mode 100644 config/fudo/mail.nix create mode 100644 config/fudo/mail/clamav.nix create mode 100644 config/fudo/mail/dkim.nix create mode 100644 config/fudo/mail/dovecot.nix create mode 100644 config/fudo/mail/dovecot/imap_sieve/report-ham.sieve create mode 100644 config/fudo/mail/dovecot/imap_sieve/report-spam.sieve create mode 100755 config/fudo/mail/dovecot/pipe_bin/sa-learn-ham.sh create mode 100755 config/fudo/mail/dovecot/pipe_bin/sa-learn-spam.sh create mode 100644 config/fudo/mail/postfix.nix create mode 100644 config/fudo/mail/rspamd.nix create mode 100644 config/fudo/minecraft-server.nix create mode 100644 config/fudo/node-exporter.nix create mode 100644 config/fudo/postgres.nix create mode 100644 config/fudo/profiles.nix create mode 100644 config/fudo/profiles/desktop.nix create mode 100644 config/fudo/profiles/server.nix create mode 100644 config/fudo/prometheus.nix create mode 100644 config/fudo/sites.nix create mode 100644 config/local.nix create mode 100644 fudo/alias-users.nix create mode 100644 fudo/email.nix create mode 100644 fudo/recipient-blacklist.nix create mode 100644 fudo/sender-blacklist.nix create mode 100644 fudo/user-aliases.nix rename packages/{acme-ca.nix => letsencrypt-ca.nix} (80%) delete mode 100644 packages/local-packages.nix rename packages/{minecraft-server_1_15_1.nix => local.nix} (55%) delete mode 100644 packages/options/postgresql_11.nix delete mode 100644 packages/postgresql_11_gssapi.nix delete mode 100644 profiles/services/heimdal_kdc.nix delete mode 100644 profiles/services/minecraft.nix delete mode 100644 profiles/services/postgres.nix create mode 100644 static/letsencryptauthorityx3.pem diff --git a/config/fudo/acme-for-hostname.nix b/config/fudo/acme-for-hostname.nix new file mode 100644 index 0000000..4dd5f2e --- /dev/null +++ b/config/fudo/acme-for-hostname.nix @@ -0,0 +1,61 @@ +# Starts an Nginx server on $HOSTNAME just to get a cert for this host + +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.fudo.acme; + + wwwRoot = hostname: + pkgs.writeTextFile { + name = "index.html"; + + text = '' + + + ${hostname} + + +

${hostname} + + + ''; + destination = "/www"; + }; + +in { + + options.fudo.acme = { + hostnames = mkOption { + type = with types; listOf str; + description = "A list of hostnames mapping to this host, for which to acquire SSL certificates."; + default = []; + example = [ + "my.hostname.com" + "alt.hostname.com" + ]; + }; + }; + + config = { + + services.nginx = { + enable = true; + + virtualHosts = listToAttrs + (map + (hostname: + nameValuePair hostname + { + enableACME = true; + forceSSL = true; + root = (wwwRoot hostname) + ("/" + "www"); + }) + cfg.hostnames); + }; + + security.acme.certs = listToAttrs + (map (hostname: nameValuePair hostname { email = "admin@fudo.org"; }) + cfg.hostnames); + }; +} diff --git a/config/fudo/authentication.nix b/config/fudo/authentication.nix new file mode 100644 index 0000000..c88fa7c --- /dev/null +++ b/config/fudo/authentication.nix @@ -0,0 +1,67 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.fudo.authentication; +in { + options.fudo.authentication = { + enable = mkEnableOption "Use Fudo users & groups from LDAP."; + + ssl-ca-certificate = mkOption { + type = types.str; + description = "Path to the CA certificate to use to bind to the server."; + }; + + bind-passwd-file = mkOption { + type = types.str; + description = "Path to a file containing the password used to bind to the server."; + }; + + ldap-url = mkOption { + type = types.str; + description = "URL of the LDAP server."; + example = "ldaps://auth.fudo.org"; + }; + + base = mkOption { + type = types.str; + description = "The LDAP base in which to look for users."; + default = "dc=fudo,dc=org"; + }; + + bind-dn = mkOption { + type = types.str; + description = "The DN with which to bind the LDAP server."; + default = "cn=auth_reader,dc=fudo,dc=org"; + }; + }; + + config = mkIf cfg.enable { + users.ldap = { + enable = true; + base = cfg.base; + bind = { + distinguishedName = cfg.bind-dn; + passwordFile = cfg.bind-passwd-file; + timeLimit = 5; + }; + loginPam = true; + nsswitch = true; + server = cfg.ldap-url; + timeLimit = 5; + useTLS = true; + extraConfig = '' + TLS_CACERT ${cfg.ssl-ca-certificate} + TSL_REQCERT allow + ''; + + daemon = { + enable = true; + extraConfig = '' + tls_cacertfile ${cfg.ssl-ca-certificate} + tls_reqcert allow + ''; + }; + }; + }; +} diff --git a/config/fudo/common.nix b/config/fudo/common.nix new file mode 100644 index 0000000..3679ff9 --- /dev/null +++ b/config/fudo/common.nix @@ -0,0 +1,16 @@ +# General Fudo config, shared across packages +{ config, lib, pkgs, ... }: + +with lib; +{ + options.fudo.common = { + local-networks = mkOption { + type = with types; listOf str; + description = '' + A list of networks to consider 'local'. Used by various services to + limit access to the external world. + ''; + default = []; + }; + }; +} diff --git a/config/fudo/grafana.nix b/config/fudo/grafana.nix new file mode 100644 index 0000000..10ee540 --- /dev/null +++ b/config/fudo/grafana.nix @@ -0,0 +1,127 @@ +# NOTE: this assumes that postgres is running locally. + +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.fudo.grafana; + + database-name = "grafana"; + database-user = "grafana"; + +in { + + options.fudo.grafana = { + enable = mkEnableOption "Fudo Metrics Display Service"; + + hostname = mkOption { + type = types.str; + description = "Grafana site hostname."; + example = "fancy-graphs.fudo.org"; + }; + + smtp-username = mkOption { + type = types.str; + description = "Username with which to send email."; + }; + + smtp-password-file = mkOption { + type = types.path; + description = "Path to a file containing the email user's password."; + }; + + database-password-file = mkOption { + type = types.path; + description = "Path to a file containing the database user's password."; + }; + + admin-password-file = mkOption { + type = types.path; + description = "Path to a file containing the admin user's password."; + }; + + secret-key-file = mkOption { + type = types.path; + description = "Path to a file containing the server's secret key, used for signatures."; + }; + + prometheus-host = mkOption { + type = types.str; + description = "The URL of the prometheus data source."; + }; + }; + + config = mkIf cfg.enable { + fudo.postgresql = { + databases.${database-name} = {}; + + local-users.${database-user} = { + password = (fileContents cfg.database-password-file); + databases = ["${database-name}"]; + }; + }; + + services.nginx = { + enable = true; + + virtualHosts = { + "${cfg.hostname}" = { + enableACME = true; + forceSSL = true; + + locations."/" = { + proxyPass = "http://127.0.0.1:3000"; + + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-By $server_addr:$server_port; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + ''; + }; + }; + }; + }; + + services.grafana = { + enable = true; + + addr = "127.0.0.1"; + protocol = "http"; + domain = "${cfg.hostname}"; + rootUrl = "https://${cfg.hostname}/"; + + security = { + adminPasswordFile = cfg.admin-password-file; + secretKeyFile = cfg.secret-key-file; + }; + + smtp = { + enable = true; + fromAddress = "metrics@fudo.org"; + host = "mail.fudo.org:25"; + user = cfg.smtp-username; + passwordFile = cfg.smtp-password-file; + }; + + database = { + host = "localhost"; + name = database-name; + user = database-user; + passwordFile = cfg.database-password-file; + type = "postgres"; + }; + + provision.datasources = [ + { + editable = false; + isDefault = true; + name = cfg.prometheus-host; + type = "prometheus"; + url = "https://${cfg.prometheus-host}/"; + } + ]; + }; + }; +} diff --git a/config/fudo/kdc.nix b/config/fudo/kdc.nix new file mode 100644 index 0000000..71954f4 --- /dev/null +++ b/config/fudo/kdc.nix @@ -0,0 +1,99 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + + cfg = config.fudo.auth.kdc; + + stringJoin = joiner: attrList: + if (length attrList) == 0 then + "" + else + foldr(lAttr: rAttr: "${lAttr}${joiner}${rAttr}") (last attrList) (init attrList); + +in { + + options.fudo.auth.kdc = { + enable = mkEnableOption "Fudo KDC"; + + database-path = mkOption { + type = types.str; + description = '' + The path at which to store the database files. + ''; + default = "/var/heimdal/heimdal"; + }; + + realm = mkOption { + type = types.str; + description = '' + The realm for which we are the acting KDC. + ''; + }; + + mkey-file = mkOption { + type = types.str; + description = '' + The path to the master key file. + ''; + }; + + acl-file = mkOption { + type = types.str; + description = '' + The path to the Access Control file. + ''; + }; + + bind-addresses = mkOption { + type = with types; listOf str; + description = '' + A list of IP addresses on which to bind. + ''; + default = []; + }; + }; + + config = mkIf cfg.enable { + environment = { + systemPackages = [ + pkgs.heimdalFull + ]; + + etc."krb5.conf" = { + text = mkAfter '' + [kdc] + database = { + realm = ${cfg.realm} + mkey_file = ${cfg.mkey-file} + acl_file = ${cfg.acl-file} + } + addresses = ${stringJoin " " cfg.bind-addresses} + enable-http = true + ''; + }; + }; + + systemd.services = { + heimdal-kdc = { + enable = true; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + description = "Heimdal Kerberos Key Distribution Center (ticket server)"; + serviceConfig = { + ExecStart = ''${pkgs.heimdalFull}/libexec/heimdal/kdc''; + }; + }; + + heimdal-admin-server = { + enable = true; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + description = "Heimdal Kerberos Remote Administration Server"; + serviceConfig = { + ExecStart = ''${pkgs.heimdalFull}/libexec/heimdal/kadmind''; + }; + }; + }; + }; +} diff --git a/config/fudo/ldap.nix b/config/fudo/ldap.nix index 20ac8d8..d7a5578 100644 --- a/config/fudo/ldap.nix +++ b/config/fudo/ldap.nix @@ -206,10 +206,11 @@ in { }; sslCACert = mkOption { - type = types.str; + type = with types; nullOr str; description = '' The path to the SSL CA cert used to sign the certificate. ''; + default = null; }; organization = mkOption { @@ -329,7 +330,7 @@ in { TLSCertificateFile ${cfg.sslCert} TLSCertificateKeyFile ${cfg.sslKey} - TLSCACertificateFile ${cfg.sslCACert} + ${optionalString (cfg.sslCACert != null) "TLSCACertificateFile ${cfg.sslCACert}"} authz-regexp "^uid=auth/([^.]+)\.fudo\.org,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=$1,ou=hosts,dc=fudo,dc=org" authz-regexp "^uid=[^,/]+/root,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=admin,dc=fudo,dc=org" @@ -363,8 +364,9 @@ access to dn.subtree="ou=groups,${cfg.base}" attrs=memberUid by users read by * none -access to dn.subtree="ou=members,${cfg.base}" attrs=cn,sn,homeDirectory,loginShell,gecos,description +access to dn.subtree="ou=members,${cfg.base}" attrs=cn,sn,homeDirectory,loginShell,gecos,description,homeDirectory,uidNumber,gidNumber by group.exact="cn=admin,ou=groups,${cfg.base}" write + by dn.exact="cn=user_db_reader,${cfg.base}" read by users read by * none @@ -384,6 +386,9 @@ access to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by users read by * none + + +index objectClass,uid eq ''; declarativeContents = '' diff --git a/config/fudo.nix b/config/fudo/local-network.nix similarity index 91% rename from config/fudo.nix rename to config/fudo/local-network.nix index 631a1e1..29967c2 100644 --- a/config/fudo.nix +++ b/config/fudo/local-network.nix @@ -1,3 +1,7 @@ +# UNFINISHED! +# +# The plan is to bootstrap a local network config: DNS, DHCP, etc. + { lib, config, pkgs, ... }: with lib; @@ -33,14 +37,14 @@ let ipv6Address = mkOption { type = types.str; description = '' - The V6 IP of a given host, if any. + The V6 IP of this nameserver, if any. ''; }; ipv4Address = mkOption { type = types.str; description = '' - The V4 IP of a given host, if any. + The V4 IP of this nameserver, if any. ''; }; @@ -56,9 +60,6 @@ let }; in { - imports = [ - ./fudo/ldap.nix - ]; options = { diff --git a/config/fudo/mail-container.nix b/config/fudo/mail-container.nix new file mode 100644 index 0000000..948172b --- /dev/null +++ b/config/fudo/mail-container.nix @@ -0,0 +1,256 @@ +{ config, lib, ... }: + +with lib; +let + cfg = config.fudo.mail-server; + container-maildir = "/var/lib/mail"; + container-statedir = "/var/lib/mail-state"; + container-shared = "container/mail-server"; + container-postfix-cert = "${container-shared}/postfix/cert.pem"; + container-postfix-key = "${container-shared}/postfix/key.pem"; + container-dovecot-cert = "${container-shared}/dovecot/cert.pem"; + container-dovecot-key = "${container-shared}/dovecot/key.pem"; + container-fudo-ca-cert = "${container-shared}/fudo-ca.pem"; + + # Don't bother with group-id, nixos doesn't seem to use it anyway + container-mail-user = "mailer"; + container-mail-user-id = 542; + container-mail-group = "mailer"; + trusted-networks = config.fudo.prometheus.trusted-networks; + +in rec { + options.fudo.mail-server.container = { + ldap-url = mkOption { + type = types.str; + description = "URL of the LDAP server to use for authentication."; + example = "ldaps://auth.fudo.org/"; + }; + + # host-ip = mkOption { + # type = types.str; + # description = "The IP to assign to this server, for communication with the mail server container."; + # default = "10.110.0.1"; + # }; + + # container-ip = mkOption { + # type = types.str; + # description = "The IP to assign to the mail server container."; + # default = "10.110.0.2"; + # }; + }; + + config = mkIf (cfg.enableContainer && !cfg.enable) { + + # Disable postfix on thi host--it'll be run in the container instead + services.postfix.enable = false; + + # Copy data intended for the container to a path in /etc which can be + # bind-mounted. + environment.etc = { + "${container-postfix-cert}" = { + mode = "0444"; + source = cfg.postfix.ssl-certificate; + }; + + "${container-postfix-key}" = { + mode = "0400"; + source = cfg.postfix.ssl-private-key; + }; + + "${container-dovecot-cert}" = { + mode = "0444"; + source = cfg.dovecot.ssl-certificate; + }; + + "${container-dovecot-key}" = { + mode = "0400"; + source = cfg.dovecot.ssl-private-key; + }; + + "${container-fudo-ca-cert}" = { + mode = "0444"; + source = "/etc/nixos/static/fudo_ca.pem"; + }; + }; + + services.nginx = mkIf cfg.monitoring { + enable = true; + + virtualHosts = let + proxy-headers = '' + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + '' + ; + trusted-network-string = optionalString ((length trusted-networks) > 0) + (concatStringsSep "\n" + (map (network: "allow ${network};") trusted-networks)) + "\ndeny all;"; + in { + "${cfg.hostname}" = { + enableACME = true; + forceSSL = true; + + locations."/metrics/postfix" = { + proxyPass = "http://127.0.0.1:9154/metrics"; + + extraConfig = '' + ${proxy-headers} + + ${trusted-network-string} + ''; + }; + + locations."/metrics/dovecot" = { + proxyPass = "http://127.0.0.1:9166/metrics"; + + extraConfig = '' + ${proxy-headers} + + ${trusted-network-string} + ''; + }; + + locations."/metrics/rspamd" = { + proxyPass = "http://127.0.0.1:7980/metrics"; + + extraConfig = '' + ${proxy-headers} + + ${trusted-network-string} + ''; + }; + }; + }; + }; + + # services.xinetd = let + # xinetd-entry = name: port: { + # name = name; + # port = port; + # protocol = "tcp"; + # server = ""; + # extraConfig = '' + # socket_type = stream + # wait = no + # redirect = ${cfg.container.container-ip} ${toString port} + # ''; + # }; + # in { + # enable = true; + # services = [ + # (xinetd-entry "smtp" 25) + # (xinetd-entry "pop3" 110) + # (xinetd-entry "pop3s" 995) + # (xinetd-entry "imap" 143) + # (xinetd-entry "imaps" 993) + # (xinetd-entry "submission" 587) + # ]; + # }; + + containers.mail-server = { + + autoStart = true; + + bindMounts = { + "${container-maildir}" = { + hostPath = cfg.mail-directory; + isReadOnly = false; + }; + + "${container-statedir}" = { + hostPath = cfg.state-directory; + isReadOnly = false; + }; + + "/etc/${container-shared}" = { + hostPath = "/etc/${container-shared}"; + isReadOnly = true; + }; + }; + + config = { config, pkgs, ... }: { + + environment.systemPackages = with pkgs; [ + nmap + ]; + + imports = [ + ../local.nix + ]; + + environment = { + etc = { + "postfix-certs/key.pem" = { + source = "/etc/${container-postfix-key}"; + user = config.services.postfix.user; + mode = "0400"; + }; + + "dovecot-certs/key.pem" = { + source = "/etc/${container-dovecot-key}"; + user = config.services.dovecot2.user; + mode = "0400"; + }; + }; + }; + + users = { + users = { + ${container-mail-user} = { + isSystemUser = true; + uid = container-mail-user-id; + group = "mailer"; + }; + }; + + groups = { + ${container-mail-group} = { + members = ["mailer"]; + }; + }; + }; + + fudo.mail-server = + { + enable = true; + hostname = cfg.hostname; + domain = cfg.domain; + + debug = cfg.debug; + monitoring = cfg.monitoring; + + state-directory = container-statedir; + mail-directory = container-maildir; + + postfix.ssl-certificate = "/etc/${container-postfix-cert}"; + postfix.ssl-private-key = "/etc/postfix-certs/key.pem"; + + dovecot = { + ssl-certificate = "/etc/${container-dovecot-cert}"; + ssl-private-key = "/etc/dovecot-certs/key.pem"; + ldap-ca = "/etc/${container-fudo-ca-cert}"; + ldap-urls = cfg.dovecot.ldap-urls; + ldap-reader-dn = cfg.dovecot.ldap-reader-dn; + ldap-reader-passwd = cfg.dovecot.ldap-reader-passwd; + }; + + local-domains = cfg.local-domains; + + alias-users = cfg.alias-users; + user-aliases = cfg.user-aliases; + sender-blacklist = cfg.sender-blacklist; + recipient-blacklist = cfg.recipient-blacklist; + trusted-networks = cfg.trusted-networks; + + mail-user = container-mail-user; + mail-user-id = container-mail-user-id; + mail-group = container-mail-group; + + clamav.enable = cfg.clamav.enable; + + dkim.signing = cfg.dkim.signing; + }; + }; + }; + }; +} diff --git a/config/fudo/mail.nix b/config/fudo/mail.nix new file mode 100644 index 0000000..7b664a8 --- /dev/null +++ b/config/fudo/mail.nix @@ -0,0 +1,170 @@ +{ config, lib, pkgs, environment, ... }: + +with lib; +let + inherit (lib.strings) concatStringsSep; + cfg = config.fudo.mail-server; + +in { + + options.fudo.mail-server = { + enable = mkEnableOption "Fudo Email Server"; + + enableContainer = mkEnableOption '' + Run the mail server in a container. + + Mutually exclusive with mail-server.enable. + ''; + + domain = mkOption { + type = types.str; + description = "The main and default domain name for this email server."; + }; + + hostname = mkOption { + type = types.str; + description = "The domain name to use for the mail server."; + }; + + monitoring = mkEnableOption "Enable monitoring for the mail server."; + + mail-user = mkOption { + type = types.str; + description = "User to use for mail delivery."; + }; + + # No group id, because NixOS doesn't seem to use it + mail-group = mkOption { + type = types.str; + description = "Group to use for mail delivery."; + }; + + mail-user-id = mkOption { + type = types.int; + description = "UID of mail-user."; + }; + + local-domains = mkOption { + type = with types; listOf str; + description = "A list of domains for which we accept mail."; + default = ["localhost" "localhost.localdomain"]; + example = [ + "localhost" + "localhost.localdomain" + "somedomain.com" + "otherdomain.org" + ]; + }; + + mail-directory = mkOption { + type = types.str; + description = "Path to use for mail storage."; + }; + + state-directory = mkOption { + type = types.str; + description = "Path to use for state data."; + }; + + trusted-networks = mkOption { + type = with types; listOf str; + description = "A list of trusted networks, for which we will happily relay without auth."; + example = [ + "10.0.0.0/16" + "192.168.0.0/24" + ]; + }; + + sender-blacklist = mkOption { + type = with types; listOf str; + description = "A list of email addresses for whom we will not send email."; + default = []; + example = [ + "baduser@test.com" + "change-pw@test.com" + ]; + }; + + recipient-blacklist = mkOption { + type = with types; listOf str; + description = "A list of email addresses for whom we will not accept email."; + default = []; + example = [ + "baduser@test.com" + "change-pw@test.com" + ]; + }; + + message-size-limit = mkOption { + type = types.int; + description = "Size of max email in megabytes."; + default = 30; + }; + + user-aliases = mkOption { + type = with types; loaOf(listOf str); + description = "A map of real user to list of aliases."; + example = { + someuser = ["alias0" "alias1"]; + }; + }; + + alias-users = mkOption { + type = with types; loaOf(listOf str); + description = "A map of email alias to a list of users."; + example = { + alias = ["realuser0" "realuser1"]; + }; + }; + + mailboxes = mkOption { + description = '' + The mailboxes for dovecot. + + Depending on the mail client used it might be necessary to change some mailbox's name. + ''; + default = [ + { + name = "Trash"; + auto = "no"; + specialUse = "Trash"; + } + { + name = "Junk"; + auto = "subscribe"; + specialUse = "Junk"; + } + { + name = "Drafts"; + auto = "subscribe"; + specialUse = "Drafts"; + } + { + name = "Sent"; + auto = "subscribe"; + specialUse = "Sent"; + } + ]; + }; + + debug = mkOption { + description = "Enable debugging on mailservers."; + type = types.bool; + default = false; + }; + + max-user-connections = mkOption { + description = "Max simultaneous connections per user."; + type = types.int; + default = 20; + }; + }; + + imports = [ + ./mail/dkim.nix + ./mail/dovecot.nix + ./mail/postfix.nix + ./mail/rspamd.nix + ./mail/clamav.nix + ]; +} diff --git a/config/fudo/mail/clamav.nix b/config/fudo/mail/clamav.nix new file mode 100644 index 0000000..4dd2a74 --- /dev/null +++ b/config/fudo/mail/clamav.nix @@ -0,0 +1,28 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.fudo.mail-server; + +in { + options.fudo.mail-server.clamav = { + enable = mkOption { + description = "Enable virus scanning with ClamAV."; + type = types.bool; + default = true; + }; + }; + + config = mkIf (cfg.enable && cfg.clamav.enable) { + + services.clamav = { + daemon = { + enable = true; + extraConfig = '' + PhishingScanURLs no + ''; + }; + updater.enable = true; + }; + }; +} diff --git a/config/fudo/mail/dkim.nix b/config/fudo/mail/dkim.nix new file mode 100644 index 0000000..3e0cb48 --- /dev/null +++ b/config/fudo/mail/dkim.nix @@ -0,0 +1,114 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.fudo.mail-server; + + createDomainDkimCert = dom: + let + dkim_key = "${cfg.dkim.key-directory}/${dom}.${cfg.dkim.selector}.key"; + dkim_txt = "${cfg.dkim.key-directory}/${dom}.${cfg.dkim.selector}.txt"; + in + '' + if [ ! -f "${dkim_key}" ] || [ ! -f "${dkim_txt}" ] + then + ${cfg.dkim.package}/bin/opendkim-genkey -s "${cfg.dkim.selector}" \ + -d "${dom}" \ + --bits="${toString cfg.dkim.key-bits}" \ + --directory="${cfg.dkim.key-directory}" + mv "${cfg.dkim.key-directory}/${cfg.dkim.selector}.private" "${dkim_key}" + mv "${cfg.dkim.key-directory}/${cfg.dkim.selector}.txt" "${dkim_txt}" + echo "Generated key for domain ${dom} selector ${cfg.dkim.selector}" + fi + ''; + + createAllCerts = lib.concatStringsSep "\n" (map createDomainDkimCert cfg.local-domains); + + keyTable = pkgs.writeText "opendkim-KeyTable" + (lib.concatStringsSep "\n" (lib.flip map cfg.local-domains + (dom: "${dom} ${dom}:${cfg.dkim.selector}:${cfg.dkim.key-directory}/${dom}.${cfg.dkim.selector}.key"))); + signingTable = pkgs.writeText "opendkim-SigningTable" + (lib.concatStringsSep "\n" (lib.flip map cfg.local-domains (dom: "${dom} ${dom}"))); + + dkim = config.services.opendkim; + args = [ "-f" "-l" ] ++ lib.optionals (dkim.configFile != null) [ "-x" dkim.configFile ]; +in +{ + + options.fudo.mail-server.dkim = { + signing = mkOption { + type = types.bool; + default = true; + description = "Enable dkim signatures for mail."; + }; + + key-directory = mkOption { + type = types.str; + default = "/var/dkim"; + description = "Path to use to store DKIM keys."; + }; + + selector = mkOption { + type = types.str; + default = "mail"; + description = "Name to use for mail-signing keys."; + }; + + key-bits = mkOption { + type = types.int; + default = 2048; + description = '' + How many bits in generated DKIM keys. RFC6376 advises minimum 1024-bit keys. + + If you have already deployed a key with a different number of bits than specified + here, then you should use a different selector (dkimSelector). In order to get + this package to generate a key with the new number of bits, you will either have to + change the selector or delete the old key file. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.opendkim; + description = "OpenDKIM package to use."; + }; + }; + + config = mkIf (cfg.dkim.signing && cfg.enable) { + services.opendkim = { + enable = true; + selector = cfg.dkim.selector; + domains = "csl:${builtins.concatStringsSep "," cfg.local-domains}"; + configFile = pkgs.writeText "opendkim.conf" ('' + Canonicalization relaxed/simple + UMask 0002 + Socket ${dkim.socket} + KeyTable file:${keyTable} + SigningTable file:${signingTable} + '' + (lib.optionalString cfg.debug '' + Syslog yes + SyslogSuccess yes + LogWhy yes + '')); + }; + + users.users = { + "${config.services.postfix.user}" = { + extraGroups = [ "${config.services.opendkim.group}" ]; + }; + }; + + systemd.services.opendkim = { + preStart = lib.mkForce createAllCerts; + serviceConfig = { + ExecStart = lib.mkForce "${cfg.dkim.package}/bin/opendkim ${escapeShellArgs args}"; + PermissionsStartOnly = lib.mkForce false; + }; + }; + + systemd.tmpfiles.rules = [ + "d '${cfg.dkim.key-directory}' - ${config.services.opendkim.user} ${config.services.opendkim.group} - -" + ]; + }; +} diff --git a/config/fudo/mail/dovecot.nix b/config/fudo/mail/dovecot.nix new file mode 100644 index 0000000..6c5d4fd --- /dev/null +++ b/config/fudo/mail/dovecot.nix @@ -0,0 +1,242 @@ +{ config, lib, pkgs, environment, ... }: + +with lib; +let + cfg = config.fudo.mail-server; + + state-directory = "${cfg.state-directory}/dovecot"; + + pipe-bin = pkgs.stdenv.mkDerivation { + name = "pipe_bin"; + src = ./dovecot/pipe_bin; + buildInputs = with pkgs; [ makeWrapper coreutils bash rspamd ]; + buildCommand = '' + mkdir -p $out/pipe/bin + cp $src/* $out/pipe/bin/ + chmod a+x $out/pipe/bin/* + patchShebangs $out/pipe/bin + + for file in $out/pipe/bin/*; do + wrapProgram $file \ + --set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin" + done + ''; + }; + + ldap-conf = filename: uris: + pkgs.writeText filename '' + uris = ${concatStringsSep " " uris} + ldap_version = 3 + dn = ${cfg.dovecot.ldap-reader-dn} + dnpass = ${cfg.dovecot.ldap-reader-passwd} + auth_bind = yes + auth_bind_userdn = uid=%u,ou=members,dc=fudo,dc=org + base = dc=fudo,dc=org + # tls_ca_cert_file = ${cfg.dovecot.ldap-ca} + # FIXME: turn back on when certs work + tls = no + tls_require_cert = try + ''; + + dovecot-user = config.services.dovecot2.user; + +in { + options.fudo.mail-server.dovecot = { + ssl-private-key = mkOption { + type = types.str; + description = "Location of the server SSL private key."; + }; + + ssl-certificate = mkOption { + type = types.str; + description = "Location of the server SSL certificate."; + }; + + ldap-ca = mkOption { + type = types.str; + description = "The path to the CA cert used to sign the LDAP server certificate."; + }; + + ldap-urls = mkOption { + type = with types; listOf str; + description = "The urls of LDAP servers."; + }; + + ldap-reader-dn = mkOption { + type = types.str; + description = '' + DN to use for reading user information. Needs access to homeDirectory, + uidNumber, gidNumber, and uid, but not password attributes. + ''; + }; + + ldap-reader-passwd = mkOption { + type = types.str; + description = '' + Password for the user specified in ldap-reader-dn. + ''; + }; + }; + + config = mkIf cfg.enable { + + services.prometheus.exporters.dovecot = mkIf cfg.monitoring { + enable = true; + scopes = ["user" "global"]; + listenAddress = "127.0.0.1"; + port = 9166; + socketPath = "/var/run/dovecot2/old-stats"; + }; + + services.dovecot2 = { + enable = true; + enableImap = true; + enableLmtp = true; + enablePop3 = true; + enablePAM = false; + + + createMailUser = true; + + mailUser = cfg.mail-user; + mailGroup = cfg.mail-group; + mailLocation = "maildir:${cfg.mail-directory}/%u/"; + + sslServerCert = cfg.dovecot.ssl-certificate; + sslServerKey = cfg.dovecot.ssl-private-key; + + modules = [ pkgs.dovecot_pigeonhole ]; + protocols = [ "sieve" ]; + + sieveScripts = { + after = builtins.toFile "spam.sieve" '' + require "fileinto"; + + if header :is "X-Spam" "Yes" { + fileinto "Junk"; + stop; + } + ''; + }; + + mailboxes = cfg.mailboxes; + + extraConfig = '' + #Extra Config + + # The prometheus exporter still expects an older style of metrics + mail_plugins = $mail_plugins old_stats + service old-stats { + unix_listener old-stats { + user = dovecot-exporter + group = dovecot-exporter + } + } + + ${lib.optionalString cfg.debug '' + mail_debug = yes + auth_debug = yes + verbose_ssl = yes + ''} + + protocol imap { + mail_max_userip_connections = ${toString cfg.max-user-connections} + mail_plugins = $mail_plugins imap_sieve + } + + protocol pop3 { + mail_max_userip_connections = ${toString cfg.max-user-connections} + } + + protocol lmtp { + mail_plugins = $mail_plugins sieve + } + + mail_access_groups = ${cfg.mail-group} + ssl = required + + # When looking up usernames, just use the name, not the full address + auth_username_format = %n + + service lmtp { + # Enable logging in debug mode + ${optionalString cfg.debug "executable = lmtp -L"} + + # Unix socket for postfix to deliver messages via lmtp + unix_listener dovecot-lmtp { + user = "postfix" + group = ${cfg.mail-group} + mode = 0600 + } + + # Drop privs, since all mail is owned by one user + user = ${cfg.mail-user} + group = ${cfg.mail-group} + } + + auth_mechanisms = login plain + passdb { + driver = ldap + args = ${ldap-conf "ldap-passdb.conf" cfg.dovecot.ldap-urls} + } + userdb { + driver = static + args = uid=${toString cfg.mail-user-id} home=${cfg.mail-directory}/%u + } + + # Used by postfix to authorize users + service auth { + unix_listener auth { + mode = 0660 + user = "${config.services.postfix.user}" + group = ${config.services.postfix.group} + } + } + + namespace inbox { + separator = "/" + inbox = yes + } + + plugin { + sieve_plugins = sieve_imapsieve sieve_extprograms + sieve = file:/var/sieve/%u/scripts;active=/var/sieve/%u/active.sieve + sieve_default = file:/var/sieve/%u/default.sieve + sieve_default_name = default + # From elsewhere to Spam folder + imapsieve_mailbox1_name = Junk + imapsieve_mailbox1_causes = COPY + imapsieve_mailbox1_before = file:${state-directory}/imap_sieve/report-spam.sieve + # From Spam folder to elsewhere + imapsieve_mailbox2_name = * + imapsieve_mailbox2_from = Junk + imapsieve_mailbox2_causes = COPY + imapsieve_mailbox2_before = file:${state-directory}/imap_sieve/report-ham.sieve + sieve_pipe_bin_dir = ${pipe-bin}/pipe/bin + sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment + } + + recipient_delimiter = + + + lmtp_save_to_detail_mailbox = yes + + lda_mailbox_autosubscribe = yes + lda_mailbox_autocreate = yes + ''; + }; + + systemd.services.dovecot2.preStart = '' + mkdir -p '${state-directory}' + chown ${dovecot-user}:${cfg.mail-group} '${state-directory}' + rm -rf '${state-directory}/imap_sieve' + mkdir '${state-directory}/imap_sieve' + cp -p "${./dovecot/imap_sieve}"/*.sieve '${state-directory}/imap_sieve/' + for k in "${state-directory}/imap_sieve"/*.sieve ; do + ${pkgs.dovecot_pigeonhole}/bin/sievec "$k" + done + chown -R '${dovecot-user}:${cfg.mail-group}' '${state-directory}/imap_sieve' + + chown ${cfg.mail-user}:${cfg.mail-group} ${cfg.mail-directory} + ''; + }; +} diff --git a/config/fudo/mail/dovecot/imap_sieve/report-ham.sieve b/config/fudo/mail/dovecot/imap_sieve/report-ham.sieve new file mode 100644 index 0000000..a9d30cf --- /dev/null +++ b/config/fudo/mail/dovecot/imap_sieve/report-ham.sieve @@ -0,0 +1,15 @@ +require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; + +if environment :matches "imap.mailbox" "*" { + set "mailbox" "${1}"; +} + +if string "${mailbox}" "Trash" { + stop; +} + +if environment :matches "imap.user" "*" { + set "username" "${1}"; +} + +pipe :copy "sa-learn-ham.sh" [ "${username}" ]; diff --git a/config/fudo/mail/dovecot/imap_sieve/report-spam.sieve b/config/fudo/mail/dovecot/imap_sieve/report-spam.sieve new file mode 100644 index 0000000..4024b7a --- /dev/null +++ b/config/fudo/mail/dovecot/imap_sieve/report-spam.sieve @@ -0,0 +1,7 @@ +require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; + +if environment :matches "imap.user" "*" { + set "username" "${1}"; +} + +pipe :copy "sa-learn-spam.sh" [ "${username}" ]; \ No newline at end of file diff --git a/config/fudo/mail/dovecot/pipe_bin/sa-learn-ham.sh b/config/fudo/mail/dovecot/pipe_bin/sa-learn-ham.sh new file mode 100755 index 0000000..76fc4ed --- /dev/null +++ b/config/fudo/mail/dovecot/pipe_bin/sa-learn-ham.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -o errexit +exec rspamc -h /run/rspamd/worker-controller.sock learn_ham \ No newline at end of file diff --git a/config/fudo/mail/dovecot/pipe_bin/sa-learn-spam.sh b/config/fudo/mail/dovecot/pipe_bin/sa-learn-spam.sh new file mode 100755 index 0000000..2a2f766 --- /dev/null +++ b/config/fudo/mail/dovecot/pipe_bin/sa-learn-spam.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -o errexit +exec rspamc -h /run/rspamd/worker-controller.sock learn_spam \ No newline at end of file diff --git a/config/fudo/mail/postfix.nix b/config/fudo/mail/postfix.nix new file mode 100644 index 0000000..927f8c5 --- /dev/null +++ b/config/fudo/mail/postfix.nix @@ -0,0 +1,297 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + inherit (lib.strings) concatStringsSep; + + cfg = config.fudo.mail-server; + + make-user-aliases = entries: + concatStringsSep "\n" + (mapAttrsToList (user: aliases: + concatStringsSep "\n" + (map (alias: "${alias} ${user}") aliases)) + entries); + + make-alias-users = domains: entries: + concatStringsSep "\n" + (flatten + (mapAttrsToList (alias: users: + (map (domain: + "${alias}@${domain} ${concatStringsSep "," users}") + domains)) + entries)); + + policyd-spf = pkgs.writeText "policyd-spf.conf" ( + cfg.postfix.policy-spf-extra-config + + (lib.optionalString cfg.debug '' + debugLevel = 4 + '')); + + submission-header-cleanup-rules = pkgs.writeText "submission_header_cleanup_rules" ('' + # Removes sensitive headers from mails handed in via the submission port. + # See https://thomas-leister.de/mailserver-debian-stretch/ + # Uses "pcre" style regex. + + /^Received:/ IGNORE + /^X-Originating-IP:/ IGNORE + /^X-Mailer:/ IGNORE + /^User-Agent:/ IGNORE + /^X-Enigmail:/ IGNORE + ''); + + blacklist-postfix-entry = sender: "${sender} REJECT"; + blacklist-postfix-file = entries: + concatStringsSep "\n" (map blacklist-postfix-entry entries); + sender-blacklist-file = builtins.toFile "reject_senders" + (blacklist-postfix-file cfg.sender-blacklist); + recipient-blacklist-file = builtins.toFile "reject_recipients" + (blacklist-postfix-file cfg.recipient-blacklist); + + # A list of domains for which we accept mail + virtual-mailbox-map-file = builtins.toFile "virtual_mailbox_map" + (concatStringsSep "\n" + (map (domain: "@${domain} OK") cfg.local-domains)); + + sender-login-map-file = let + escapeDot = (str: replaceStrings ["."] ["\\."] str); + in builtins.toFile "sender_login_maps" + (concatStringsSep "\n" + (map (domain: "/^(.*)@${escapeDot domain}$/ \${1}") cfg.local-domains)); + + mapped-file = name: "hash:/var/lib/postfix/conf/${name}"; + + pcre-file = name: "pcre:/var/lib/postfix/conf/${name}"; + +in { + + options.fudo.mail-server.postfix = { + + ssl-private-key = mkOption { + type = types.str; + description = "Location of the server SSL private key."; + }; + + ssl-certificate = mkOption { + type = types.str; + description = "Location of the server SSL certificate."; + }; + + policy-spf-extra-config = mkOption { + type = types.lines; + default = ""; + example = '' + skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1 + ''; + description = '' + Extra configuration options for policyd-spf. This can be use to among + other things skip spf checking for some IP addresses. + ''; + }; + }; + + config = mkIf cfg.enable { + + services.prometheus.exporters.postfix = mkIf cfg.monitoring { + enable = true; + systemd.enable = true; + }; + + services.postfix = { + enable = true; + domain = cfg.domain; + origin = cfg.domain; + hostname = cfg.hostname; + destination = ["localhost" "localhost.localdomain"] ++ + (map (domain: "localhost.${domain}") cfg.local-domains); + + enableHeaderChecks = true; + enableSmtp = true; + enableSubmission = true; + + mapFiles."reject_senders" = sender-blacklist-file; + mapFiles."reject_recipients" = recipient-blacklist-file; + mapFiles."virtual_mailbox_map" = virtual-mailbox-map-file; + mapFiles."sender_login_map" = sender-login-map-file; + + # TODO: enable! + # headerChecks = [ { action = "REDIRECT spam@example.com"; pattern = "/^X-Spam-Flag:/"; } ]; + networks = cfg.trusted-networks; + + virtual = '' + ${make-user-aliases cfg.user-aliases} + + ${make-alias-users cfg.local-domains cfg.alias-users} + ''; + + sslCert = cfg.postfix.ssl-certificate; + sslKey = cfg.postfix.ssl-private-key; + + config = { + virtual_mailbox_domains = builtins.toFile "domain-list" (concatStringsSep "\n" cfg.local-domains); + # virtual_mailbox_base = "${cfg.mail-directory}/"; + virtual_mailbox_maps = mapped-file "virtual_mailbox_map"; + + virtual_uid_maps = "static:${toString cfg.mail-user-id}"; + virtual_gid_maps = "static:${toString config.users.groups."${cfg.mail-group}".gid}"; + + virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp"; + + # NOTE: it's important that this ends with /, to indicate Maildir format! + # mail_spool_directory = "${cfg.mail-directory}/"; + message_size_limit = toString(cfg.message-size-limit * 1024 * 1024); + + smtpd_banner = "${cfg.hostname} ESMTP NO UCE"; + + tls_eecdh_strong_curve = "prime256v1"; + tls_eecdh_ultra_curve = "secp384r1"; + + policy-spf_time_limit = "3600s"; + + smtp_host_lookup = "dns, native"; + + smtpd_sasl_type = "dovecot"; + smtpd_sasl_path = "/run/dovecot2/auth"; + smtpd_sasl_auth_enable = "yes"; + + smtpd_sender_login_maps = (pcre-file "sender_login_map"); + + disable_vrfy_command = "yes"; + + recipient_delimiter = "+"; + + milter_protocol = "6"; + milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer}"; + + smtpd_milters = [ + "unix:/run/rspamd/rspamd-milter.sock" + "unix:/var/run/opendkim/opendkim.sock" + ]; + + non_smtpd_milters = [ + "unix:/run/rspamd/rspamd-milter.sock" + "unix:/var/run/opendkim/opendkim.sock" + ]; + + smtpd_relay_restrictions = [ + "permit_mynetworks" + "permit_sasl_authenticated" + "reject_unauth_destination" + "reject_unauth_pipelining" + "reject_unauth_destination" + "reject_unknown_sender_domain" + ]; + + smtpd_sender_restrictions = [ + "check_sender_access ${mapped-file "reject_senders"}" + ]; + + smtpd_recipient_restrictions = [ + "check_sender_access ${mapped-file "reject_recipients"}" + "permit_mynetworks" + "permit_sasl_authenticated" + "check_policy_service unix:private/policy-spf" + "reject_unknown_recipient_domain" + "reject_unauth_pipelining" + "reject_unauth_destination" + "reject_invalid_hostname" + "reject_non_fqdn_hostname" + "reject_non_fqdn_sender" + "reject_non_fqdn_recipient" + ]; + + # Handled by submission + smtpd_tls_security_level = "may"; + + smtpd_tls_eecdh_grade = "ultra"; + + # Disable obselete protocols + smtpd_tls_protocols = [ + "TLSv1.2" + "TLSv1.1" + "!TLSv1" + "!SSLv2" + "!SSLv3" + ]; + smtp_tls_protocols = [ + "TLSv1.2" + "TLSv1.1" + "!TLSv1" + "!SSLv2" + "!SSLv3" + ]; + smtpd_tls_mandatory_protocols = [ + "TLSv1.2" + "TLSv1.1" + "!TLSv1" + "!SSLv2" + "!SSLv3" + ]; + smtp_tls_mandatory_protocols = [ + "TLSv1.2" + "TLSv1.1" + "!TLSv1" + "!SSLv2" + "!SSLv3" + ]; + + smtp_tls_ciphers = "high"; + smtpd_tls_ciphers = "high"; + smtp_tls_mandatory_ciphers = "high"; + smtpd_tls_mandatory_ciphers = "high"; + + smtpd_tls_mandatory_exclude_ciphers = ["MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL" "aNULL"]; + smtpd_tls_exclude_ciphers = ["MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL" "aNULL"]; + smtp_tls_mandatory_exclude_ciphers = ["MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL" "aNULL"]; + smtp_tls_exclude_ciphers = ["MD5" "DES" "ADH" "RC4" "PSD" "SRP" "3DES" "eNULL" "aNULL"]; + + tls_preempt_cipherlist = "yes"; + + smtpd_tls_auth_only = "yes"; + + smtpd_tls_loglevel = "1"; + + tls_random_source = "dev:/dev/urandom"; + }; + + submissionOptions = { + smtpd_tls_security_level = "encrypt"; + smtpd_sasl_auth_enable = "yes"; + smtpd_sasl_type = "dovecot"; + smtpd_sasl_path = "/run/dovecot2/auth"; + smtpd_sasl_security_options = "noanonymous"; + smtpd_sasl_local_domain = cfg.domain; + smtpd_client_restrictions = "permit_sasl_authenticated,reject"; + smtpd_sender_restrictions = "reject_sender_login_mismatch,reject_unknown_sender_domain"; + smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"; + cleanup_service_name = "submission-header-cleanup"; + }; + + masterConfig = { + "policy-spf" = { + type = "unix"; + privileged = true; + chroot = false; + command = "spawn"; + args = [ "user=nobody" "argv=${pkgs.pypolicyd-spf}/bin/policyd-spf" "${policyd-spf}"]; + }; + "submission-header-cleanup" = { + type = "unix"; + private = false; + chroot = false; + maxproc = 0; + command = "cleanup"; + args = ["-o" "header_checks=pcre:${submission-header-cleanup-rules}"]; + }; + }; + }; + + # Postfix requires dovecot lmtp socket, dovecot auth socket and certificate to work + systemd.services.postfix = { + after = [ "dovecot2.service" ] + ++ (lib.optional cfg.dkim.signing "opendkim.service"); + requires = [ "dovecot2.service" ] + ++ (lib.optional cfg.dkim.signing "opendkim.service"); + }; + }; +} diff --git a/config/fudo/mail/rspamd.nix b/config/fudo/mail/rspamd.nix new file mode 100644 index 0000000..4bc9324 --- /dev/null +++ b/config/fudo/mail/rspamd.nix @@ -0,0 +1,88 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.fudo.mail-server; + +in { + config = mkIf cfg.enable { + services.prometheus.exporters.rspamd.enable = true; + + services.rspamd = { + + enable = true; + + locals = { + "milter_headers.conf" = { + text = '' + extended_spam_headers = yes; + ''; + }; + + "antivirus.conf" = { + text = '' + clamav { + action = "reject"; + symbol = "CLAM_VIRUS"; + type = "clamav"; + log_clean = true; + servers = "/run/clamav/clamd.ctl"; + scan_mime_parts = false; # scan mail as a whole unit, not parts. seems to be needed to work at all + } + ''; + }; + }; + + overrides = { + "milter_headers.conf" = { + text = '' + extended_spam_headers = true; + ''; + }; + }; + + workers.rspamd_proxy = { + type = "rspamd_proxy"; + bindSockets = [{ + socket = "/run/rspamd/rspamd-milter.sock"; + mode = "0664"; + }]; + count = 1; # Do not spawn too many processes of this type + extraConfig = '' + milter = yes; # Enable milter mode + timeout = 120s; # Needed for Milter usually + + upstream "local" { + default = yes; # Self-scan upstreams are always default + self_scan = yes; # Enable self-scan + } + ''; + }; + + workers.controller = { + type = "controller"; + count = 1; + bindSockets = [ + "localhost:11334" + { + socket = "/run/rspamd/worker-controller.sock"; + mode = "0666"; + } + ]; + includes = []; + }; + }; + + systemd.services.rspamd = { + requires = (optional cfg.clamav.enable "clamav-daemon.service"); + after = (optional cfg.clamav.enable "clamav-daemon.service"); + }; + + systemd.services.postfix = { + after = [ "rspamd.service" ]; + requires = [ "rspamd.service" ]; + }; + + users.extraUsers.${config.services.postfix.user}.extraGroups = [ config.services.rspamd.group ]; + }; +} diff --git a/config/fudo/minecraft-server.nix b/config/fudo/minecraft-server.nix new file mode 100644 index 0000000..06f9c67 --- /dev/null +++ b/config/fudo/minecraft-server.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.fudo.minecraft-server; + +in { + options.fudo.minecraft-server = { + enable = mkEnableOption "Start a minecraft server."; + + package = mkOption { + type = types.package; + description = "Minecraft package to use."; + default = pkgs.minecraft-server_1_15_1; + }; + + data-dir = mkOption { + type = types.path; + description = "Path at which to store minecraft data."; + }; + + world-name = mkOption { + type = types.str; + description = "Name of the server world (used in saves etc)."; + }; + + motd = mkOption { + type = types.str; + description = "Welcome message for newcomers."; + }; + + game-mode = mkOption { + type = types.enum ["survival" "creative" "adventure" "spectator"]; + description = "Game mode of the server."; + default = "survival"; + }; + + difficulty = mkOption { + type = types.int; + description = "Difficulty level, where 0 is peaceful and 3 is hard."; + default = 2; + }; + }; + + config = mkIf cfg.enable { + services.minecraft-server = { + enable = true; + package = cfg.package; + dataDir = cfg.data-dir; + eula = true; + declarative = true; + serverProperties = { + level-name = cfg.world-name; + motd = cfg.motd; + difficulty = cfg.difficulty; + gamemode = cfg.game-mode; + }; + }; + }; +} diff --git a/config/fudo/node-exporter.nix b/config/fudo/node-exporter.nix new file mode 100644 index 0000000..82236cb --- /dev/null +++ b/config/fudo/node-exporter.nix @@ -0,0 +1,58 @@ +{ lib, config, pkgs, ... }: + +with lib; +let + inherit (lib.strings) concatStringsSep; + + cfg = config.fudo.node-exporter; + fudo-cfg = config.fudo.common; + + allow-network = network: "allow ${network};"; + +in { + options.fudo.node-exporter = { + enable = mkEnableOption "Enable a Prometheus node exporter with some reasonable settings."; + + hostname = mkOption { + type = types.str; + description = "Hostname from which to export statistics."; + }; + }; + + config = mkIf cfg.enable { + services = { + # This'll run an exporter at localhost:9100 + prometheus.exporters.node = { + enable = true; + enabledCollectors = [ "systemd" ]; + listenAddress = "127.0.0.1"; + port = 9100; + user = "node"; + }; + + # ...And this'll expose the above to the outside world, or at least the + # list of trusted networks, with SSL protection. + nginx = { + enable = true; + + virtualHosts."${cfg.hostname}" = { + enableACME = true; + forceSSL = true; + + location."/metrics/node" = { + extraConfig = '' + ${concatStringsSep "\n" (map allow-network fudo-cfg.local-networks)} + allow 127.0.0.0/16; + deny all; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + ''; + + proxyPass = "http://127.0.0.1:9100/metrics"; + }; + }; + }; + }; + }; +} diff --git a/config/fudo/postgres.nix b/config/fudo/postgres.nix new file mode 100644 index 0000000..d24cc80 --- /dev/null +++ b/config/fudo/postgres.nix @@ -0,0 +1,197 @@ +{ config, lib, pkgs, environment, ... }: + +with lib; +let + + cfg = config.fudo.postgresql; + + userOpts = { username, ... }: { + options = { + password = mkOption { + type = types.str; + description = "The user's (plaintext) password."; + }; + + databases = mkOption { + type = with types; listOf str; + description = "Databases to which this user has access."; + default = []; + }; + }; + }; + + databaseOpts = { dbname, ... }: { + options = { + users = mkOption { + type = with types; listOf str; + description = "A list of users who should have access to this database."; + default = []; + }; + }; + }; + + userDatabaseAccess = user: databases: + listToAttrs (map (database-name: + { + name = "DATABASE ${database-name}"; + value = "ALL PRIVILEGES"; + }) + databases); + + stringJoin = joiner: els: + if (length els) == 0 then + "" + else + foldr(lel: rel: "${lel}${joiner}${rel}") (last els) (init els); + + makeEntry = nw: + "host all all ${nw} gss include_realm=0 krb_realm=FUDO.ORG"; + + makeNetworksEntry = networks: + stringJoin "\n" (map makeEntry networks); + + setPasswordSql = username: attrs: + "ALTER USER ${username} ENCRYPTED PASSWORD '${attrs.password}';"; + + setPasswordsSql = users: + stringJoin "\n" + (mapAttrsToList (username: attrs: setPasswordSql username attrs) + users); + + makeLocalUserPasswordEntries = users: + stringJoin "\n" + (mapAttrsToList + (username: attrs: + stringJoin "\n" + (map (db: '' + host ${username} ${db} 127.0.0.1/16 md5 + host ${username} ${db} ::1/128 md5 + '') attrs.databases)) + users); + + +in { + + options.fudo.postgresql = { + enable = mkEnableOption "Fudo PostgreSQL Server"; + + ssl-private-key = mkOption { + type = types.str; + description = "Location of the server SSL private key."; + }; + + ssl-certificate = mkOption { + type = types.str; + description = "Location of the server SSL certificate."; + }; + + keytab = mkOption { + type = types.str; + description = "Location of the server Kerberos keytab."; + }; + + local-networks = mkOption { + type = with types; listOf str; + description = "A list of networks from which to accept connections."; + example = [ + "10.0.0.1/16" + ]; + default = []; + }; + + local-users = mkOption { + type = with types; loaOf (submodule userOpts); + description = "A map of users to user attributes."; + example = { + sampleUser = { + password = "some-password"; + databases = [ "sample_user_db" ]; + }; + }; + default = {}; + }; + + databases = mkOption { + type = with types; loaOf (submodule databaseOpts); + description = "A map of databases to database options."; + default = {}; + }; + }; + + config = mkIf cfg.enable { + + environment = { + systemPackages = with pkgs; [ + postgresql_11_gssapi + ]; + + etc = { + "postgresql/private/privkey.pem" = { + mode = "0400"; + user = "postgres"; + group = "postgres"; + source = cfg.ssl-private-key; + }; + + "postgresql/cert.pem" = { + mode = "0444"; + user = "postgres"; + group = "postgres"; + source = cfg.ssl-certificate; + }; + + "postgresql/private/postgres.keytab" = { + mode = "0400"; + user = "postgres"; + group = "postgres"; + source = cfg.keytab; + }; + }; + }; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_11_gssapi; + enableTCPIP = true; + ensureDatabases = mapAttrsToList (name: value: name) cfg.databases; + ensureUsers = mapAttrsToList + (username: attrs: + { + name = username; + ensurePermissions = + #{ "DATABASE ${username}" = "ALL PRIVILEGES"; }; + (userDatabaseAccess username attrs.databases); + }) + cfg.local-users; + + extraConfig = + '' + krb_server_keyfile = '/etc/postgresql/private/postgres.keytab' + + ssl = true + ssl_cert_file = '/etc/postgresql/cert.pem' + ssl_key_file = '/etc/postgresql/private/privkey.pem' + + unix_socket_directories = '/var/run/postgresql' + ''; + + authentication = + '' + local all all ident + + ${makeLocalUserPasswordEntries cfg.local-users} + + # host-local + host all all 127.0.0.1/32 gss include_realm=0 krb_realm=FUDO.ORG + host all all ::1/128 gss include_realm=0 krb_realm=FUDO.ORG + + # local networks + ${makeNetworksEntry cfg.local-networks} + ''; + + initialScript = pkgs.writeText "database-init.sql" '' + ${setPasswordsSql cfg.local-users} + ''; + }; + }; +} diff --git a/config/fudo/profiles.nix b/config/fudo/profiles.nix new file mode 100644 index 0000000..0a1d78d --- /dev/null +++ b/config/fudo/profiles.nix @@ -0,0 +1,32 @@ +# Switch between different basic profiles +{ lib, config, pkgs, ... }: + +with lib; +let + profile = config.fudo.profile; + + profiles = { + desktop = ./profiles/desktop.nix { + pkgs = pkgs; + config = config; + }; + server = ./profiles/server.nix { + pkgs = pkgs; + config = config; + }; + }; + +in { + options.fudo.profile = { + type = types.enum (attrNames profiles); + example = "desktop"; + description = '' + The profile to use for this host. This will do some profile-dependent + configuration, for example removing X-libs from servers and adding UI + packages to desktops. + ''; + default = "server"; + }; + + config = optionalAttrs (profiles ? profile) profiles.${profile}; +} diff --git a/config/fudo/profiles/desktop.nix b/config/fudo/profiles/desktop.nix new file mode 100644 index 0000000..1aa0d53 --- /dev/null +++ b/config/fudo/profiles/desktop.nix @@ -0,0 +1,151 @@ +{ config, pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ + cool-retro-term + chrome-gnome-shell + chromium + ffmpeg-full + firefox + gimp + glxinfo + gnome3.gnome-shell + gnome3.gnome-session + google-chrome + gtk2 + gtk2-x11 + gtk3 + gtkimageview + i3lock + libfixposix + minecraft + mplayer + nomacs + openssl_1_1 + redshift + rhythmbox + shotwell + spotify + sqlite + steam + system-config-printer + virtmanager + xorg.xev + xzgv + virtmanager-qt + ]; + + # Splash screen + boot.plymouth.enable = true; + + services.avahi = { + enable = true; + browseDomains = [config.fudo.domain;]; + domainName = config.fudo.domain; + }; + + boot.tmpOnTmpfs = true; + + services.xserver = { + enable = true; + + layout = "us"; + xkbVariant = "dvp"; + xkbOptions = "ctrl:nocaps"; + + desktopManager.gnome3.enable = true; + desktopManager.default = "gnome3"; + + displayManager.gdm.enable = true; + + windowManager.session = pkgs.lib.singleton { + name = "stumpwm"; + start = '' + ${pkgs.lispPackages.stumpwm}/bin/stumpwm & + waidPID=$! + ''; + }; + }; + + services.printing = { + enable = true; + }; + + services.gnome3 = { + evolution-data-server.enable = pkgs.lib.mkForce false; + gnome-user-share.enable = pkgs.lib.mkForce false; + }; + + services.dbus.socketActivated = true; + + services.openssh.forwardX11 = true; + + programs.ssh.forwardX11 = true; + + sound.enable = true; + + hardware.pulseaudio.enable = true; + + fonts = { + enableCoreFonts = true; + enableFontDir = true; + enableGhostscriptFonts = false; + fontconfig.ultimate.enable = true; + + fonts = with pkgs; [ + cantarell_fonts + dejavu_fonts + dina-font + dosemu_fonts + fira-code + fira-code-symbols + freefont_ttf + liberation_ttf + mplus-outline-fonts + nerdfonts + noto-fonts + noto-fonts-cjk + noto-fonts-emoji + proggyfonts + terminus_font + ubuntu_font_family + ucsFonts + unifont + vistafonts + xlibs.fontadobe100dpi + xlibs.fontadobe75dpi + xlibs.fontadobeutopia100dpi + xlibs.fontadobeutopia75dpi + xlibs.fontadobeutopiatype1 + xlibs.fontarabicmisc + xlibs.fontbh100dpi + xlibs.fontbh75dpi + xlibs.fontbhlucidatypewriter100dpi + xlibs.fontbhlucidatypewriter75dpi + xlibs.fontbhttf + xlibs.fontbhtype1 + xlibs.fontbitstream100dpi + xlibs.fontbitstream75dpi + xlibs.fontbitstreamtype1 + xlibs.fontcronyxcyrillic + xlibs.fontcursormisc + xlibs.fontdaewoomisc + xlibs.fontdecmisc + xlibs.fontibmtype1 + xlibs.fontisasmisc + xlibs.fontjismisc + xlibs.fontmicromisc + xlibs.fontmisccyrillic + xlibs.fontmiscethiopic + xlibs.fontmiscmeltho + xlibs.fontmiscmisc + xlibs.fontmuttmisc + xlibs.fontschumachermisc + xlibs.fontscreencyrillic + xlibs.fontsonymisc + xlibs.fontsunmisc + xlibs.fontwinitzkicyrillic + xlibs.fontxfree86type1 + ]; + }; +} diff --git a/config/fudo/profiles/server.nix b/config/fudo/profiles/server.nix new file mode 100644 index 0000000..70c9271 --- /dev/null +++ b/config/fudo/profiles/server.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: + +{ + environment = { + systemPackages = with pkgs; [ + ]; + + noXlibs = true; + }; + + security = { + hideProcessInformation = true; + }; + + boot.tmpOnTmpfs = true; + + services.xserver.enable = false; + + programs = { + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + + ssh.startAgent = true; + }; +} diff --git a/config/fudo/prometheus.nix b/config/fudo/prometheus.nix new file mode 100644 index 0000000..df8c928 --- /dev/null +++ b/config/fudo/prometheus.nix @@ -0,0 +1,204 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + inherit (lib.strings) concatStringsSep; + cfg = config.fudo.prometheus; + fudo-cfg = config.fudo.common; + +in { + + options.fudo.prometheus = { + enable = mkEnableOption "Fudo Prometheus Data-Gathering Server"; + + service-discovery-dns = mkOption { + type = with types; loaOf (listOf str); + description = '' + A map of exporter type to a list of domains to use for service discovery. + ''; + example = { + node = [ "node._metrics._tcp.my-domain.com" ]; + postfix = [ "postfix._metrics._tcp.my-domain.com" ]; + }; + default = { + dovecot = []; + node = []; + postfix = []; + rspamd = []; + }; + }; + + static-targets = mkOption { + type = with types; loaOf (listOf str); + description = '' + A map of exporter type to a list of host:ports from which to collect metrics. + ''; + example = { + node = [ "my-host.my-domain:1111" ]; + }; + default = { + dovecot = []; + node = []; + postfix = []; + rspamd = []; + }; + }; + + docker-hosts = mkOption { + type = with types; listOf str; + description = '' + A list of explicit docker targets from which to gather node data. + ''; + default = []; + }; + + push-url = mkOption { + type = with types; nullOr str; + description = '' + The that services can use to manually push data. + ''; + default = null; + }; + + push-address = mkOption { + type = with types; nullOr str; + description = '' + The address on which to listen for incoming data. + ''; + default = null; + }; + + hostname = mkOption { + type = with types; str; + description = "The hostname upon which Prometheus will serve."; + example = "my-metrics-server.fudo.org"; + }; + }; + + config = mkIf cfg.enable { + + services.nginx = { + enable = true; + + virtualHosts = { + "${cfg.hostname}" = { + enableACME = true; + forceSSL = true; + + locations."/" = { + proxyPass = "http://127.0.0.1:9090"; + + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-By $server_addr:$server_port; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + + ${optionalString ((length fudo-cfg.local-networks) > 0) + (concatStringsSep "\n" (map (network: "allow ${network};") fudo-cfg.local-networks)) + "\ndeny all;"} + ''; + }; + }; + }; + }; + + services.prometheus = { + + enable = true; + + webExternalUrl = "https://${cfg.hostname}"; + + scrapeConfigs = [ + { + job_name = "docker"; + honor_labels = false; + static_configs = [ + { + targets = cfg.docker-hosts; + } + ]; + } + + { + job_name = "node"; + scheme = "https"; + metrics_path = "/metrics/node"; + honor_labels = false; + dns_sd_configs = [ + { + names = cfg.service-discovery-dns.node; + } + ]; + static_configs = [ + { + targets = cfg.static-targets.node; + } + ]; + } + + { + job_name = "dovecot"; + scheme = "https"; + metrics_path = "/metrics/dovecot"; + honor_labels = false; + dns_sd_configs = [ + { + names = cfg.service-discovery-dns.dovecot; + } + ]; + static_configs = [ + { + targets = cfg.static-targets.dovecot; + } + ]; + } + + { + job_name = "postfix"; + scheme = "https"; + metrics_path = "/metrics/postfix"; + honor_labels = false; + dns_sd_configs = [ + { + names = cfg.service-discovery-dns.postfix; + } + ]; + static_configs = [ + { + targets = cfg.static-targets.postfix; + } + ]; + } + + { + job_name = "rspamd"; + scheme = "https"; + metrics_path = "/metrics/rspamd"; + honor_labels = false; + dns_sd_configs = [ + { + names = cfg.service-discovery-dns.rspamd; + } + ]; + static_configs = [ + { + targets = cfg.static-targets.rspamd; + } + ]; + } + ]; + + pushgateway = { + enable = if (cfg.push-url != null) then true else false; + web = { + external-url = if cfg.push-url == null then + cfg.push-address + else + cfg.push-url; + listen-address = cfg.push-address; + }; + }; + }; + }; +} diff --git a/config/fudo/sites.nix b/config/fudo/sites.nix new file mode 100644 index 0000000..d7e242e --- /dev/null +++ b/config/fudo/sites.nix @@ -0,0 +1,79 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + site = config.fudo.site; + + hostname = config.networking.hostName; + + winnipeg-networks = [ + "208.81.1.128/28" + "208.81.3.112/28" + "192.168.11.1/24" + ]; + + site-configs = { + global-config = { + }; + + winnipeg = global-config // { + time.timeZone = "America/Winnipeg"; + + fudo.common.local-networks = winnipeg-networks; + + services.cron = { + mailto = "admin@fudo.org"; + }; + + networking = { + domain = "fudo.org"; + search = ["fudo.org"]; + firewall.enable = false; + networkmanager.enable = pkgs.lib.mkForce false; + nameservers = [ "1.1.1.1" "208.81.7.14" "2606:4700:4700::1111" ]; + }; + + security.acme.certs."${hostname}" = { + email = "admin@fudo.org"; + + plugins = [ + "fullchain.pem" + "full.pem" + "key.pem" + "chain.pem" + "cert.pem" + ]; + }; + + fudo.node-exporter = { + enable = true; + hostname = hostname; + }; + + nginx = { + enable = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + }; + }; + + nutty-club = winnipeg // { + defaultGateway = "208.81.3.113"; + }; + }; + +in { + options.fudo.site = mkOption { + type = types.enum (attrNames site-configs); + example = "nutty-club"; + description = '' + The site at which this host is located. This will do some site-dependent + configuration. + ''; + default = ""; + }; + + config = optionalAttrs (site-configs ? site) site-configs.${site}; +} diff --git a/config/local.nix b/config/local.nix new file mode 100644 index 0000000..14a1f85 --- /dev/null +++ b/config/local.nix @@ -0,0 +1,21 @@ +{ lib, config, pkgs, ... }: + +with lib; +{ + imports = [ + ./fudo/acme-for-hostname.nix + ./fudo/authentication.nix + ./fudo/common.nix + ./fudo/grafana.nix + ./fudo/kdc.nix + ./fudo/ldap.nix + ./fudo/mail.nix + ./fudo/mail-container.nix + ./fudo/minecraft-server.nix + ./fudo/node-exporter.nix + ./fudo/postgres.nix + ./fudo/profiles.nix + ./fudo/prometheus.nix + ./fudo/sites.nix + ]; +} diff --git a/config/postgresql_11.nix b/config/postgresql_11.nix index ff75b52..e2238cb 100644 --- a/config/postgresql_11.nix +++ b/config/postgresql_11.nix @@ -72,67 +72,4 @@ in { }; }; }; - - # config = mkIf config.fudo.postgresql.enable - - # environment = { - - # systemPackages = with pkgs; [ - # postgresql_11_gssapi - # ]; - - # etc = { - # "postgresql/private/privkey.pem" = { - # mode = "0400"; - # user = "postgres"; - # group = "postgres"; - # source = dataPath + "/certs/private/privkey.pem"; - # }; - - # "postgresql/cert.pem" = { - # mode = "0444"; - # user = "postgres"; - # group = "postgres"; - # source = dataPath + "/certs/cert.pem"; - # }; - - # "postgresql/private/postgres.keytab" = { - # mode = "0400"; - # user = "postgres"; - # group = "postgres"; - # source = dataPath + "/keytabs/postgres.keytab"; - # }; - # }; - # }; - - # services.postgresql = { - # enable = true; - # package = pkgs.postgresql_11_gssapi; - # enableTCPIP = true; - - # extraConfig = '' - # krb_server_keyfile = '/etc/postgresql/private/postgres.keytab' - - # ssl = true - # ssl_cert_file = '/etc/postgresql/cert.pem' - # ssl_key_file = '/etc/postgresql/private/privkey.pem' - # ''; - - # authentication = '' - # local all all ident - - # # host-local - # host all all 127.0.0.1/32 gss include_realm=0 krb_realm=FUDO.ORG - # host all all ::1/128 gss include_realm=0 krb_realm=FUDO.ORG - - # # local network - # host all all 10.0.0.1/24 gss include_realm=0 krb_realm=FUDO.ORG - # host all all 2601:600:997f:fc00::/60 gss include_realm=0 krb_realm=FUDO.ORG - # ''; - - # initialScript = pkgs.writeText "backend-initscript" '' - # ${catLines (map createUserSql fudo.postgresql.users)} - # ${catLines (map createDatabaseSql fudo.postgresql.databases)} - # ''; - # }; } diff --git a/defaults.nix b/defaults.nix index 772758e..121c83b 100644 --- a/defaults.nix +++ b/defaults.nix @@ -5,10 +5,8 @@ { imports = [ ./hardware-configuration.nix - ./packages/postgresql_11_gssapi.nix - ./packages/minecraft-server_1_15_1.nix - ./config/fudo.nix - ./config/postgresql_11.nix + ./packages/local.nix + ./config/local.nix ]; nixpkgs.config.allowUnfree = true; @@ -97,7 +95,6 @@ mosh.enable = true; ssh = { - forwardX11 = true; extraConfig = '' GSSAPIAuthentication yes GSSAPIDelegateCredentials yes @@ -126,7 +123,6 @@ openssh = { enable = true; startWhenNeeded = true; - forwardX11 = true; extraConfig = '' GSSAPIAuthentication yes GSSAPICleanupCredentials yes @@ -146,31 +142,16 @@ }; }; - users.groups = { - fudosys = { - gid = 888; + users.extraUsers = { + node = { + isSystemUser = true; + group = "nogroup"; }; }; - users.ldap = { - enable = true; - base = "dc=fudo,dc=org"; - bind.distinguishedName = "cn=auth_reader,dc=fudo,dc=org"; - bind.passwordFile = "/srv/nslcd/bind.passwd"; - bind.timeLimit = 5; - loginPam = false; - server = "ldap://france.fudo.org"; - timeLimit = 5; - useTLS = true; - extraConfig = '' - TLS_CACERT /etc/nixos/static/fudo_ca.pem - ''; - - daemon = { - enable = true; - extraConfig = '' - tls_cacertfile /etc/nixos/static/fudo_ca.pem - ''; + users.groups = { + fudosys = { + gid = 888; }; }; diff --git a/fudo/alias-users.nix b/fudo/alias-users.nix new file mode 100644 index 0000000..a0bd333 --- /dev/null +++ b/fudo/alias-users.nix @@ -0,0 +1,18 @@ +# A map of email aliases to a list of users (useful for system and bulk aliases) + +let + admin-users = ["reaper@fudo.org" "niten@fudo.org"]; +in { + root = admin-users; + postmaster = admin-users; + + www-data = admin-users; + hostmaster = admin-users; + webmaster = admin-users; + ftp = admin-users; + irc = admin-users; + admin = admin-users; + system = admin-users; + + asdf = ["mswaffer@gmail.com" "bouncetest@fudo.org"]; +} diff --git a/fudo/email.nix b/fudo/email.nix new file mode 100644 index 0000000..bea47a5 --- /dev/null +++ b/fudo/email.nix @@ -0,0 +1,39 @@ +# Fudo email settings +{ config }: + +let + mail-hostname = "france.fudo.org"; + +in { + + domain = "fudo.org"; + + local-domains = [ + "fudo.org" + "mail.fudo.org" + "${config.networking.hostName}" + "selby.ca" + "mail.selby.ca" + "fudo.im" + "mail.fudo.im" + "fudo.ca" + "mail.fudo.ca" + "fudo.link" + "mail.fudo.link" + "selbyhomecentre.com" + "stewartsoundservices.ca" + "rogerwongphoto.com" + ]; + + alias-users = import ./alias-users.nix; + user-aliases = import ./user-aliases.nix; + sender-blacklist = import ./sender-blacklist.nix; + recipient-blacklist = import ./recipient-blacklist.nix; + + trusted-networks = [ + "208.81.1.128/28" + "208.81.3.112/28" + "192.168.11.0/24" + "127.0.0.0/8" + ]; +} diff --git a/fudo/recipient-blacklist.nix b/fudo/recipient-blacklist.nix new file mode 100644 index 0000000..002dda1 --- /dev/null +++ b/fudo/recipient-blacklist.nix @@ -0,0 +1,3 @@ +# Emails for which we won't accept any email. + +[] diff --git a/fudo/sender-blacklist.nix b/fudo/sender-blacklist.nix new file mode 100644 index 0000000..8ca71e0 --- /dev/null +++ b/fudo/sender-blacklist.nix @@ -0,0 +1,7 @@ +# We won't forward email from these addresses, because they were used for +# spamming. Learn2passward! + +[ + "ark@fudo.org" + "theblacksun@fudo.org" +] diff --git a/fudo/system-users.nix b/fudo/system-users.nix index ec57dc4..21830ef 100644 --- a/fudo/system-users.nix +++ b/fudo/system-users.nix @@ -8,4 +8,9 @@ description = "System Authenticator"; hashed-password = "{MD5}N36/kQ64mev1HARddvVk7Q=="; }; + + user_db_reader = { + description = "User Database Reader"; + hashed-password = "{SSHA}IVKhrB+wMOCI/CCzbJW8sNDbH67ZTMBv"; + }; } diff --git a/fudo/user-aliases.nix b/fudo/user-aliases.nix new file mode 100644 index 0000000..05cfb9e --- /dev/null +++ b/fudo/user-aliases.nix @@ -0,0 +1,36 @@ +# A map of user to a list of email aliases (better for users with multiple nicknames) + +{ + "niten@fudo.link" = [ + "ertian@fudo.org" + "peter@fudo.org" + "peter@fudo.link" + "pselby@fudo.org" + "yiliu@fudo.org" + + "peter@selby.ca" + ]; + + "xiaoxuan@fudo.org" = [ + "xixi@fudo.org" + "claire@fudo.org" + + "xixi@selby.ca" + "claire@selby.ca" + ]; + + "reaper@fudo.org" = [ + "cricket@fudo.org" + "jstewart@fudo.org" + "jonathan@fudo.org" + "reaper@fudo.link" + ]; + + "swaff@fudo.org" = [ + "mark@fudo.org" + ]; + + "ken@selby.ca" = [ + "kselby@selby.ca" + ]; +} diff --git a/fudo/users.nix b/fudo/users.nix index 75b7e76..9089b58 100644 --- a/fudo/users.nix +++ b/fudo/users.nix @@ -393,6 +393,14 @@ hashed-password = "{SSHA}DKnhrycmXSu4HKWFPeBXA9xvZ0ytgXIpZA10tg=="; }; + # Used to send alerts from grafana + metrics = { + uid = 10109; + group = "fudo"; + common-name = "Fudo Metrics"; + hashed-password = "{SSHA}FveEVy6kljQZey0xp0nF62SMlO5nATJ1"; + }; + testuser = { uid = 10110; group = "fudo"; diff --git a/hosts/france.nix b/hosts/france.nix index b0e770b..b9657d7 100644 --- a/hosts/france.nix +++ b/hosts/france.nix @@ -1,59 +1,194 @@ -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: +with lib; let hostname = "france.fudo.org"; + mail-hostname = "france.fudo.org"; + host_ipv4 = "208.81.3.117"; + all-hostnames = []; + + acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem"; + acme-certificate = hostname: "/var/lib/acme/${hostname}/fullchain.pem"; + acme-ca = "/etc/nixos/static/letsencryptauthorityx3.pem"; + + fudo-ca = "/etc/nixos/static/fudo_ca.pem"; + + minecraft-data-dir = "/srv/minecraft/data"; + + system-mail-directory = "/srv/mail"; in { - boot.loader.grub.enable = true; - boot.loader.grub.version = 2; - boot.loader.grub.device = "/dev/sda"; - - security.hideProcessInformation = true; + boot.loader.grub = { + enable = true; + version = 2; + device = "/dev/sda"; + }; imports = [ - ../defaults.nix - ../networks/fudo.org.nix - ../profiles/server.nix - ../config/fudo.nix - ../profiles/services/basic_acme.nix - ../profiles/services/heimdal_kdc.nix - ../profiles/services/minecraft.nix ../hardware-configuration.nix - ../packages/local-packages.nix + + ../defaults.nix + + # These should really both be settings... + # ../networks/fudo.org.nix + # ../profiles/server.nix + ]; + + fudo.profile = "server"; + fudo.site = "nutty-club"; + fudo.local-networks = [ + "208.81.1.128/28" + "208.81.3.112/28" + "172.17.0.0/16" + "127.0.0.0/8" ]; environment.systemPackages = with pkgs; [ - acme-ca + docker lxd multipath-tools + nix-prefetch-docker ]; - fudo.auth.server = { + fudo.prometheus = { enable = true; - base = "dc=fudo,dc=org"; - organization = "Fudo"; - rootpw-file = "/srv/ldap/secure/root.pw"; - kerberos-host = "france.fudo.org"; - kerberos-keytab = "/srv/ldap/secure/ldap.keytab"; - - sslCert = "/srv/ldap/france.fudo.org.pem"; - sslKey = "/srv/ldap/secure/france.fudo.org-key.pem"; - sslCACert = "/etc/nixos/static/fudo_ca.pem"; - - listen-uris = [ - "ldap://${hostname}/" - "ldaps://${hostname}/" - "ldap://localhost/" - "ldaps://localhost/" - "ldapi:///" + hostname = "metrics.fudo.org"; + service-discovery-dns = { + node = [ "node._metrics._tcp.fudo.org" ]; + postfix = [ "postfix._metrics._tcp.fudo.org" ]; + dovecot = [ "dovecot._metrics._tcp.fudo.org" ]; + rspamd = [ "rspamd._metrics._tcp.fudo.org" ]; + }; + # Connections will be allowed from these networks. No auth is performed--the + # data is read-only anyway. + trusted-networks = [ + "208.81.1.128/28" + "208.81.3.112/28" + "172.17.0.0/16" + "127.0.0.0/8" ]; + }; - users = import ../fudo/users.nix; + fudo.grafana = { + enable = true; + hostname = "monitor.fudo.org"; + smtp-username = "metrics"; + smtp-password-file = "/srv/grafana/secure/smtp.passwd"; + database-password-file = "/srv/grafana/secure/db.passwd"; + admin-password-file = "/srv/grafana/secure/admin.passwd"; + secret-key-file = "/srv/grafana/secure/secret.key"; + prometheus-host = "metrics.fudo.org"; + }; - groups = import ../fudo/groups.nix; + # So that grafana waits for postgresql + systemd.services.grafana.requires = [ + "postgresql" + ]; - system-users = import ../fudo/system-users.nix; + fudo.postgresql = { + enable = true; + ssl-private-key = (acme-private-key hostname); + ssl-certificate = (acme-certificate hostname); + keytab = "/srv/postgres/secure/postgres.keytab"; + + # We allow connections from local networks. Auth is still required. Outside + # of these networks, no access is allowed. + # + # TODO: that's probably to strict, allow kerberos connections from anywhere. + local-networks = [ + "208.81.1.128/28" + "208.81.3.112/28" + "192.168.11.1/24" + "127.0.0.1/8" + "172.17.0.0/16" + ]; + }; + + # Not all users need access to france; don't allow LDAP-user access. + fudo.authentication.enable = false; + + # But we DO run an LDAP auth server. Should be better-named. + fudo.auth = { + server = { + enable = true; + base = "dc=fudo,dc=org"; + organization = "Fudo"; + rootpw-file = "/srv/ldap/secure/root.pw"; + kerberos-host = "france.fudo.org"; + kerberos-keytab = "/srv/ldap/secure/ldap.keytab"; + + sslCert = "/srv/ldap/france.fudo.org.pem"; + sslKey = "/srv/ldap/secure/france.fudo.org-key.pem"; + sslCACert = fudo-ca; + + # We're using fudo-generated certs for now, but we should move to ACME + # once I can figure out how to correctly produce the ca.pem file. Until + # then, the server will fail to start using these certs. See: + # https://serverfault.com/a/834565 + + # sslCert = (acme-bare-cert hostname); + # sslKey = (acme-private-key hostname); + # sslCACert = acme-ca; + + # TODO: loop over v4 and v6 IPs. + listen-uris = [ + "ldap://${host_ipv4}/" + "ldaps://${host_ipv4}/" + "ldap://localhost/" + "ldaps://localhost/" + "ldapi:///" + ]; + + users = import ../fudo/users.nix; + + groups = import ../fudo/groups.nix; + + system-users = import ../fudo/system-users.nix; + }; + + # Heimdal Kerberos server + kdc = { + enable = true; + database-path = "/var/heimdal/heimdal"; + realm = "FUDO.ORG"; + mkey-file = "/var/heimdal/m-key"; + acl-file = "/etc/heimdal/kdc.acl"; + bind-addresses = [ + host_ipv4 + "127.0.0.1" + "127.0.1.1" + ]; + }; + }; + + # TODO: not used yet + fudo.acme.hostnames = all-hostnames; + + fudo.mail-server = import ../fudo/email.nix { inherit config; } // { + enableContainer = true; + debug = true; + monitoring = true; + + hostname = mail-hostname; + + postfix.ssl-certificate = (acme-certificate mail-hostname); + postfix.ssl-private-key = (acme-private-key mail-hostname); + dovecot.ssl-certificate = (acme-certificate mail-hostname); + dovecot.ssl-private-key = (acme-private-key mail-hostname); + + state-directory = "${system-mail-directory}/var"; + mail-directory = "${system-mail-directory}/mailboxes"; + + dovecot.ldap-reader-dn = "cn=user_db_reader,dc=fudo,dc=org"; + dovecot.ldap-reader-passwd = removeSuffix "\n" (readFile /srv/ldap/secure/user_db.passwd); + + # FIXME: use SSL once I can figure out Acme SSL cert CA for LDAP. + dovecot.ldap-urls = [ "ldap://france.fudo.org" ]; + + clamav.enable = true; + + dkim.signing = true; }; networking = { @@ -64,7 +199,8 @@ in { interfaces.enp4s0f0.useDHCP = true; interfaces.enp4s0f1.useDHCP = true; - enableIPv6 = true; + # TODO: fix IPv6 + enableIPv6 = false; # Create a bridge for VMs to use macvlans = { @@ -84,7 +220,7 @@ in { macAddress = "02:d4:e8:3b:10:2f"; ipv4.addresses = [ { - address = "208.81.3.117"; + address = host_ipv4; prefixLength = 28; } ]; @@ -104,7 +240,82 @@ in { hardware.bluetooth.enable = false; - virtualisation.lxd = { + virtualisation = { + lxd = { + enable = true; + }; + + docker = { + enable = true; + enableOnBoot = true; + + autoPrune = { + enable = true; + }; + }; + }; + + fileSystems = { + "/srv/archiva" = { + fsType = "btrfs"; + options = ["subvol=archiva"]; + label = "pool0"; + }; + "/srv/grafana" = { + fsType = "btrfs"; + options = ["subvol=grafana"]; + label = "pool0"; + }; + "${system-mail-directory}" = { + fsType = "btrfs"; + options = ["subvol=mail"]; + label = "pool0"; + }; + "/srv/gitlab" = { + fsType = "btrfs"; + options = ["subvol=gitlab"]; + label = "pool0"; + }; + }; + + ## + # Archiva + ## + + users.extraUsers = { + archiva = { + isNormalUser = false; + group = "nogroup"; + uid = 1000; + }; + }; + + docker-containers = { + archiva = { + image = "xetusoss/archiva"; + ports = ["127.0.0.1:8091:8080"]; + volumes = [ + "/srv/archiva:/archiva-data" + ]; + environment = { + # Not directly connected to the world anyway + SSL_ENABLED = "false"; + }; + # Ugly as shit: name-to-uid lookup fails. + #user = "1000"; + user = toString config.users.users.archiva.uid; + }; + }; + + ### + # Minecraft + ### + + fudo.minecraft-server = { enable = true; + package = pkgs.minecraft-server_1_15_1; + data-dir = minecraft-data-dir; + world-name = "selbyland"; + motd = "Welcome to the Selby Minecraft server."; }; } diff --git a/hosts/nostromo.nix b/hosts/nostromo.nix index 24e5b64..578b30e 100644 --- a/hosts/nostromo.nix +++ b/hosts/nostromo.nix @@ -1,7 +1,7 @@ { config, pkgs, ... }: let - hostname = "nostromo"; + hostname = "nostromo.sea.fudo.org"; in { @@ -16,11 +16,20 @@ in { ../networks/sea.fudo.org.nix ../profiles/server.nix ../hardware-configuration.nix - - ../profiles/services/postgres.nix # ../profiles/services/local_nameserver.nix ]; + fudo.postgresql = { + enable = true; + ssl-private-key = "/srv/nostromo.sea.fudo.org/certs/private/privkey.pem"; + ssl-certificate = "/srv/nostromo.sea.fudo.org/certs/cert.pem"; + keytab = "/srv/nostromo.sea.fudo.org/keytabs/postgres.keytab"; + + local-networks = [ + "10.0.0.1/24" + ]; + }; + networking = { hostName = hostname; diff --git a/networks/fudo.org.nix b/networks/fudo.org.nix index 96f0666..9b4ba6e 100644 --- a/networks/fudo.org.nix +++ b/networks/fudo.org.nix @@ -1,27 +1,112 @@ -{ config, pkgs, ... }: +{ lib, config, pkgs, ... }: -{ - config.time.timeZone = "America/Winnipeg"; +let + hostname = config.networking.hostName; - config.services.cron = { - mailto = "admin@fudo.org"; + www-root = "/var/www"; + + index = pkgs.writeTextFile { + name = "index.html"; + + text = '' + + + ${hostname} + + +

${hostname} + + + ''; + destination = www-root + ("/" + hostname); }; - config.networking = { - domain = "fudo.org"; +in { - search = ["fudo.org"]; + config = { + time.timeZone = "America/Winnipeg"; - firewall.enable = false; + services.cron = { + mailto = "admin@fudo.org"; + }; - networkmanager.enable = pkgs.lib.mkForce false; + networking = { + domain = "fudo.org"; - defaultGateway = "208.81.3.113"; + search = ["fudo.org"]; - nameservers = [ "1.1.1.1" "208.81.7.14" "2606:4700:4700::1111" ]; - }; + firewall.enable = false; - config.services.prometheus.exporters = { - node.enable = true; + networkmanager.enable = pkgs.lib.mkForce false; + + defaultGateway = "208.81.3.113"; + + nameservers = [ "1.1.1.1" "208.81.7.14" "2606:4700:4700::1111" ]; + }; + + security.acme.certs."${hostname}" = { + email = "admin@fudo.org"; + + plugins = [ + "fullchain.pem" + "full.pem" + "key.pem" + "chain.pem" + "cert.pem" + ]; + }; + + services = { + prometheus.exporters.node = { + enable = true; + enabledCollectors = [ "systemd" ]; + user = "node"; + }; + + nginx = { + enable = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + + virtualHosts = { + + "${hostname}" = { + enableACME = true; + forceSSL = true; + root = www-root + ("/" + hostname); + + listen = [ + { + addr = hostname; + port = 80; + ssl = false; + } + { + addr = hostname; + port = 443; + ssl = true; + } + ]; + + locations."/metrics/node" = { + extraConfig = '' + allow 208.81.1.128/28; + allow 208.81.3.112/28; + allow 127.0.0.0/16; + deny all; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + ''; + # proxy_set_header Host $http_host; + + proxyPass = "http://127.0.0.1:9100/metrics"; + }; + }; + }; + }; + }; }; } diff --git a/packages/acme-ca.nix b/packages/letsencrypt-ca.nix similarity index 80% rename from packages/acme-ca.nix rename to packages/letsencrypt-ca.nix index f4aaca0..c0957e5 100644 --- a/packages/acme-ca.nix +++ b/packages/letsencrypt-ca.nix @@ -1,8 +1,6 @@ { stdenv, fetchurl }: let - # url = "https://letsencrypt.org/certs/isrgrootx1.pem.txt"; - # sha256 = "4c99356c265ee06c0ae0502e74d38231263513726d001cfe28ea25e70af2cc7f"; url = "https://letsencrypt.org/certs/letsencryptauthorityx3.pem.txt"; sha256 = "b6dd03f7fb8508e4f7ffe82ca8a3f98dde163e0bd44897e112a0850a5b606acf"; diff --git a/packages/local-packages.nix b/packages/local-packages.nix deleted file mode 100644 index e93431f..0000000 --- a/packages/local-packages.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, ... }: - -{ - nixpkgs.config.packageOverrides = pkgs: rec { - acme-ca = import ./acme-ca.nix { - stdenv = pkgs.stdenv; - fetchurl = builtins.fetchurl; - }; - }; -} diff --git a/packages/minecraft-server_1_15_1.nix b/packages/local.nix similarity index 55% rename from packages/minecraft-server_1_15_1.nix rename to packages/local.nix index a923bf4..5318f41 100644 --- a/packages/minecraft-server_1_15_1.nix +++ b/packages/local.nix @@ -2,6 +2,11 @@ { nixpkgs.config.packageOverrides = pkgs: rec { + letsencrypt-ca = import ./letsencrypt-ca.nix { + stdenv = pkgs.stdenv; + fetchurl = builtins.fetchurl; + }; + minecraft-server_1_15_1 = pkgs.minecraft-server.overrideAttrs (oldAttrs: rec { version = "1.15.1"; src = builtins.fetchurl { @@ -9,5 +14,10 @@ sha256 = "a0c062686bee5a92d60802ca74d198548481802193a70dda6d5fe7ecb7207993"; }; }); + + postgresql_11_gssapi = pkgs.postgresql_11.overrideAttrs (oldAttrs: rec { + configureFlags = oldAttrs.configureFlags ++ [ "--with-gssapi" ]; + buildInputs = oldAttrs.buildInputs ++ [ pkgs.krb5 ]; + }); }; } diff --git a/packages/options/postgresql_11.nix b/packages/options/postgresql_11.nix deleted file mode 100644 index 51d14c7..0000000 --- a/packages/options/postgresql_11.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - userOpts = { name, config, ... }: { - options = { - passwd = mkOption { - type = types.str; - description = '' - The password of a given user. - ''; - }; - - databases = mkOption { - type = types.listOf types.str; - default = []; - description = '' - A list of databases to which this user should have access. - ''; - }; - }; - }; - -in { - - options = { - fudo.postgresql = { - databases = mkOption { - type = types.attrsOf types.lines; - default = {}; - description = '' - A map of database_name => database_defn. - ''; - }; - users = mkOption { - type = with types; attrsOf (submodule userOpts); - default = {}; - description = '' - A map of user_name => { user_attributes }. - ''; - }; - }; - }; -} diff --git a/packages/postgresql_11_gssapi.nix b/packages/postgresql_11_gssapi.nix deleted file mode 100644 index 12700ea..0000000 --- a/packages/postgresql_11_gssapi.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, ... }: - -{ - nixpkgs.config.packageOverrides = pkgs: rec { - postgresql_11_gssapi = pkgs.postgresql_11.overrideAttrs (oldAttrs: rec { - configureFlags = oldAttrs.configureFlags ++ [ "--with-gssapi" ]; - buildInputs = oldAttrs.buildInputs ++ [ pkgs.krb5 ]; - }); - }; -} diff --git a/profiles/desktop.nix b/profiles/desktop.nix index 3b28702..445d47d 100644 --- a/profiles/desktop.nix +++ b/profiles/desktop.nix @@ -77,6 +77,10 @@ services.dbus.socketActivated = true; + services.openssh.forwardX11 = true; + + programs.ssh.forwardX11 = true; + sound.enable = true; hardware.pulseaudio.enable = true; diff --git a/profiles/server.nix b/profiles/server.nix index 8dfc03c..cb3ff2c 100644 --- a/profiles/server.nix +++ b/profiles/server.nix @@ -1,8 +1,14 @@ { config, pkgs, ... }: { - environment.systemPackages = with pkgs; [ - ]; + environment = { + systemPackages = with pkgs; [ + ]; + + noXlibs = true; + }; + + security.hideProcessInformation = true; boot.tmpOnTmpfs = true; diff --git a/profiles/services/heimdal_kdc.nix b/profiles/services/heimdal_kdc.nix deleted file mode 100644 index 4f9d46b..0000000 --- a/profiles/services/heimdal_kdc.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ config, pkgs, environment, ... }: - -let - databasePath = /var/heimdal/heimdal; - -in { - environment = { - systemPackages = with pkgs; [ - heimdalFull - ]; - }; - - systemd.services = { - heimdal-kdc = { - enable = true; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - description = "Heimdal Kerberos Key Distribution Center (ticket server)"; - serviceConfig = { - ExecStart = ''${pkgs.heimdalFull}/libexec/heimdal/kdc''; - }; - }; - - heimdal-admin-server = { - enable = true; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - description = "Heimdal Kerberos Remote Administration Server"; - serviceConfig = { - ExecStart = ''${pkgs.heimdalFull}/libexec/heimdal/kadmind''; - }; - }; - }; -} diff --git a/profiles/services/minecraft.nix b/profiles/services/minecraft.nix deleted file mode 100644 index 47ba6c1..0000000 --- a/profiles/services/minecraft.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ pkgs, ... }: - -let - dataDir = /srv/minecraft/data; -in { - services.minecraft-server = { - enable = true; - package = pkgs.minecraft-server_1_15_1; - dataDir = dataDir; - eula = true; - declarative = true; - serverProperties = { - level-name = "selbyland"; - motd = "Welcome to the Selby Minecraft Server"; - difficulty = 2; - gamemode = "survival"; - }; - }; -} diff --git a/profiles/services/postgres.nix b/profiles/services/postgres.nix deleted file mode 100644 index d097882..0000000 --- a/profiles/services/postgres.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ config, pkgs, environment, ... }: - -let - dataPath = /srv + ("/" + config.networking.hostName); - -in { - - environment = { - - systemPackages = with pkgs; [ - postgresql_11_gssapi - ]; - - etc = { - "postgresql/private/privkey.pem" = { - mode = "0400"; - user = "postgres"; - group = "postgres"; - source = dataPath + "/certs/private/privkey.pem"; - }; - - "postgresql/cert.pem" = { - mode = "0444"; - user = "postgres"; - group = "postgres"; - source = dataPath + "/certs/cert.pem"; - }; - - "postgresql/private/postgres.keytab" = { - mode = "0400"; - user = "postgres"; - group = "postgres"; - source = dataPath + "/keytabs/postgres.keytab"; - }; - }; - }; -< - services.postgresql = { - enable = true; - package = pkgs.postgresql_11_gssapi; - enableTCPIP = true; - - extraConfig = - '' - krb_server_keyfile = '/etc/postgresql/private/postgres.keytab' - - ssl = true - ssl_cert_file = '/etc/postgresql/cert.pem' - ssl_key_file = '/etc/postgresql/private/privkey.pem' - ''; - - authentication = - '' - local all all ident - - # host-local - host all all 127.0.0.1/32 gss include_realm=0 krb_realm=FUDO.ORG - host all all ::1/128 gss include_realm=0 krb_realm=FUDO.ORG - - # local network - host all all 10.0.0.1/24 gss include_realm=0 krb_realm=FUDO.ORG - host all all 2601:600:997f:fc00::/60 gss include_realm=0 krb_realm=FUDO.ORG - ''; - }; -} diff --git a/static/fudo_ca.pem b/static/fudo_ca.pem index cddc528..60637eb 100644 --- a/static/fudo_ca.pem +++ b/static/fudo_ca.pem @@ -1,23 +1,17 @@ -----BEGIN CERTIFICATE----- -MIIDvzCCAyigAwIBAgIJAIO7c/KlNXiJMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD -VQQGEwJDQTERMA8GA1UECBMITWFuaXRvYmExETAPBgNVBAcTCFdpbm5pcGVnMREw -DwYDVQQKEwhGdWRvLm9yZzERMA8GA1UECxMIU2VjdXJpdHkxIjAgBgNVBAMTGUZ1 -ZG8ub3JnIFJvb3QgQ2VydGlmaWNhdGUxHTAbBgkqhkiG9w0BCQEWDmFkbWluQGZ1 -ZG8ub3JnMB4XDTA2MTIyMjIyMTYxMVoXDTE2MTIxOTIyMTYxMVowgZwxCzAJBgNV -BAYTAkNBMREwDwYDVQQIEwhNYW5pdG9iYTERMA8GA1UEBxMIV2lubmlwZWcxETAP -BgNVBAoTCEZ1ZG8ub3JnMREwDwYDVQQLEwhTZWN1cml0eTEiMCAGA1UEAxMZRnVk -by5vcmcgUm9vdCBDZXJ0aWZpY2F0ZTEdMBsGCSqGSIb3DQEJARYOYWRtaW5AZnVk -by5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANZpJiFZjgs1M744PTLH -nAQVMC2VzH76+qNbLClNK3n6dknrx+FMFq35naXnJLnkmEhHW5DFMeQBudCAD1tv -DTj6KxgBbBoMFIXfukQjMOjFIXcPE0MsbfJowjJxGDA3KFE5pLs5u5suGPLXPpog -6ASSTg1n75crFSU/d9hN+drVAgMBAAGjggEFMIIBATAdBgNVHQ4EFgQUQS8uOVCa -rLmMGYU6T0pIkDAnQr8wgdEGA1UdIwSByTCBxoAUQS8uOVCarLmMGYU6T0pIkDAn -Qr+hgaKkgZ8wgZwxCzAJBgNVBAYTAkNBMREwDwYDVQQIEwhNYW5pdG9iYTERMA8G -A1UEBxMIV2lubmlwZWcxETAPBgNVBAoTCEZ1ZG8ub3JnMREwDwYDVQQLEwhTZWN1 -cml0eTEiMCAGA1UEAxMZRnVkby5vcmcgUm9vdCBDZXJ0aWZpY2F0ZTEdMBsGCSqG -SIb3DQEJARYOYWRtaW5AZnVkby5vcmeCCQCDu3PypTV4iTAMBgNVHRMEBTADAQH/ -MA0GCSqGSIb3DQEBBQUAA4GBAH2ZUJoSeNcslGlQUs7xPWwTSKVZ0OGpfhdI/pmA -WQGC6Kj5MzlEunqaBEKaLSJ9yx/t0l5c5aFT77ERFacH0lhWme+AACEDAKuCbMeL -fRnsQYoPZ0jEygnxvdG4IHl9dmKWr9SR361OWOP0uYpvWtiuF5w0GvFLJ0L5x7jy -xZuP +MIICqTCCAhICCQD6IEI142ZdAjANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMC +Q0ExETAPBgNVBAgMCE1hbml0b2JhMREwDwYDVQQHDAhXaW5uaXBlZzERMA8GA1UE +CgwIRnVkby5vcmcxHjAcBgNVBAsMFVNlY3VyaXR5ICYgRW5jcnlwdGlvbjERMA8G +A1UEAwwIZnVkby5vcmcxHTAbBgkqhkiG9w0BCQEWDmFkbWluQGZ1ZG8ub3JnMB4X +DTIwMDEwNzIzMzA0NFoXDTQ5MTIzMDIzMzA0NFowgZgxCzAJBgNVBAYTAkNBMREw +DwYDVQQIDAhNYW5pdG9iYTERMA8GA1UEBwwIV2lubmlwZWcxETAPBgNVBAoMCEZ1 +ZG8ub3JnMR4wHAYDVQQLDBVTZWN1cml0eSAmIEVuY3J5cHRpb24xETAPBgNVBAMM +CGZ1ZG8ub3JnMR0wGwYJKoZIhvcNAQkBFg5hZG1pbkBmdWRvLm9yZzCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEA1mkmIVmOCzUzvjg9MsecBBUwLZXMfvr6o1ss +KU0refp2SevH4UwWrfmdpeckueSYSEdbkMUx5AG50IAPW28NOPorGAFsGgwUhd+6 +RCMw6MUhdw8TQyxt8mjCMnEYMDcoUTmkuzm7my4Y8tc+miDoBJJODWfvlysVJT93 +2E352tUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQA4SLrx3nJfHrq/AJmemzw+IZoc +WWERdSIMzCwM7iYSlp0dV0muAlm+QasOif9ZIDQF7Sl41DP6kznQO1VLVH4MBL0w +67qJzmuXDO2nj959YxsblDHrP4vTR/Am2aBejTFTEgYHqVgiZA+mHzd6YuJgDc/8 +x61QIkPH0uK79dit/w== -----END CERTIFICATE----- diff --git a/static/letsencryptauthorityx3.pem b/static/letsencryptauthorityx3.pem new file mode 100644 index 0000000..5decaec --- /dev/null +++ b/static/letsencryptauthorityx3.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1 +WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX +NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf +89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl +Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc +Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz +uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB +AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU +BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB +FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo +SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js +LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF +BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG +AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD +VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB +ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx +A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM +UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2 +DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1 +eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu +OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw +p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY +2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0 +ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR +PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b +rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt +-----END CERTIFICATE-----