Informis.land is functioning again.

This commit is contained in:
root@procul 2021-04-14 13:05:55 -05:00
parent 7e6c08b1ec
commit 145996cf38
10 changed files with 480 additions and 88 deletions

View File

@ -0,0 +1,229 @@
{ config, lib, pkgs, ... }:
with lib;
let
hostname = "procul";
host-ipv4 = "172.86.179.18";
domain = config.fudo.hosts.${hostname}.domain;
site = config.fudo.hosts.${hostname}.site;
host-fqdn = "${hostname}.${domain}";
local-networks = config.fudo.domains.${domain}.local-networks
++ config.fudo.sites.${site}.local-networks;
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";
local-packages = with pkgs; [ ldns.examples ];
in {
networking = {
dhcpcd.enable = false;
useDHCP = false;
enableIPv6 = true;
# FIXME: this isn't the right place
search = [ domain ];
nameservers = [ "127.0.0.1" ];
defaultGateway = "172.86.179.17";
interfaces = {
extif0 = {
ipv4.addresses = [{
address = host-ipv4;
prefixLength = 29;
}];
};
};
};
environment.systemPackages = local-packages;
networking.firewall.allowedTCPPorts = [ 80 443 ];
users.users = {
gituser = {
isSystemUser = true;
group = "nogroup";
};
};
fudo = {
client.dns = {
enable = true;
ipv4 = true;
ipv6 = true;
user = "fudo-client";
external-interface = "extif0";
password-file = "/srv/client/secure/client.passwd";
};
auth.kdc = {
enable = true;
realm = "INFORMIS.LAND";
bind-addresses = [ host-ipv4 "127.0.0.1" ];
acl = {
"niten" = { perms = [ "add" "change-password" "list" ]; };
"*/root" = { perms = [ "all" ]; };
};
};
secure-dns-proxy = {
enable = true;
upstream-dns =
[ "https://1.1.1.1/dns-query" "https://1.0.0.1/dns-query" ];
bootstrap-dns = "1.1.1.1";
listen-ips = [ "127.0.0.1" ];
listen-port = 53;
allowed-networks = [ "1.1.1.1/32" "1.0.0.1/32" "localhost" "link-local" ];
};
# networks."informis.land" = {
# hosts = {
# procul = {
# ipv4-address = host-ipv4;
# };
# };
# verbatim-dns-records = [
# ''_kerberos IN TXT "INFORMIS.LAND"''
# ''@ IN TXT "v=spf1 mx ip4:${host-ipv4}/29 -all"''
# ''@ IN SPF "v=spf1 mx ip4:${host-ipv4}/29 -all"''
# ];
# };
dns = {
enable = true;
identity = "procul.informis.land";
nameservers = {
ns1 = {
ipv4-address = host-ipv4;
description = "Primary Informis Nameserver";
};
ns2 = {
ipv4-address = host-ipv4;
description = "Secondary Informis Nameserver";
};
};
listen-ips = [ host-ipv4 ];
domains = {
"informis.land" = {
dnssec = true;
default-host = host-ipv4;
gssapi-realm = "INFORMIS.LAND";
mx = [ "smtp.informis.land" ];
network-definition = config.fudo.networks."informis.land";
dmarc-report-address = "dmarc-report@informis.land";
};
};
};
mail-server = {
enable = true;
debug = true;
domain = domain;
hostname = "${host-fqdn}";
monitoring = false;
mail-user = "mailuser";
mail-user-id = 525;
mail-group = "mailgroup";
clamav.enable = true;
dkim.signing = true;
dovecot = {
ssl-certificate = acme-certificate "imap.${domain}";
ssl-private-key = acme-private-key "imap.${domain}";
};
postfix = {
ssl-certificate = acme-certificate "smtp.${domain}";
ssl-private-key = acme-private-key "smtp.${domain}";
};
# This should NOT include the primary domain
local-domains = [
host-fqdn
"smtp.${domain}"
];
mail-directory = "/srv/mailserver/mail";
state-directory = "/srv/mailserver/state";
trusted-networks = [
"172.86.179.16/29"
"127.0.0.0/16"
];
alias-users = {
root = ["niten"];
postmaster = ["niten"];
hostmaster = ["niten"];
webmaster = ["niten"];
system = ["niten"];
admin = ["niten"];
dmarc-report = ["niten"];
};
};
postgresql = {
enable = true;
ssl-certificate = (acme-certificate host-fqdn);
ssl-private-key = (acme-private-key host-fqdn);
keytab = "/srv/postgres/secure/postgres.keytab";
local-networks = local-networks;
users = {
gituser = {
password-file = "/srv/git/secure/db.passwd";
databases = {
git = {
access = "CONNECT";
entity-access = {
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
"ALL SEQUENCES IN SCHEMA public" = "SELECT, UPDATE";
};
};
};
};
};
databases = { git = { users = [ "niten" ]; }; };
};
git = {
enable = true;
hostname = "git.informis.land";
site-name = "informis git";
user = "gituser";
# admin-email = "viator@informis.land";
repository-dir = /srv/git/repo;
state-dir = /srv/git/state;
database = {
user = "gituser";
password-file = /srv/git/secure/db.passwd;
hostname = "127.0.0.1";
name = "git";
};
ssh = {
listen-ip = host-ipv4;
listen-port = 2222;
};
};
acme = {
enable = true;
admin-address = "admin@${domain}";
hostnames = [
"informis.land"
"imap.informis.land"
"smtp.informis.land"
"gemini.informis.land"
];
};
};
}

