merge with upstream

This commit is contained in:
nostoromo root 2020-07-16 14:09:50 -07:00
commit 05b2b69b3c
16 changed files with 969 additions and 134 deletions

View File

@ -6,26 +6,28 @@ with lib;
let let
cfg = config.fudo.acme; cfg = config.fudo.acme;
wwwRoot = hostname: # wwwRoot = hostname:
pkgs.writeTextFile { # pkgs.writeTextFile {
name = "index.html"; # name = "index.html";
text = '' # text = ''
<html> # <html>
<head> # <head>
<title>${hostname}</title> # <title>${hostname}</title>
</head> # </head>
<body> # <body>
<h1>${hostname}</title> # <h1>${hostname}</title>
</body> # </body>
</html> # </html>
''; # '';
destination = "/www"; # destination = "/www";
}; # };
in { in {
options.fudo.acme = { options.fudo.acme = {
enable = mkEnableOption "Fetch ACME certs for supplied local hostnames.";
hostnames = mkOption { hostnames = mkOption {
type = with types; listOf str; type = with types; listOf str;
description = "A list of hostnames mapping to this host, for which to acquire SSL certificates."; description = "A list of hostnames mapping to this host, for which to acquire SSL certificates.";
@ -35,9 +37,15 @@ in {
"alt.hostname.com" "alt.hostname.com"
]; ];
}; };
admin-address = mkOption {
type = types.str;
description = "The admin address in charge of these addresses.";
default = "admin@fudo.org";
};
}; };
config = { config = mkIf cfg.enable {
services.nginx = { services.nginx = {
enable = true; enable = true;
@ -49,13 +57,13 @@ in {
{ {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
root = (wwwRoot hostname) + ("/" + "www"); # root = (wwwRoot hostname) + ("/" + "www");
}) })
cfg.hostnames); cfg.hostnames);
}; };
security.acme.certs = listToAttrs security.acme.certs = listToAttrs
(map (hostname: nameValuePair hostname { email = "admin@fudo.org"; }) (map (hostname: nameValuePair hostname { email = cfg.admin-address; })
cfg.hostnames); cfg.hostnames);
}; };
} }

218
config/fudo/dns.nix Normal file
View File

