Currently broken config...
This commit is contained in:
parent
46c45f4440
commit
00a97b1d94
|
@ -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 = ''
|
||||
<html>
|
||||
<head>
|
||||
<title>${hostname}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${hostname}</title>
|
||||
</body>
|
||||
</html>
|
||||
'';
|
||||
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);
|
||||
};
|
||||
}
|
|
@ -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
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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 = [];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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}/";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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 = ''
|
||||
|
|
|
@ -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 = {
|
||||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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
|
||||
];
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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} - -"
|
||||
];
|
||||
};
|
||||
}
|
|
@ -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}
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -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}" ];
|
|
@ -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}" ];
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -o errexit
|
||||
exec rspamc -h /run/rspamd/worker-controller.sock learn_ham
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -o errexit
|
||||
exec rspamc -h /run/rspamd/worker-controller.sock learn_spam
|
|
@ -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");
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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 ];
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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};
|
||||
}
|
|
@ -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
|
||||
];
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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 <host:port> docker targets from which to gather node data.
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
|
||||
push-url = mkOption {
|
||||
type = with types; nullOr str;
|
||||
description = ''
|
||||
The <host:port> that services can use to manually push data.
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
|
||||
push-address = mkOption {
|
||||
type = with types; nullOr str;
|
||||
description = ''
|
||||
The <host:port> 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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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};
|
||||
}
|
|
@ -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
|
||||
];
|
||||
}
|
|
@ -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)}
|
||||
# '';
|
||||
# };
|
||||
}
|
||||
|
|
37
defaults.nix
37
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,34 +142,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
users.extraUsers = {
|
||||
node = {
|
||||
isSystemUser = true;
|
||||
group = "nogroup";
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = {
|
||||
fudosys = {
|
||||
gid = 888;
|
||||
};
|
||||
};
|
||||
|
||||
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.extraUsers = {
|
||||
niten = {
|
||||
isNormalUser = true;
|
||||
|
|
|
@ -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"];
|
||||
}
|
|
@ -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"
|
||||
];
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Emails for which we won't accept any email.
|
||||
|
||||
[]
|
|
@ -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"
|
||||
]
|
|
@ -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";
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
];
|
||||
}
|
|
@ -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";
|
||||
|
|
255
hosts/france.nix
255
hosts/france.nix
|
@ -1,35 +1,116 @@
|
|||
{ 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;
|
||||
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"
|
||||
];
|
||||
};
|
||||
|
||||
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";
|
||||
};
|
||||
|
||||
# So that grafana waits for postgresql
|
||||
systemd.services.grafana.requires = [
|
||||
"postgresql"
|
||||
];
|
||||
|
||||
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";
|
||||
|
@ -39,11 +120,21 @@ in {
|
|||
|
||||
sslCert = "/srv/ldap/france.fudo.org.pem";
|
||||
sslKey = "/srv/ldap/secure/france.fudo.org-key.pem";
|
||||
sslCACert = "/etc/nixos/static/fudo_ca.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://${hostname}/"
|
||||
"ldaps://${hostname}/"
|
||||
"ldap://${host_ipv4}/"
|
||||
"ldaps://${host_ipv4}/"
|
||||
"ldap://localhost/"
|
||||
"ldaps://localhost/"
|
||||
"ldapi:///"
|
||||
|
@ -56,6 +147,50 @@ in {
|
|||
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 = {
|
||||
hostName = hostname;
|
||||
|
||||
|
@ -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.";
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -1,13 +1,36 @@
|
|||
{ config, pkgs, ... }:
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
{
|
||||
config.time.timeZone = "America/Winnipeg";
|
||||
let
|
||||
hostname = config.networking.hostName;
|
||||
|
||||
config.services.cron = {
|
||||
www-root = "/var/www";
|
||||
|
||||
index = pkgs.writeTextFile {
|
||||
name = "index.html";
|
||||
|
||||
text = ''
|
||||
<html>
|
||||
<head>
|
||||
<title>${hostname}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${hostname}</title>
|
||||
</body>
|
||||
</html>
|
||||
'';
|
||||
destination = www-root + ("/" + hostname);
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
config = {
|
||||
time.timeZone = "America/Winnipeg";
|
||||
|
||||
services.cron = {
|
||||
mailto = "admin@fudo.org";
|
||||
};
|
||||
|
||||
config.networking = {
|
||||
networking = {
|
||||
domain = "fudo.org";
|
||||
|
||||
search = ["fudo.org"];
|
||||
|
@ -21,7 +44,69 @@
|
|||
nameservers = [ "1.1.1.1" "208.81.7.14" "2606:4700:4700::1111" ];
|
||||
};
|
||||
|
||||
config.services.prometheus.exporters = {
|
||||
node.enable = true;
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
nixpkgs.config.packageOverrides = pkgs: rec {
|
||||
acme-ca = import ./acme-ca.nix {
|
||||
stdenv = pkgs.stdenv;
|
||||
fetchurl = builtins.fetchurl;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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 ];
|
||||
});
|
||||
};
|
||||
}
|
|
@ -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 }.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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 ];
|
||||
});
|
||||
};
|
||||
}
|
|
@ -77,6 +77,10 @@
|
|||
|
||||
services.dbus.socketActivated = true;
|
||||
|
||||
services.openssh.forwardX11 = true;
|
||||
|
||||
programs.ssh.forwardX11 = true;
|
||||
|
||||
sound.enable = true;
|
||||
|
||||
hardware.pulseaudio.enable = true;
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
];
|
||||
|
||||
noXlibs = true;
|
||||
};
|
||||
|
||||
security.hideProcessInformation = true;
|
||||
|
||||
boot.tmpOnTmpfs = true;
|
||||
|
||||
services.xserver.enable = false;
|
||||
|
|
|
@ -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'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -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-----
|
||||
|
|
|
@ -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-----
|
Loading…
Reference in New Issue