View File

@ -4,5 +4,6 @@
config.fudo.networks = { config.fudo.networks = {
"rus.selby.ca" = import ./networks/rus.selby.ca.nix { inherit config lib; }; "rus.selby.ca" = import ./networks/rus.selby.ca.nix { inherit config lib; };
"sea.fudo.org" = import ./networks/sea.fudo.org.nix { inherit config lib; }; "sea.fudo.org" = import ./networks/sea.fudo.org.nix { inherit config lib; };
"informis.land" = import ./networks/informis.land.nix { inherit config lib; };
}; };
} }

View File

@ -0,0 +1,91 @@
{ config, lib, ... }:
with lib;
{
mx = [ "smtp.informis.land" ];
aliases = {
smtp = "procul.informis.land.";
imap = "procul.informis.land.";
gemini = "procul.informis.land.";
git = "procul.informis.land.";
};
verbatim-dns-records = let
domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
# NOTE: we're assuming IPv4...
domain-local-nets = map (network: "ip4:${network}") config.fudo.domains.${domain-name}.local-networks;
local-net-string = concatStringsSep " " domain-local-nets;
in [
''@ IN TXT "v=spf1 mx ${local-net-string} -all"''
''@ IN SPF "v=spf1 mx ${local-net-string} -all"''
];
srv-records = {
tcp = {
domain = [{
host = "ns1.informis.land";
port = 53;
}];
ssh = [{
host = "procul.informis.land";
port = 22;
}];
submission = [{
host = "procul.informis.land";
port = 587;
}];
kerberos = [{
host = "procul.informis.land";
port = 88;
}];
kerberos-adm = [{
host = "procul.informis.land";
port = 749;
}];
imaps = [{
host = "procul.informis.land";
port = 993;
priority = 0;
}];
pop3s = [{
host = "procul.informis.land";
port = 995;
priority = 10;
}];
http = [{
host = "procul.informis.land";
port = 80;
}];
https = [{
host = "procul.informis.land";
port = 443;
}];
};
udp = {
domain = [{
host = "ns1.informis.land";
port = 53;
}];
kerberos = [{
host = "procul.informis.land";
port = 88;
}];
kerberos-master = [{
host = "procul.informis.land";
port = 88;
}];
kpasswd = [{
host = "procul.informis.land";
port = 464;
}];
};
};
hosts = {
procul = {
ipv4-address = "172.86.179.18";
};
};
}

View File