@ -0,0 +1,218 @@
{ lib, config, pkgs, ... }:
with lib;
let
cfg = config.fudo.dns;
ip = import ../../lib/ip.nix { lib = lib; };
join-lines = concatStringsSep "\n";
hostOpts = { host, ...}: {
options = {
ip-addresses = mkOption {
type = with types; listOf str;
description = ''
A list of IPv4 addresses assigned to this host.
'';
default = [];
};
ipv6-addresses = mkOption {
type = with types; listOf str;
description = ''
A list of IPv6 addresses assigned to this host.
'';
default = [];
};
ssh-fingerprints = mkOption {
type = with types; listOf str;
description = ''
A list of DNS SSHFP records for this host.
'';
};
};
};
srvRecordOpts = with types; {
options = {
weight = mkOption {
type = int;
description = "Weight relative to other records.";
default = 1;
};
priority = mkOption {
type = int;
description = "Priority to give this record.";
default = 0;
};
port = mkOption {
type = port;
description = "Port to use while connecting to this service.";
};
host = mkOption {
type = str;
description = "Host that provides this service.";
example = "my-host.my-domain.com";
};
};
};
domainOpts = { domain, ... }: with types; {
options = {
hosts = mkOption {
type = loaOf (submodule hostOpts);
default = {};
description = "A map of hostname to { host_attributes }.";
};
dnssec = mkEnableOption "Enable DNSSEC security for this zone.";
mx = mkOption {
type = listOf str;
description = "A list of mail servers serving this domain.";
default = [];
};
srv-records = mkOption {
type = attrsOf (attrsOf (listOf (submodule srvRecordOpts)));
description = "Map of traffic type to srv records.";
default = {};
example = {
tcp = {
kerberos = {
port = 88;
host = "auth-host.my-domain.com";
};
};
};
};
aliases = mkOption {
type = loaOf str;
default = {};
description = "A mapping of host-alias => hostnames to add to DNS.";
example = {
"music" = "host.dom.com.";
"mail" = "hostname";
};
};
extra-dns-records = mkOption {
type = listOf str;
description = "Records to be inserted verbatim into the DNS zone.";
example = ["some-host IN CNAME base-host"];
default = [];
};
dmarc-report-address = mkOption {
type = nullOr str;
description = "The email to use to recieve DMARC reports, if any.";
example = "admin-user@domain.com";
default = null;
};
default-host = mkOption {
type = nullOr str;
description = "IP of the host which will act as the default server for this domain, if any.";
default = null;
};
};
};
hostARecords = host: data:
join-lines ((map (ip: "${host} IN A ${ip}") data.ip-addresses) ++
(map (ip: "${host} IN AAAA ${ip}") data.ipv6-addresses));
makeSrvRecords = protocol: type: records:
join-lines (map (record: "_${type}._${protocol} IN SRV ${toString record.priority} ${toString record.weight} ${toString record.port} ${toString record.host}.")
records);
makeSrvProtocolRecords = protocol: types: join-lines (mapAttrsToList (makeSrvRecords protocol) types);
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
hostSshFpRecords = host: data: join-lines (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints);
mxRecords = mxs:
concatStringsSep "\n"
(map (mx: "@ IN MX 10 ${mx}.") mxs);
dmarcRecord = dmarc-email:
optionalString (dmarc-email != null)
''_dmarc IN TXT "v=DMARC1;p=quarantine;sp=quarantine;rua=mailto:${dmarc-email};"'';
nsRecords = ns-hosts:
join-lines ((mapAttrsToList (host: _: "@ IN NS ${host}.") ns-hosts) ++
(mapAttrsToList (host: ip: "${host} IN A ${ip}") ns-hosts));
in {
options.fudo.dns = with types; {
enable = mkEnableOption "Enable master DNS services.";
# FIXME: This should allow for AAAA addresses too...
dns-hosts = mkOption {
type = loaOf str;
description = "Map of domain nameserver FQDNs to IP.";
example = { "ns1.domain.com" = "1.1.1.1"; };
};
domains = mkOption {
type = loaOf (submodule domainOpts);
default = {};
description = "A map of domain to domain options.";
};
listen-ips = mkOption {
type = listOf str;
description = "A list of IPs on which to listen for DNS queries.";
example = ["1.2.3.4"];
};
};
config = mkIf cfg.enable {
services.nsd = {
enable = true;
identity = "procul.informis.land";
interfaces = cfg.listen-ips;
zones = mapAttrs' (dom: dom-cfg:
nameValuePair "${dom}." {
dnssec = dom-cfg.dnssec;
data = ''
$ORIGIN ${dom}.
$TTL 12h
@ IN SOA ns1.${dom}. hostmaster.${dom}. (
${toString builtins.currentTime}
5m
2m
6w
5m)
${optionalString (dom-cfg.default-host != null) "@ IN A ${dom-cfg.default-host}"}
${mxRecords dom-cfg.mx}
$TTL 6h
${nsRecords cfg.dns-hosts}
${dmarcRecord dom-cfg.dmarc-report-address}
${join-lines (mapAttrsToList makeSrvProtocolRecords dom-cfg.srv-records)}
${join-lines (mapAttrsToList hostARecords dom-cfg.hosts)}
${join-lines (mapAttrsToList hostSshFpRecords dom-cfg.hosts)}
${join-lines (mapAttrsToList cnameRecord dom-cfg.aliases)}
${join-lines dom-cfg.extra-dns-records}
'';
}) cfg.domains;
};
};
}

View File

@ -104,6 +104,7 @@ in {
user-aliases = mkOption { user-aliases = mkOption {
type = with types; loaOf(listOf str); type = with types; loaOf(listOf str);
description = "A map of real user to list of aliases."; description = "A map of real user to list of aliases.";
default = {};
example = { example = {
someuser = ["alias0" "alias1"]; someuser = ["alias0" "alias1"];
}; };
@ -167,4 +168,22 @@ in {
./mail/rspamd.nix ./mail/rspamd.nix
./mail/clamav.nix ./mail/clamav.nix
]; ];
config = mkIf cfg.enable {
users = {
users = {
mailuser = {
isSystemUser = true;
uid = cfg.mail-user-id;
group = "mailgroup";
};
};
groups = {
mailgroup = {
members = ["mailuser"];
};
};
};
};
} }

View File