@ -26,18 +26,42 @@ let
type = submodule (import ../types/network-definition.nix); type = submodule (import ../types/network-definition.nix);
description = "Definition of network to be served by local server."; description = "Definition of network to be served by local server.";
}; };
default-host = mkOption {
type = str;
description = "The host to which the domain should map by default.";
};
mx = mkOption {
type = listOf str;
description = "The hosts which act as the domain mail exchange.";
default = [];
};
gssapi-realm = mkOption {
type = nullOr str;
description = "The GSSAPI realm of this domain.";
default = null;
};
}; };
}; };
hostRecords = host: data: networkHostOpts = import ../types/network-host.nix { inherit lib; };
join-lines
((optional (data.ipv4-address != null) "${host} IN A ${data.ipv4-address}") hostRecords = hostname: nethost-data: let
++ (optional (data.ipv6-address != null) # FIXME: RP doesn't work.
"${host} IN AAAA ${data.ipv6-address}") # generic-host-records = let
++ (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints) # host-data = if (hasAttr hostname config.fudo.hosts) then config.fudo.hosts.${hostname} else null;
++ (optional (data.rp != null) "${host} IN RP ${data.rp}") # in
++ (optional (data.description != null) # if (host-data == null) then [] else (
"${host} IN TXT ${data.description}")); # (map (sshfp: "${hostname} IN SSHFP ${sshfp}") host-data.ssh-fingerprints) ++ (optional (host-data.rp != null) "${hostname} IN RP ${host-data.rp}")
# );
sshfp-records = if (hasAttr hostname config.fudo.hosts) then (map (sshfp: "${hostname} IN SSHFP ${sshfp}") config.fudo.hosts.${hostname}.ssh-fingerprints) else [];
a-record = optional (nethost-data.ipv4-address != null) "${hostname} IN A ${nethost-data.ipv4-address}";
aaaa-record = optional (nethost-data.ipv6-address != null) "${hostname} IN AAAA ${nethost-data.ipv6-address}";
description-record = optional (nethost-data.description != null) "${hostname} IN TXT \"${nethost-data.description}\"";
in
join-lines (a-record ++ aaaa-record ++ description-record ++ sshfp-records);
makeSrvRecords = protocol: type: records: makeSrvRecords = protocol: type: records:
join-lines (map (record: join-lines (map (record:
@ -67,12 +91,11 @@ in {
# FIXME: This should allow for AAAA addresses too... # FIXME: This should allow for AAAA addresses too...
nameservers = mkOption { nameservers = mkOption {
type = attrsOf (submodule hostOpts); type = attrsOf (submodule networkHostOpts);
description = "Map of domain nameserver FQDNs to IP."; description = "Map of domain nameserver FQDNs to IP.";
example = { example = {
"ns1.domain.com" = { "ns1.domain.com" = {
ip-addresses = [ "1.1.1.1" ]; ipv4-address = "1.1.1.1";
ipv6-addresses = [ ];
description = "my fancy dns server"; description = "my fancy dns server";
}; };
}; };
@ -101,8 +124,9 @@ in {
enable = true; enable = true;
identity = cfg.identity; identity = cfg.identity;
interfaces = cfg.listen-ips; interfaces = cfg.listen-ips;
zones = mapAttrs' (dom: dom-cfg: zones = mapAttrs' (dom: dom-cfg: let
nameValuePair "${dom}." { net-cfg = dom-cfg.network-definition;
in nameValuePair "${dom}." {
dnssec = dom-cfg.dnssec; dnssec = dom-cfg.dnssec;
data = '' data = ''
@ -132,10 +156,10 @@ in {
${dmarcRecord dom-cfg.dmarc-report-address} ${dmarcRecord dom-cfg.dmarc-report-address}
${join-lines ${join-lines
(mapAttrsToList makeSrvProtocolRecords dom-cfg.srv-records)} (mapAttrsToList makeSrvProtocolRecords net-cfg.srv-records)}
${join-lines (mapAttrsToList hostRecords dom-cfg.hosts)} ${join-lines (mapAttrsToList hostRecords net-cfg.hosts)}
${join-lines (mapAttrsToList cnameRecord dom-cfg.aliases)} ${join-lines (mapAttrsToList cnameRecord net-cfg.aliases)}
${join-lines dom-cfg.extra-dns-records} ${join-lines net-cfg.verbatim-dns-records}
''; '';
}) cfg.domains; }) cfg.domains;
}; };

View File

@ -93,7 +93,9 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
security.acme.certs.${cfg.hostname}.email = config.fudo.common.admin-email; security.acme.certs.${cfg.hostname}.email = let
domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
in config.fudo.domains.${domain-name}.admin-email;
services = { services = {
gitea = { gitea = {
@ -114,14 +116,19 @@ in {
stateDir = toString cfg.state-dir; stateDir = toString cfg.state-dir;
rootUrl = "https://${cfg.hostname}/"; rootUrl = "https://${cfg.hostname}/";
user = mkIf (cfg.user != null) cfg.user; user = mkIf (cfg.user != null) cfg.user;
extraConfig = mkIf (cfg.ssh != null) '' ssh = {
[server] enable = true;
START_SSH_SERVER = true clonePort = cfg.ssh.listen-port;
SSH_DOMAIN = ${cfg.hostname} };
SSH_PORT = ${toString cfg.ssh.listen-port} # settings = mkIf (cfg.ssh != null) {
SSH_LISTEN_PORT = ${toString cfg.ssh.listen-port} # server = {
SSH_LISTEN_HOST = ${cfg.ssh.listen-ip} # START_SSH_SERVER = true;
''; # SSH_DOMAIN = cfg.hostname;
# SSH_PORT = cfg.ssh.listen-port;
# SSH_LISTEN_PORT = cfg.ssh.listen-port;
# SSH_LISTEN_HOST = cfg.ssh.listen-ip;
# };
# };
}; };
nginx = { nginx = {

View File

@ -124,28 +124,35 @@ in {
Depending on the mail client used it might be necessary to change some mailbox's name. Depending on the mail client used it might be necessary to change some mailbox's name.
''; '';
default = [ default = {
{ Trash = {
name = "Trash"; auto = "create";
auto = "no";
specialUse = "Trash"; specialUse = "Trash";
} autoexpunge = "30d";
{ };
name = "Junk"; Junk = {
auto = "subscribe"; auto = "create";
specialUse = "Junk"; specialUse = "Junk";
} autoexpunge = "60d";
{ };
name = "Drafts"; Drafts = {
auto = "subscribe"; auto = "create";
specialUse = "Drafts"; specialUse = "Drafts";
} autoexpunge = "60d";
{ };
name = "Sent"; Sent = {
auto = "subscribe"; auto = "subscribe";
specialUse = "Sent"; specialUse = "Sent";
} };
]; Archive = {
auto = "no";
specialUse = "Archive";
};
Flagged = {
auto = "no";
specialUse = "Flagged";
};
};
}; };
debug = mkOption { debug = mkOption {

View File

@ -245,17 +245,17 @@ in {
ensurePermissions = { "DATABASE ${database}" = "ALL PRIVILEGES"; }; ensurePermissions = { "DATABASE ${database}" = "ALL PRIVILEGES"; };
}) opts.users)) cfg.databases))); }) opts.users)) cfg.databases)));
extraConfig = '' settings = {
krb_server_keyfile = '/etc/postgresql/private/postgres.keytab' krb_server_keyfile = "/etc/postgresql/private/postgres.keytab";
ssl = true ssl = true;
ssl_cert_file = '/etc/postgresql/cert.pem' ssl_cert_file = "/etc/postgresql/cert.pem";
ssl_key_file = '/etc/postgresql/private/privkey.pem' ssl_key_file = "/etc/postgresql/private/privkey.pem";
unix_socket_directories = '${cfg.socket-directory}' unix_socket_directories = cfg.socket-directory;
unix_socket_group = '${cfg.socket-group}' unix_socket_group = cfg.socket-group;
unix_socket_permissions = 0777 unix_socket_permissions = "0777";
''; };
authentication = lib.mkForce '' authentication = lib.mkForce ''
${makeLocalUserPasswordEntries cfg.users} ${makeLocalUserPasswordEntries cfg.users}
@ -318,7 +318,7 @@ in {
${usersAccessSql cfg.users} ${usersAccessSql cfg.users}
''; '';
in '' in ''
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${pkgs.postgresql}/bin/psql --port ${ ${pkgs.postgresql}/bin/psql --port ${
toString config.services.postgresql.port toString config.services.postgresql.port
} -d postgres -f ${extra-settings-sql} } -d postgres -f ${extra-settings-sql}
${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL* ${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*

View File

@ -46,20 +46,49 @@ in {
"List of networks with which this job is allowed to communicate."; "List of networks with which this job is allowed to communicate.";
default = null; default = null;
}; };
user = mkOption {
type = str;
description = "User as which to run secure DNS proxy.";
default = "secure-dns-proxy";
}; };
config = mkIf cfg.enable { group = mkOption {
environment.systemPackages = with pkgs; [ dnsproxy ]; type = str;
description = "Group as which to run secure DNS proxy.";
default = "secure-dns-proxy";
};
};
config = mkIf cfg.enable (let
upgrade-perms = cfg.listen-port <= 1024;
in {
users = mkIf upgrade-perms {
users = {
${cfg.user} = {
isSystemUser = true;
group = cfg.group;
};
};
groups = {
${cfg.group} = {
members = [ cfg.user ];
};
};
};
fudo.system.services.secure-dns-proxy = { fudo.system.services.secure-dns-proxy = {
description = "DNS Proxy for secure DNS-over-HTTPS lookups."; description = "DNS Proxy for secure DNS-over-HTTPS lookups.";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
after = [ "network.target" ]; after = [ "network.target" ];
privateNetwork = false; privateNetwork = false;
requiredCapabilities = [ ]; requiredCapabilities = mkIf upgrade-perms [ "CAP_NET_BIND_SERVICE" ];
restartWhen = "always"; restartWhen = "always";
addressFamilies = [ "AF_INET" "AF_INET6" ]; addressFamilies = [ "AF_INET" "AF_INET6" ];
networkWhitelist = cfg.allowed-networks; networkWhitelist = cfg.allowed-networks;
user = mkIf upgrade-perms cfg.user;
group = mkIf upgrade-perms cfg.group;
execStart = let execStart = let
upstreams = map (upstream: "-u ${upstream}") cfg.upstream-dns; upstreams = map (upstream: "-u ${upstream}") cfg.upstream-dns;
@ -70,5 +99,5 @@ in {
toString cfg.listen-port toString cfg.listen-port
} ${upstream-line} ${listen-line} -b ${cfg.bootstrap-dns}"; } ${upstream-line} ${listen-line} -b ${cfg.bootstrap-dns}";
}; };
}; });
} }

View File

@ -31,35 +31,7 @@ let
}; };
}; };
networkHostOpts = { hostname, ... }: { networkHostOpts = import ./network-host.nix { inherit lib; };
options = with types; {
hostname = mkOption {
type = str;
description =
"Hostname (which may map to a host in config.fudo.hosts).";
default = hostname;
};
ipv4-address = mkOption {
type = nullOr str;
description = "The V4 IP of a given host, if any.";
default = null;
};
ipv6-address = mkOption {
type = nullOr str;
description = "The V6 IP of a given host, if any.";
default = null;
};
mac-address = mkOption {
type = nullOr types.str;
description =
"The MAC address of a given host, if desired for IP reservation.";
default = null;
};
};
};
in { in {
options = with types; { options = with types; {

View File

@ -0,0 +1,32 @@
{ lib, ... }:
{ hostname, ... }:
with lib;
{
options = with types; {
ipv4-address = mkOption {
type = nullOr str;
description = "The V4 IP of a given host, if any.";
default = null;
};
ipv6-address = mkOption {
type = nullOr str;
description = "The V6 IP of a given host, if any.";
default = null;
};
mac-address = mkOption {
type = nullOr types.str;
description =
"The MAC address of a given host, if desired for IP reservation.";
default = null;
};
description = mkOption {
type = nullOr str;
description = "Description of the host.";
default = null;
};
};
}