@ -23,61 +23,86 @@ let
''; '';
}; };
ldap-conf = filename: uris: ldap-conf = filename: config:
pkgs.writeText filename '' let
uris = ${concatStringsSep " " uris} ssl-config = if config.ca == null then ''
tls = no
tls_require_cert = try
'' else ''
tls_ca_cert_file = ${config.ca}
tls = yes
tls_require_cert = try
'';
in
pkgs.writeText filename ''
uris = ${concatStringsSep " " config.server-urls}
ldap_version = 3 ldap_version = 3
dn = ${cfg.dovecot.ldap-reader-dn} dn = ${config.reader-dn}
dnpass = ${cfg.dovecot.ldap-reader-passwd} dnpass = ${config.reader-passwd}
auth_bind = yes auth_bind = yes
auth_bind_userdn = uid=%u,ou=members,dc=fudo,dc=org auth_bind_userdn = uid=%u,ou=members,dc=fudo,dc=org
base = dc=fudo,dc=org base = dc=fudo,dc=org
# tls_ca_cert_file = ${cfg.dovecot.ldap-ca} ${ssl-config}
# FIXME: turn back on when certs work
tls = no
tls_require_cert = try
''; '';
dovecot-user = config.services.dovecot2.user; ldap-passwd-entry = ldap-config: ''
passdb {
driver = ldap
args = ${ldap-conf "ldap-passdb.conf" ldap-config}
}
'';
in { ldapOpts = with types; {
options.fudo.mail-server.dovecot = { ca = mkOption {
ssl-private-key = mkOption { type = str;
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."; description = "The path to the CA cert used to sign the LDAP server certificate.";
}; };
ldap-urls = mkOption { server-urls = mkOption {
type = with types; listOf str; type = listOf str;
description = "The urls of LDAP servers."; description = "A list of LDAP server URLs used for authentication.";
}; };
ldap-reader-dn = mkOption { reader-dn = mkOption {
type = types.str; type = str;
description = '' description = ''
DN to use for reading user information. Needs access to homeDirectory, DN to use for reading user information. Needs access to homeDirectory,
uidNumber, gidNumber, and uid, but not password attributes. uidNumber, gidNumber, and uid, but not password attributes.
''; '';
}; };
ldap-reader-passwd = mkOption { reader-pw = mkOption {
type = types.str; type = str;
description = '' description = ''
Password for the user specified in ldap-reader-dn. Password for the user specified in ldap-reader-dn.
''; '';
}; };
}; };
dovecot-user = config.services.dovecot2.user;
in {
options.fudo.mail-server.dovecot = with types; {
ssl-private-key = mkOption {
type = str;
description = "Location of the server SSL private key.";
};
ssl-certificate = mkOption {
type = str;
description = "Location of the server SSL certificate.";
};
ldap = mkOption {
type = nullOr (submodule ldapOpts);
default = null;
description = ''
LDAP auth server configuration. If omitted, the server will use local authentication.
'';
};
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.prometheus.exporters.dovecot = mkIf cfg.monitoring { services.prometheus.exporters.dovecot = mkIf cfg.monitoring {
@ -93,8 +118,7 @@ in {
enableImap = true; enableImap = true;
enableLmtp = true; enableLmtp = true;
enablePop3 = true; enablePop3 = true;
enablePAM = false; enablePAM = cfg.dovecot.ldap == null;
createMailUser = true; createMailUser = true;
@ -124,14 +148,16 @@ in {
extraConfig = '' extraConfig = ''
#Extra Config #Extra Config
# The prometheus exporter still expects an older style of metrics ${optionalString cfg.monitoring ''
mail_plugins = $mail_plugins old_stats # The prometheus exporter still expects an older style of metrics
service old-stats { mail_plugins = $mail_plugins old_stats
unix_listener old-stats { service old-stats {
user = dovecot-exporter unix_listener old-stats {
group = dovecot-exporter user = dovecot-exporter
group = dovecot-exporter
}
} }
} ''}
${lib.optionalString cfg.debug '' ${lib.optionalString cfg.debug ''
mail_debug = yes mail_debug = yes
@ -170,15 +196,15 @@ in {
} }
# Drop privs, since all mail is owned by one user # Drop privs, since all mail is owned by one user
user = ${cfg.mail-user} # user = ${cfg.mail-user}
group = ${cfg.mail-group} # group = ${cfg.mail-group}
user = root
} }
auth_mechanisms = login plain auth_mechanisms = login plain
passdb {
driver = ldap ${optionalString (cfg.dovecot.ldap != null)
args = ${ldap-conf "ldap-passdb.conf" cfg.dovecot.ldap-urls} (ldap-conf cfg.dovecot.ldap)}
}
userdb { userdb {
driver = static driver = static
args = uid=${toString cfg.mail-user-id} home=${cfg.mail-directory}/%u args = uid=${toString cfg.mail-user-id} home=${cfg.mail-directory}/%u
@ -189,8 +215,18 @@ in {
unix_listener auth { unix_listener auth {
mode = 0660 mode = 0660
user = "${config.services.postfix.user}" user = "${config.services.postfix.user}"
group = ${config.services.postfix.group} group = ${cfg.mail-group}
} }
unix_listener auth-userdb {
mode = 0660
user = "${config.services.postfix.user}"
group = ${cfg.mail-group}
}
}
service auth-worker {
user = root
} }
namespace inbox { namespace inbox {
@ -236,7 +272,8 @@ in {
done done
chown -R '${dovecot-user}:${cfg.mail-group}' '${state-directory}/imap_sieve' chown -R '${dovecot-user}:${cfg.mail-group}' '${state-directory}/imap_sieve'
chown ${cfg.mail-user}:${cfg.mail-group} ${cfg.mail-directory} chown '${cfg.mail-user}:${cfg.mail-group}' ${cfg.mail-directory}
chmod g+w ${cfg.mail-directory}
''; '';
}; };
} }

View File

@ -6,6 +6,14 @@ let
cfg = config.fudo.mail-server; cfg = config.fudo.mail-server;
# The final newline is important
write-entries = filename: entries:
let
entries-string = (concatStringsSep "\n" entries);
in builtins.toFile filename ''
${entries-string}
'';
make-user-aliases = entries: make-user-aliases = entries:
concatStringsSep "\n" concatStringsSep "\n"
(mapAttrsToList (user: aliases: (mapAttrsToList (user: aliases:
@ -39,25 +47,22 @@ let
/^User-Agent:/ IGNORE /^User-Agent:/ IGNORE
/^X-Enigmail:/ IGNORE /^X-Enigmail:/ IGNORE
''); '');
blacklist-postfix-entry = sender: "${sender} REJECT"; blacklist-postfix-entry = sender: "${sender} REJECT";
blacklist-postfix-file = entries: blacklist-postfix-file = filename: entries:
concatStringsSep "\n" (map blacklist-postfix-entry entries); write-entries filename entries;
sender-blacklist-file = builtins.toFile "reject_senders" sender-blacklist-file = blacklist-postfix-file "reject_senders"
(blacklist-postfix-file cfg.sender-blacklist); (map blacklist-postfix-entry cfg.sender-blacklist);
recipient-blacklist-file = builtins.toFile "reject_recipients" recipient-blacklist-file = blacklist-postfix-file "reject_recipients"
(blacklist-postfix-file cfg.recipient-blacklist); (map blacklist-postfix-entry cfg.recipient-blacklist);
# A list of domains for which we accept mail # A list of domains for which we accept mail
virtual-mailbox-map-file = builtins.toFile "virtual_mailbox_map" virtual-mailbox-map-file = write-entries "virtual_mailbox_map"
(concatStringsSep "\n" (map (domain: "@${domain} OK") (cfg.local-domains ++ [cfg.domain]));
(map (domain: "@${domain} OK") (cfg.local-domains ++ [cfg.domain])));
sender-login-map-file = let sender-login-map-file = let
escapeDot = (str: replaceStrings ["."] ["\\."] str); escapeDot = (str: replaceStrings ["."] ["\\."] str);
in builtins.toFile "sender_login_maps" in write-entries "sender_login_maps"
(concatStringsSep "\n" (map (domain: "/^(.*)@${escapeDot domain}$/ \${1}") (cfg.local-domains ++ [cfg.domain]));
(map (domain: "/^(.*)@${escapeDot domain}$/ \${1}") (cfg.local-domains ++ [cfg.domain])));
mapped-file = name: "hash:/var/lib/postfix/conf/${name}"; mapped-file = name: "hash:/var/lib/postfix/conf/${name}";
@ -106,9 +111,8 @@ in {
origin = cfg.domain; origin = cfg.domain;
hostname = cfg.hostname; hostname = cfg.hostname;
destination = ["localhost" "localhost.localdomain"]; destination = ["localhost" "localhost.localdomain"];
# destination = ["localhost" "localhost.localdomain"] ++ # destination = ["localhost" "localhost.localdomain" cfg.hostname] ++
# (map (domain: "localhost.${domain}") cfg.local-domains) ++ # cfg.local-domains;;
# cfg.local-domains;
enableHeaderChecks = true; enableHeaderChecks = true;
enableSmtp = true; enableSmtp = true;
@ -133,7 +137,7 @@ in {
sslKey = cfg.postfix.ssl-private-key; sslKey = cfg.postfix.ssl-private-key;
config = { config = {
virtual_mailbox_domains = builtins.toFile "domain-list" (concatStringsSep "\n" cfg.local-domains); virtual_mailbox_domains = cfg.local-domains ++ [cfg.domain];
# virtual_mailbox_base = "${cfg.mail-directory}/"; # virtual_mailbox_base = "${cfg.mail-directory}/";
virtual_mailbox_maps = mapped-file "virtual_mailbox_map"; virtual_mailbox_maps = mapped-file "virtual_mailbox_map";

View File

@ -0,0 +1,212 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.informis.cl-gemini;
lisp-libs = with pkgs.lispPackages; [
asdf-package-system
asdf-system-connections
alexandria
asdf-package-system
asdf-system-connections
cl_plus_ssl
cl-ppcre
quicklisp
quri
uiop
usocket
];
launchServer = ip: port: root: public-dir: key: cert: slynk-port: feeds-string: textfiles-archive:
pkgs.writeText "launch-server.lisp" ''
(load (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))
(ql:quickload :slynk)
(ql:quickload :cl-gemini)
${optionalString (slynk-port != null) "(slynk:create-server :port ${toString slynk-port} :dont-close t)"}
${feeds-string}
(cl-gemini:start-gemini-server "${ip}" "${key}" "${cert}"
:port ${toString port}
:document-root "${root}"
:textfiles-root "${textfiles-archive}"
:file-cmd "${pkgs.file}/bin/file"
:log-stream *standard-output*
:threaded t
:separate-thread t)
(loop (sleep 60))
'';
sbcl-with-ssl = pkgs.sbcl.overrideAttrs (oldAttrs: rec {
extraLibs = with pkgs; [
openssl_1_1.dev
];
});
feedOpts = with types; {
options = {
url = mkOption {
type = str;
description = "Base URI of the feed, i.e. the URI corresponding to the feed path.";
example = "gemini://my.server/path/to/feedfiles";
};
title = mkOption {
type = str;
description = "Title of given feed.";
example = "My Fancy Feed";
};
path = mkOption {
type = str;
description = "Path to Gemini files making up the feed.";
example = "/path/to/feed";
};
};
};
register-feed = name: opts: ''
(cl-gemini:register-feed :name "${name}" :title "${opts.title}" :path "${opts.path}" :base-uri "${opts.url}")'';
register-feeds = feeds:
concatStringsSep "\n"
(mapAttrsToList register-feed feeds);
in {
options.informis.cl-gemini = with types; {
enable = mkEnableOption "Enable the cl-gemini server.";
port = mkOption {
type = port;
description = "Port on which to serve Gemini traffic.";
default = 1965;
};
server-ip = mkOption {
type = str;
description = "IP on which to serve Gemini traffic.";
example = "1.2.3.4";
};
document-root = mkOption {
type = str;
description = "Root at which to look for gemini files.";
example = "/my/gemini/root";
};
user-public = mkOption {
type = str;
description = "Subdirectory of user homes to check for gemini files.";
default = "gemini-public";
};
ssl-private-key = mkOption {
type = path;
description = "Path to the pem-encoded server private key.";
example = /path/to/secret/key.pem;
};
ssl-certificate = mkOption {
type = path;
description = "Path to the pem-encoded server public certificate.";
example = /path/to/cert.pem;
};
slynk-port = mkOption {
type = nullOr port;
description = "Port on which to open a slynk server, if any.";
default = null;
};
feeds = mkOption {
type = loaOf (submodule feedOpts);
description = "Feeds to generate and make available (as eg. /feed/name.xml).";
example = {
diary = {
title = "My Diary";
path = "/path/to/my/gemfiles/";
url = "gemini://my.host/blog-path/";
};
};
default = {};
};
textfiles-archive = mkOption {
type = str;
description = "A path containing only gemini & text files.";
example = "/path/to/textfiles/";
};
};
config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [
cl-gemini
];
users.users = {
cl-gemini = {
isSystemUser = true;
group = "nogroup";
createHome = true;
home = "/var/lib/cl-gemini";
};
};
environment.etc = {
"cl-gemini/key.pem" = {
mode = "0400";
user = "cl-gemini";
source = cfg.ssl-private-key;
};
"cl-gemini/cert.pem" = {
mode = "0444";
user = "cl-gemini";
source = cfg.ssl-certificate;
};
};
systemd.services.cl-gemini = {
description = "cl-gemini Gemini server (https://gemini.circumlunar.space/)";
serviceConfig = let
feed-registrations = register-feeds cfg.feeds;
in {
ExecStartPre = "${pkgs.lispPackages.quicklisp}/bin/quicklisp init";
ExecStart = "${sbcl-with-ssl}/bin/sbcl --load ${
launchServer
cfg.server-ip
cfg.port
cfg.document-root
cfg.user-public
"/etc/cl-gemini/key.pem"
"/etc/cl-gemini/cert.pem"
cfg.slynk-port
feed-registrations
cfg.textfiles-archive
}";
Restart = "on-failure";
PIDFile = "/run/cl-gemini.$USERNAME.uid";
User = "cl-gemini";
};
environment = {
LD_LIBRARY_PATH = "${pkgs.openssl_1_1.out}/lib";
CL_SOURCE_REGISTRY = concatStringsSep ":"
(["${config.users.users.cl-gemini.home}/quicklisp/quicklisp"] ++
(map
(pkg: "${pkg}//")
(lisp-libs ++ [pkgs.cl-gemini])));
};
path = with pkgs; [
gcc
file
getent
];
wantedBy = [ "default.target" ];
};
};
}

View File

@ -7,6 +7,7 @@ with lib;
./fudo/authentication.nix ./fudo/authentication.nix
./fudo/chat.nix ./fudo/chat.nix
./fudo/common.nix ./fudo/common.nix
./fudo/dns.nix
./fudo/git.nix ./fudo/git.nix
./fudo/grafana.nix ./fudo/grafana.nix
./fudo/kdc.nix ./fudo/kdc.nix
@ -23,6 +24,8 @@ with lib;
./fudo/system.nix ./fudo/system.nix
./fudo/webmail.nix ./fudo/webmail.nix
./informis/cl-gemini.nix
../fudo/profiles ../fudo/profiles
../fudo/sites ../fudo/sites
]; ];

View File

@ -57,6 +57,7 @@
mkpasswd mkpasswd
ncurses5 ncurses5
nix-index nix-index
nix-prefetch-git
nmap nmap
oidentd oidentd
openldap openldap
@ -84,14 +85,13 @@
yubikey-personalization yubikey-personalization
]; ];
system.stateVersion = "19.09"; system.stateVersion = "20.03";
system.autoUpgrade.enable = true; system.autoUpgrade.enable = true;
environment.etc.current-nixos-config.source = ./.; environment.etc.current-nixos-config.source = ./.;
krb5.enable = true; krb5.enable = true;
krb5.libdefaults.default_realm = "FUDO.ORG";
krb5.kerberos = pkgs.heimdalFull; krb5.kerberos = pkgs.heimdalFull;
console.keyMap = "dvp"; console.keyMap = "dvp";

View File

@ -51,6 +51,8 @@ in {
config = mkIf (config.fudo.common.profile == "server") { config = mkIf (config.fudo.common.profile == "server") {
environment = { environment = {
systemPackages = with pkgs; [ systemPackages = with pkgs; [
ldns
ldns.examples
test-config test-config
reboot-if-necessary reboot-if-necessary
]; ];

View File

@ -2,17 +2,14 @@
with lib; with lib;
let let
admin = "admin@fudo.org";
nameservers = [
"1.1.1.1"
"2606:4700:4700::1111"
];
hostname = config.networking.hostName; hostname = config.networking.hostName;
gateway = "172.86.179.17"; gateway = "172.86.179.17";
local-domain = "informis.land";
admin = "admin@${local-domain}";
in { in {
config = mkIf (config.fudo.common.site == "joes") { config = mkIf (config.fudo.common.site == "joes") {
time.timeZone = "America/Winnipeg"; time.timeZone = "America/Winnipeg";
@ -22,31 +19,32 @@ in {
}; };
networking = { networking = {
domain = "fudo.org"; domain = local-domain;
search = ["fudo.org"]; search = [ local-domain "fudo.org" ];
firewall.enable = false; firewall.enable = false;
nameservers = nameservers;
defaultGateway = gateway; defaultGateway = gateway;
# defaultGateway6 = gateway6; # defaultGateway6 = gateway6;
hosts = {
"127.0.0.1" = [
"${config.networking.hostName}.${local-domain}"
config.networking.hostName
];
};
}; };
krb5.libdefaults.default_realm = "INFORMIS.LAND";
fudo.node-exporter = { fudo.node-exporter = {
enable = true; enable = false;
hostname = hostname; hostname = hostname;
}; };
security.acme.certs.${hostname} = { security.acme.certs."${hostname}.${local-domain}" = {
email = "admin@fudo.org"; email = "admin@${local-domain}";
# plugins = [
# "fullchain.pem"
# "full.pem"
# "key.pem"
# "chain.pem"
# "cert.pem"
# ];
}; };
services.nginx = { services.nginx = {
enable = true; enable = true;
recommendedGzipSettings = true; recommendedGzipSettings = true;

View File

@ -24,6 +24,8 @@ in {
mailto = admin; mailto = admin;
}; };
krb5.libdefaults.default_realm = "FUDO.ORG";
networking = { networking = {
domain = local-domain; domain = local-domain;
search = [local-domain "fudo.org"]; search = [local-domain "fudo.org"];

View File

@ -3,8 +3,10 @@
with lib; with lib;
let let
hostname = "procul"; hostname = "procul";
domain = "informis.land";
mail-hostname = hostname; mail-hostname = hostname;
host_ipv4 = "172.86.179.18"; host_ipv4 = "172.86.179.18";
host-fqdn = "${hostname}.${domain}";
all-hostnames = []; all-hostnames = [];
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem"; acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
@ -25,37 +27,20 @@ in {
../hardware-configuration.nix ../hardware-configuration.nix
../defaults.nix ../defaults.nix
../informis/users.nix
]; ];
fudo.common = {
# Sets some server-common settings. See /etc/nixos/fudo/profiles/...
profile = "server";
# Sets some common site-specific settings: gateway, monitoring, etc. See /etc/nixos/fudo/sites/...
site = "joes";
local-networks = [
"172.86.179.18/29"
"208.81.1.128/28"
"208.81.3.112/28"
"172.17.0.0/16"
"127.0.0.0/8"
];
};
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
multipath-tools multipath-tools
]; ];
# Not all users need access to procul; don't allow LDAP-user access.
fudo.authentication.enable = false;
# TODO: not used yet
fudo.acme.hostnames = all-hostnames;
networking = { networking = {
hostName = hostname; hostName = hostname;
# provided by secure-dns-proxy
nameservers = [ "127.0.0.1" ];
dhcpcd.enable = false; dhcpcd.enable = false;
useDHCP = false; useDHCP = false;
@ -86,4 +71,215 @@ in {
}; };
hardware.bluetooth.enable = false; hardware.bluetooth.enable = false;
users = {
users = {
gituser = {
isSystemUser = true;
group = "nogroup";
};
};
};
fudo = {
common = {
# Sets some server-common settings. See /etc/nixos/fudo/profiles/...
profile = "server";
# Sets some common site-specific settings: gateway, monitoring, etc. See /etc/nixos/fudo/sites/...
site = "joes";
domain = domain;
admin-email = "admin@${domain}";
local-networks = [
"172.86.179.16/29"
"208.81.1.128/28"
"208.81.3.112/28"
"172.17.0.0/16"
"127.0.0.0/8"
];
};
# Not all users need access to procul; don't allow LDAP-user access.
authentication.enable = false;
auth.kdc = {
enable = true;
database-path = "/var/heimdal/heimdal";
realm = "INFORMIS.LAND";
mkey-file = "/srv/heimdal/secure/m-key";
acl-file = "/etc/heimdal/kdc.acl";
bind-addresses = [
host_ipv4
"127.0.0.1"
"127.0.1.1"
];
};
secure-dns-proxy = {
enable = true;
upstream-dns = [ "https://cloudflare-dns.com/dns-query" ];
bootstrap-dns = "1.1.1.1";
listen-ips = [ "127.0.0.1" ];
port = 53;
};
dns = {
enable = true;
dns-hosts = {
"ns1.informis.land" = "172.86.179.18";
"ns2.informis.land" = "172.86.179.18";
};
listen-ips = [host_ipv4];
domains = {
"informis.land" = import ../informis/informis.land.nix {
inherit host_ipv4 config;
};
};
};
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 = [
"172.86.179.16/29"
"127.0.0.0/16"
];
users = {
gituser = {
password = fileContents "/srv/git/secure/db.passwd";
databases = {
git = "ALL PRIVILEGES";
};
};
};
databases = {
git = ["niten"];
};
};
git = {
enable = true;
hostname = "git.informis.land";
site-name = "informis git";
user = "gituser";
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";
};
};
acme = {
enable = true;
admin-address = "admin@${domain}";
hostnames = [
"informis.land"
"imap.informis.land"
"smtp.informis.land"
"gemini.informis.land"
];
};
};
security.acme.certs.${host-fqdn}.email = "admin@${domain}";
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
virtualHosts = {
"${host-fqdn}" = {
enableACME = true;
forceSSL = true;
};
};
};
informis.cl-gemini = {
enable = true;
server-ip = host_ipv4;
document-root = "/srv/gemini/root";
ssl-private-key = "/srv/gemini/private/key.pem";
ssl-certificate = "/srv/gemini/private/cert.pem";
slynk-port = 4005;
textfiles-archive = "/srv/gemini/textfiles";
feeds = {
viator = {
title = "viator's phlog";
path = "/home/viator/gemini-public/feed/";
url = "gemini://informis.land/user/viator/feed/";
};
};
};
} }

View File

@ -0,0 +1,98 @@
{ host_ipv4, config }:
{
dnssec = true;
mx = ["smtp.informis.land"];
hosts = {
procul = {
ip-addresses = [ "172.86.179.18" ];
ssh-fingerprints = [
"4 1 2a8e086d3589ce50b58c55bc35638af8da23988e"
"4 2 55a9f7c0addf08bb24c62ced954574db6e95eff38ee56d6a2cff312d20eb910e"
"1 1 d089902f60751b3d35b5329bf7b906df254d5fa7"
"1 2 8deebf42bbc40881a327f561bffd5d7bd328a4fc94d4e4ce8c502a9c6cbdfb92"
];
};
};
default-host = "172.86.179.18";
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;
}];
};
};
aliases = {
smtp = "procul.informis.land.";
imap = "procul.informis.land.";
gemini = "procul.informis.land.";
git = "procul.informis.land.";
};
extra-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"''
];
dmarc-report-address = "dmarc-report@informis.land";
}

14
informis/users.nix Normal file
View File

@ -0,0 +1,14 @@
{ config, ... }:
{
config = {
users.users = {
viator = {
isNormalUser = true;
description = "Viator";
createHome = true;
hashedPassword = "$6$a1q2Duoe35hd5$IaZGXPfqyGv9uq5DQm7DZq0vIHsUs39sLktBiBBqMiwl/f/Z4jSvNZLJp9DZJYe5u2qGBYh1ca.jsXvQA8FPZ/";
};
};
};
}

24
packages/cl-gemini.nix Normal file
View File

@ -0,0 +1,24 @@
{ stdenv, fetchgit, pkgs }:
let
url = "https://git.informis.land/viator/cl-gemini.git";
version = "0.1";
in stdenv.mkDerivation {
name = "cl-gemini-${version}";
src = fetchgit {
url = "https://git.informis.land/viator/cl-gemini.git";
rev = "3de4d1945fc91d0c9f8f65a5d4b0d3f39fbdaa80";
sha256 = "1xzfsp5vp36a3yas5pnhj2a1dd72r72fw3l49ah19hvbapaikhsw";
fetchSubmodules = false;
};
phases = ["installPhase"];
installPhase = ''
mkdir -p "$out/lib/common-lisp/cl-gemini"
cp "$src/cl-gemini.asd" "$out/lib/common-lisp/cl-gemini"
cp -R "$src/src" "$out/lib/common-lisp/cl-gemini"
'';
}

View File

@ -32,14 +32,14 @@
buildInputs = oldAttrs.buildInputs ++ [ pkgs.krb5 ]; buildInputs = oldAttrs.buildInputs ++ [ pkgs.krb5 ];
}); });
sbcl-with-libs = pkgs.sbcl.overrideAttrs (oldAttrs: rec {
extraLibs = with pkgs; [
openssl_1_1.dev
];
});
hll2380dw-cups = import ./hll2380dw-cups.nix { hll2380dw-cups = import ./hll2380dw-cups.nix {
inherit (pkgs) stdenv fetchurl makeWrapper cups dpkg a2ps ghostscript gnugrep gnused coreutils file perl which; inherit (pkgs) stdenv fetchurl makeWrapper cups dpkg a2ps ghostscript gnugrep gnused coreutils file perl which;
}; };
cl-gemini = import ./cl-gemini.nix {
pkgs = pkgs;
stdenv = pkgs.stdenv;
fetchgit = pkgs.fetchgit;
};
}; };
} }