Tons of changes, I guess?
This commit is contained in:
parent
c31af09ede
commit
2dd5407129
|
@ -0,0 +1,29 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
admins = config.instance.local-admins;
|
||||||
|
domain = config.instance.local-domain;
|
||||||
|
|
||||||
|
gen-addrs = names: domain:
|
||||||
|
map (name: "${name}@${domain}") names;
|
||||||
|
|
||||||
|
admin-addrs = gen-addrs admins domain;
|
||||||
|
|
||||||
|
in {
|
||||||
|
config.fudo.mail-server.alias-users = {
|
||||||
|
root = admin-addrs;
|
||||||
|
postmaster = admin-addrs;
|
||||||
|
www-data = admin-addrs;
|
||||||
|
hostmaster = admin-addrs;
|
||||||
|
webmaster = admin-addrs;
|
||||||
|
ftp = admin-addrs;
|
||||||
|
irc = admin-addrs;
|
||||||
|
admin = admin-addrs;
|
||||||
|
system = admin-addrs;
|
||||||
|
|
||||||
|
asdf = [ "mswaffer@gmail.com" "bouncetest@fudo.org" ];
|
||||||
|
|
||||||
|
network-info = [ "niten@fudo.org" ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./bash.nix
|
./aliases.nix
|
||||||
./common.nix
|
./bash.nix
|
||||||
./domains.nix
|
./common.nix
|
||||||
./groups.nix
|
./domains.nix
|
||||||
./hosts.nix
|
./groups.nix
|
||||||
./networks.nix
|
./hosts.nix
|
||||||
./profiles.nix
|
./networks.nix
|
||||||
./sites.nix
|
./sites.nix
|
||||||
./users.nix
|
./users.nix
|
||||||
./wireless-networks.nix
|
./wireless-networks.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,11 @@
|
||||||
{
|
{
|
||||||
config.fudo.domains = {
|
config.fudo.domains = {
|
||||||
"fudo.org" = {
|
"fudo.org" = {
|
||||||
local-networks = [ "208.81.1.128/28" "208.81.3.112/28" ];
|
local-networks = [
|
||||||
|
"208.81.1.128/28"
|
||||||
|
"208.81.3.112/28"
|
||||||
|
"91.229.23.204/31"
|
||||||
|
];
|
||||||
|
|
||||||
local-users = [ "niten" "reaper" ];
|
local-users = [ "niten" "reaper" ];
|
||||||
local-groups = [ "fudo" "selby" "admin" ];
|
local-groups = [ "fudo" "selby" "admin" ];
|
||||||
|
@ -13,7 +17,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
"sea.fudo.org" = {
|
"sea.fudo.org" = {
|
||||||
local-networks = [ "10.0.0.0/16" ];
|
local-networks = [
|
||||||
|
"10.0.0.0/16"
|
||||||
|
"208.81.1.128/28"
|
||||||
|
"208.81.3.112/28"
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
local-users = [ "niten" "reaper" "xiaoxuan" "ken" ];
|
local-users = [ "niten" "reaper" "xiaoxuan" "ken" ];
|
||||||
local-groups = [ "fudo" "selby" "admin" ];
|
local-groups = [ "fudo" "selby" "admin" ];
|
||||||
|
@ -44,7 +53,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
"informis.land" = {
|
"informis.land" = {
|
||||||
local-networks = [ ];
|
local-networks = [
|
||||||
|
"172.86.179.17/29"
|
||||||
|
];
|
||||||
|
|
||||||
local-users = [ "niten" "viator" ];
|
local-users = [ "niten" "viator" ];
|
||||||
local-groups = [ "admin" "informis" ];
|
local-groups = [ "admin" "informis" ];
|
||||||
|
@ -52,5 +63,19 @@
|
||||||
admin-email = "viator@informis.land";
|
admin-email = "viator@informis.land";
|
||||||
gssapi-realm = "INFORMIS.LAND";
|
gssapi-realm = "INFORMIS.LAND";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
eur.fudo.org = {
|
||||||
|
local-networks = [
|
||||||
|
"208.81.1.128/28"
|
||||||
|
"208.81.3.112/28"
|
||||||
|
"91.229.23.204/31"
|
||||||
|
];
|
||||||
|
|
||||||
|
local-users = [ "niten"];
|
||||||
|
local-groups = [ "admin" ];
|
||||||
|
local-admins = [ "niten" ];
|
||||||
|
admin-email = "nitenn@fudo.org";
|
||||||
|
gssapi-realm = "FUDO.ORG";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,15 @@
|
||||||
{
|
{
|
||||||
boot = {
|
boot = {
|
||||||
initrd = {
|
initrd = {
|
||||||
availableKernelModules =
|
availableKernelModules = [
|
||||||
[ "uhci_hcd" "ehci_pci" "ata_piix" "ahci" "floppy" "sd_mod" "sr_mod" ];
|
"uhci_hcd"
|
||||||
|
"ehci_pci"
|
||||||
|
"ata_piix"
|
||||||
|
"ahci"
|
||||||
|
"floppy"
|
||||||
|
"sd_mod"
|
||||||
|
"sr_mod"
|
||||||
|
];
|
||||||
kernelModules = [ "dm-snapshot" ];
|
kernelModules = [ "dm-snapshot" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,23 +30,27 @@
|
||||||
"/boot" = {
|
"/boot" = {
|
||||||
device = "/dev/disk/by-label/france-boot";
|
device = "/dev/disk/by-label/france-boot";
|
||||||
fsType = "ext4";
|
fsType = "ext4";
|
||||||
|
options = [ "noatime" "nodiratime" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
"/" = {
|
"/" = {
|
||||||
device = "/dev/disk/by-label/france-root";
|
device = "/dev/disk/by-label/france-root";
|
||||||
fsType = "ext4";
|
fsType = "ext4";
|
||||||
|
options = [ "noatime" "nodiratime" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
"/var/lib/lxd/storage-pools/pool0" = {
|
"/var/lib/lxd/storage-pools/pool0" = {
|
||||||
device = "/dev/disk/by-label/pool0";
|
device = "/dev/disk/by-label/pool0";
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
label = "pool0";
|
label = "pool0";
|
||||||
|
options = [ "noatime" "nodiratime" "noexec" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
"/var/lib/lxd/storage-pools/pool1" = {
|
"/var/lib/lxd/storage-pools/pool1" = {
|
||||||
device = "/dev/france-user/fudo-user";
|
device = "/dev/france-user/fudo-user";
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
label = "pool1";
|
label = "pool1";
|
||||||
|
options = [ "noatime" "nodiratime" "noexec" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,6 +61,8 @@
|
||||||
hardware.bluetooth.enable = false;
|
hardware.bluetooth.enable = false;
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
|
useDHCP = false;
|
||||||
|
|
||||||
macvlans = {
|
macvlans = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
interface = "enp4s0f1";
|
interface = "enp4s0f1";
|
||||||
|
@ -60,6 +73,11 @@
|
||||||
interface = "enp4s0f0";
|
interface = "enp4s0f0";
|
||||||
mode = "bridge";
|
mode = "bridge";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# extif1 = {
|
||||||
|
# interface = "enp4s0f0";
|
||||||
|
# mode = "bridge";
|
||||||
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
interfaces = {
|
interfaces = {
|
||||||
|
@ -72,6 +90,11 @@
|
||||||
# output of: echo france-extif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'
|
# output of: echo france-extif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'
|
||||||
macAddress = "02:5e:ff:e4:83:e4";
|
macAddress = "02:5e:ff:e4:83:e4";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# extif1 = {
|
||||||
|
# # output of: echo france-extif1|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'
|
||||||
|
# macAddress = "02:30:91:97:40:1f";
|
||||||
|
# };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib; {
|
||||||
|
boot = {
|
||||||
|
initrd = {
|
||||||
|
availableKernelModules = [
|
||||||
|
"ahci"
|
||||||
|
"usbhid"
|
||||||
|
];
|
||||||
|
kernelModules = [ "dm-snapshot" ];
|
||||||
|
};
|
||||||
|
kernelModules = [ ];
|
||||||
|
extraModulePackages = [ ];
|
||||||
|
loader.grub = {
|
||||||
|
enable = true;
|
||||||
|
version = 2;
|
||||||
|
device = "/dev/sda";
|
||||||
|
};
|
||||||
|
|
||||||
|
supportedFilesystems = [ "btrfs" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems = {
|
||||||
|
"/" = {
|
||||||
|
device = "root-tmpfs";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [ "mode=755" "noexec" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/boot" = {
|
||||||
|
device = "/dev/disk/by-label/boot";
|
||||||
|
fsType = "ext4";
|
||||||
|
options = [ "noexec" "noatime" "nodiratime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/nix" = {
|
||||||
|
device = "/dev/disk/by-label/system";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@nix" "compress=zstd" "noatime" "nodiratime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/var/log" = {
|
||||||
|
device = "/dev/disk/by-label/system";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@logs" "compress=zstd" "noatime" "nodiratime" "noexec" ];
|
||||||
|
neededForBoot = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"/state" = {
|
||||||
|
device = "/dev/disk/by-label/system";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@state" "compress=zstd" "noatime" "nodiratime" "noexec" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [{ device = "/dev/disk/by-label/swap"; }];
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
macvlans = {
|
||||||
|
extif0 = {
|
||||||
|
interface = "eno2";
|
||||||
|
mode = "bridge";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
useDHCP = false;
|
||||||
|
|
||||||
|
interfaces = {
|
||||||
|
extif0 = {
|
||||||
|
# output of: echo legatus-extif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'
|
||||||
|
macAddress = pkgs.lib.fudo.network.generate-mac-address "legatus" "extif0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -71,6 +71,7 @@
|
||||||
device = "/dev/disk/by-label/socrates-data";
|
device = "/dev/disk/by-label/socrates-data";
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
options = [ "subvol=@log" "compress=zstd" "noatime" "nodiratime" "noexec" ];
|
options = [ "subvol=@log" "compress=zstd" "noatime" "nodiratime" "noexec" ];
|
||||||
|
neededForBoot = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
"/state" = {
|
"/state" = {
|
||||||
|
|
|
@ -9,6 +9,7 @@ let
|
||||||
domain = config.fudo.domains.${domain-name};
|
domain = config.fudo.domains.${domain-name};
|
||||||
host-fqdn = "${hostname}.${domain-name}";
|
host-fqdn = "${hostname}.${domain-name}";
|
||||||
mail-hostname = "mail.fudo.org";
|
mail-hostname = "mail.fudo.org";
|
||||||
|
mail-directory = "/srv/mail";
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.france;
|
secrets = config.fudo.secrets.host-secrets.france;
|
||||||
secret-files = config.fudo.secrets.files;
|
secret-files = config.fudo.secrets.files;
|
||||||
|
@ -37,14 +38,73 @@ in {
|
||||||
config = {
|
config = {
|
||||||
security.acme.email = "admin@fudo.org";
|
security.acme.email = "admin@fudo.org";
|
||||||
|
|
||||||
fudo = {
|
fileSystems = {
|
||||||
|
"/srv/archiva" = {
|
||||||
|
fsType = "btrfs";
|
||||||
|
label = "pool0";
|
||||||
|
options = [ "noatime" "nodiratime" "noexec" "subvol=archiva" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/srv/grafana" = {
|
||||||
|
fsType = "btrfs";
|
||||||
|
label = "pool0";
|
||||||
|
options = [ "noatime" "nodiratime" "noexec" "subvol=grafana" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/srv/gitlab" = {
|
||||||
|
fsType = "btrfs";
|
||||||
|
label = "pool0";
|
||||||
|
options = [ "noatime" "nodiratime" "noexec" "subvol=grafana" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
${mail-directory} = {
|
||||||
|
fsType = "btrfs";
|
||||||
|
label = "pool0";
|
||||||
|
options = [ "noatime" "nodiratime" "noexec" "subvol=mail" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.archiva = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "nogroup";
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualisation = {
|
||||||
|
lxd.enable = true;
|
||||||
|
|
||||||
|
oci-containers = {
|
||||||
|
backend = "docker";
|
||||||
|
|
||||||
|
containers = {
|
||||||
|
archiva = {
|
||||||
|
image = "xetusoss/archiva";
|
||||||
|
autoStart = true;
|
||||||
|
ports = [ "8001:8080/tcp" ];
|
||||||
|
# Ugly: name-to-uid lookup fails.
|
||||||
|
user = toString config.users.users.archiva.uid;
|
||||||
|
volumes = [ "/srv/archiva:/archiva-data" ];
|
||||||
|
environment = {
|
||||||
|
# Not directly connected to the world anyway
|
||||||
|
SSL_ENABLED = "false";
|
||||||
|
PROXY_BASE_URL = "https://archiva.fudo.org/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fudo = let
|
||||||
|
backplane-dns-password-file = pkgs.lib.fudo.passwd.stablerandom-passwd-file
|
||||||
|
"dns-service-backplane-passwd"
|
||||||
|
"dns-service-backplane-passwd-${config.instance.build-seed}";
|
||||||
|
in {
|
||||||
hosts.france.external-interfaces = [ "extif0" ];
|
hosts.france.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
acme.host-domains.france."france.fudo.org" = {
|
acme.host-domains.france."france.fudo.org" = {
|
||||||
email = "admin@fudo.org";
|
email = "admin@fudo.org";
|
||||||
local-copies = {
|
local-copies = {
|
||||||
postgres = {
|
postgres = {
|
||||||
user = config.services.postgresql.user;
|
user = "postgres";
|
||||||
};
|
};
|
||||||
openldap = {
|
openldap = {
|
||||||
user = config.services.openldap.user;
|
user = config.services.openldap.user;
|
||||||
|
@ -56,26 +116,6 @@ in {
|
||||||
ldap-user = config.services.openldap.user;
|
ldap-user = config.services.openldap.user;
|
||||||
ldap-group = config.services.openldap.group;
|
ldap-group = config.services.openldap.group;
|
||||||
in {
|
in {
|
||||||
ldap-ssl-certificate = {
|
|
||||||
source-file = cfg.ssl-certificate;
|
|
||||||
target-file = "/run/openldap/ssl-certificate.pem";
|
|
||||||
user = ldap-user;
|
|
||||||
group = ldap-group;
|
|
||||||
permissions = "0444";
|
|
||||||
};
|
|
||||||
ldap-ssl-private-key = {
|
|
||||||
source-file = cfg.ssl-private-key;
|
|
||||||
target-file = "/run/openldap/ssl-private-key.pem";
|
|
||||||
user = ldap-user;
|
|
||||||
group = ldap-group;
|
|
||||||
};
|
|
||||||
ldap-ssl-ca-certificate = {
|
|
||||||
source-file = cfg.ssl-ca-certificate;
|
|
||||||
target-file = "/run/openldap/ssl-ca-certificate.pem";
|
|
||||||
user = ldap-user;
|
|
||||||
group = ldap-group;
|
|
||||||
permissions = "0444";
|
|
||||||
};
|
|
||||||
ldap-keytab = {
|
ldap-keytab = {
|
||||||
source-file = secret-files.service-keytabs.france.ldap;
|
source-file = secret-files.service-keytabs.france.ldap;
|
||||||
target-file = "/run/openldap/ldap.keytab";
|
target-file = "/run/openldap/ldap.keytab";
|
||||||
|
@ -83,7 +123,8 @@ in {
|
||||||
group = ldap-group;
|
group = ldap-group;
|
||||||
};
|
};
|
||||||
ldap-root-passwd = {
|
ldap-root-passwd = {
|
||||||
source-file = passwd.random-passwd-file;
|
source-file =
|
||||||
|
pkgs.lib.fudo.passwd.random-passwd-file "ldap-root-passwd" 20;
|
||||||
target-file = "/run/openldap/root.passwd";
|
target-file = "/run/openldap/root.passwd";
|
||||||
user = ldap-user;
|
user = ldap-user;
|
||||||
group = ldap-group;
|
group = ldap-group;
|
||||||
|
@ -91,7 +132,12 @@ in {
|
||||||
postgres-keytab = {
|
postgres-keytab = {
|
||||||
source-file = secret-files.service-keytabs.france.postgres;
|
source-file = secret-files.service-keytabs.france.postgres;
|
||||||
target-file = "/run/postgres/postgres.keytab";
|
target-file = "/run/postgres/postgres.keytab";
|
||||||
user = config.services.postgresql.user;
|
user = "postgres"; # This is just plain hard-coded...
|
||||||
|
};
|
||||||
|
backplane-dns-password = {
|
||||||
|
source-file = backplane-dns-password-file;
|
||||||
|
target-file = "/run/backplane/dns/xmpp.passwd";
|
||||||
|
user = config.fudo.backplane.dns.user;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,34 +163,34 @@ in {
|
||||||
|
|
||||||
kdc = {
|
kdc = {
|
||||||
state-directory = "/state/kerberos";
|
state-directory = "/state/kerberos";
|
||||||
master-key-file = "";
|
master-key-file = secret-files.realm-master-keys."FUDO.ORG";
|
||||||
listen-ips = [ primary-ip "127.0.0.1" "127.0.1.1" "::1" ];
|
listen-ips = [ primary-ip "127.0.0.1" "127.0.1.1" "::1" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
jabber = {
|
jabber = {
|
||||||
ldap-servers = [ "france.fudo.org" ];
|
ldap-servers = [ "france.fudo.org" ];
|
||||||
listen-ips = [ primary-ip ];
|
listen-ips = [ primary-ip ];
|
||||||
};
|
|
||||||
|
|
||||||
backplane = {
|
backplane = {
|
||||||
host-passwd-files = let
|
host-passwd-files = let
|
||||||
hosts = attrNames config.fudo.hosts;
|
hosts = attrNames config.fudo.hosts;
|
||||||
in mapAttrs (hostname: hostOpts: hostOpts.backplane-password-file)
|
in mapAttrs (hostname: hostOpts: hostOpts.backplane-password-file)
|
||||||
config.fudo.hosts;
|
config.fudo.hosts;
|
||||||
service-passwd-files = genAttrs [ "dns" ]
|
service-passwd-files = {
|
||||||
(service-name:
|
dns = backplane-dns-password-file;
|
||||||
lib.fudo.passwd.stablerandom-passwd-file
|
};
|
||||||
"${service-name}-service-backplane-passwd"
|
};
|
||||||
"${service-name}-service-backplane-passwd-${config.instance.build-seed}");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
backplane-server = {
|
backplane-server = {
|
||||||
listen-ips = [ primary-ip ];
|
listen-ips = [ primary-ip ];
|
||||||
|
backplane-dns-password-file =
|
||||||
|
secrets.backplane-dns-password.target-file;
|
||||||
};
|
};
|
||||||
|
|
||||||
mail = {
|
mail = {
|
||||||
mail-directory = "/srv/mail/mailboxes";
|
mail-directory = "${mail-directory}/mailboxes";
|
||||||
state-directory = "/srv/mail/var";
|
state-directory = "${mail-directory}/var";
|
||||||
ldap-server-urls = [
|
ldap-server-urls = [
|
||||||
"ldap://france.fudo.org"
|
"ldap://france.fudo.org"
|
||||||
];
|
];
|
||||||
|
@ -169,6 +215,18 @@ in {
|
||||||
ssl-certificate = cert-copy.certificate;
|
ssl-certificate = cert-copy.certificate;
|
||||||
ssl-private-key = cert-copy.private-key;
|
ssl-private-key = cert-copy.private-key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dns = {
|
||||||
|
default-host = primary-ip;
|
||||||
|
listen-ip = primary-ip;
|
||||||
|
mail-hosts = [ "mail.fudo.org" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
chat = {
|
||||||
|
chat-hostname = "chat.fudo.org";
|
||||||
|
mail-server = "mail.fudo.org";
|
||||||
|
database-host = "localhost";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
minecraft-server = {
|
minecraft-server = {
|
||||||
|
@ -181,8 +239,6 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
useDHCP = false;
|
|
||||||
|
|
||||||
interfaces = {
|
interfaces = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
|
@ -196,10 +252,6 @@ in {
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 28;
|
prefixLength = 28;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
address = git-server-ip;
|
|
||||||
prefixLength = 32;
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -218,6 +270,22 @@ in {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/".return = "301 https://webmail.fudo.org$request_uri";
|
locations."/".return = "301 https://webmail.fudo.org$request_uri";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"archiva.fudo.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8001";
|
||||||
|
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;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,8 +11,6 @@ let
|
||||||
concatGenAttrs = lst: f:
|
concatGenAttrs = lst: f:
|
||||||
foldr (a0: a1: a0 // a1) {} (map f lst);
|
foldr (a0: a1: a0 // a1) {} (map f lst);
|
||||||
|
|
||||||
passwd = import ../../../lib/passwd.nix { inherit lib; };
|
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
cfg = config.fudo.france;
|
cfg = config.fudo.france;
|
||||||
|
@ -69,45 +67,47 @@ in {
|
||||||
user = config.fudo.auth.kdc.user;
|
user = config.fudo.auth.kdc.user;
|
||||||
};
|
};
|
||||||
|
|
||||||
auth = {
|
# auth = {
|
||||||
ldap-server = {
|
# ldap-server = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
base = "dc=fudo,dc=org";
|
# base = "dc=fudo,dc=org";
|
||||||
organization = "Fudo";
|
# organization = "Fudo";
|
||||||
rootpw-file = cfg.ldap.root-password-file;
|
# rootpw-file = cfg.ldap.root-password-file;
|
||||||
kerberos-host = fqdn;
|
# kerberos-host = fqdn;
|
||||||
kerberos-keytab = cfg.ldap.keytab;
|
# kerberos-keytab = cfg.ldap.keytab;
|
||||||
ssl-certificate = cfg.ldap.ssl-certificate;
|
# ssl-certificate = cfg.ldap.ssl-certificate;
|
||||||
ssl-private-key = cfg.ldap.ssl-private-key;
|
# ssl-private-key = cfg.ldap.ssl-private-key;
|
||||||
ssl-ca-certificate = cfg.ldap.ssl-ca-certificate;
|
# ssl-ca-certificate = cfg.ldap.ssl-ca-certificate;
|
||||||
|
|
||||||
listen-uris = [ "ldap:///" "ldaps:///" "ldapi:///" ];
|
# listen-uris = [ "ldap:///" "ldaps:///" "ldapi:///" ];
|
||||||
|
|
||||||
users = config.fudo.users;
|
# users = config.fudo.users;
|
||||||
groups = config.fudo.groups;
|
# groups = config.fudo.groups;
|
||||||
system-users = config.fudo.system-users;
|
# system-users = config.fudo.system-users;
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: let build hosts create keys?
|
# database-directory = "/state/openldap";
|
||||||
kdc = {
|
# };
|
||||||
enable = true;
|
|
||||||
realm = config.fudo.domains.${domain-name}.gssapi-realm;
|
# # TODO: let build hosts create keys?
|
||||||
state-directory = cfg.kdc.state-directory;
|
# kdc = {
|
||||||
master-key-file = secrets.kdc-master-key.target-file;
|
# enable = true;
|
||||||
acl = let
|
# realm = config.fudo.domains.${domain-name}.gssapi-realm;
|
||||||
admin-entries = concatGenAttrs
|
# state-directory = cfg.kdc.state-directory;
|
||||||
config.instance.local-admins
|
# master-key-file = secrets.kdc-master-key.target-file;
|
||||||
(admin: {
|
# acl = let
|
||||||
"${admin}" = { perms = [ "add" "list" "change-password" ]; };
|
# admin-entries = concatGenAttrs
|
||||||
"${admin}/root" = { perms = [ "all" ]; };
|
# config.instance.local-admins
|
||||||
});
|
# (admin: {
|
||||||
in {
|
# "${admin}" = { perms = [ "add" "list" "change-password" ]; };
|
||||||
"host/*.fudo.org" = { perms = [ "add" ]; };
|
# "${admin}/root" = { perms = [ "all" ]; };
|
||||||
"pam_migrate/*.fudo.org" = { perms = [ "add" "change-password" ]; };
|
# });
|
||||||
} // admin-entries;
|
# in {
|
||||||
bind-addresses = cfg.kdc.listen-ips;
|
# "host/*.fudo.org" = { perms = [ "add" ]; };
|
||||||
};
|
# "pam_migrate/*.fudo.org" = { perms = [ "add" "change-password" ]; };
|
||||||
};
|
# } // admin-entries;
|
||||||
|
# bind-addresses = cfg.kdc.listen-ips;
|
||||||
|
# };
|
||||||
|
# };o
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,12 @@ let
|
||||||
backplane-dns-user = "backplane-dns";
|
backplane-dns-user = "backplane-dns";
|
||||||
|
|
||||||
generate-role-passwd = role:
|
generate-role-passwd = role:
|
||||||
lib.fudo.passwd.stablerandom-password-file
|
pkgs.lib.fudo.passwd.stablerandom-passwd-file
|
||||||
"backplane-${role}-password"
|
"backplane-${role}-password"
|
||||||
"${hostname}-${domain}-${role}-password-${config.instance.build-timestamp}";
|
"${hostname}-${domain}-${role}-password-${config.instance.build-seed}";
|
||||||
|
|
||||||
powerdns-password = generate-role-passwd "powerdns-db";
|
powerdns-password = generate-role-passwd "powerdns-db";
|
||||||
|
|
||||||
backplane-dns-xmpp-password = generate-role-passwd "backplane-dns-xmpp";
|
|
||||||
|
|
||||||
backplane-dns-db-password = generate-role-passwd "backplane-dns-db";
|
backplane-dns-db-password = generate-role-passwd "backplane-dns-db";
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.france;
|
secrets = config.fudo.secrets.host-secrets.france;
|
||||||
|
@ -36,6 +34,11 @@ in {
|
||||||
description = "List of IPv6s on which to listen for incoming backplane connections.";
|
description = "List of IPv6s on which to listen for incoming backplane connections.";
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
backplane-dns-password-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to file containing the password for connecting to the XMPP backplane.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
@ -64,19 +67,13 @@ in {
|
||||||
powerdns-password = {
|
powerdns-password = {
|
||||||
source-file = powerdns-password;
|
source-file = powerdns-password;
|
||||||
target-file = "/run/backplane/dns/powerdns/db.passwd";
|
target-file = "/run/backplane/dns/powerdns/db.passwd";
|
||||||
user = config.fudo.backplane.dns.database.user;
|
user = config.fudo.backplane.dns.powerdns.user;
|
||||||
};
|
};
|
||||||
|
|
||||||
backplane-dns-db-password = {
|
backplane-dns-db-password = {
|
||||||
source-file = backplane-dns-db-password;
|
source-file = backplane-dns-db-password;
|
||||||
target-file = "/run/backplane/dns/db.passwd";
|
target-file = "/run/backplane/dns/db.passwd";
|
||||||
user = config.fudo.backplane.dns.backplane.user;
|
user = config.fudo.backplane.dns.user;
|
||||||
};
|
|
||||||
|
|
||||||
backplane-dns-xmpp-password = {
|
|
||||||
source-file = backplane-dns-db-password;
|
|
||||||
target-file = "/run/backplane/dns/xmpp.passwd";
|
|
||||||
user = config.fudo.backplane.dns.backplane.user;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,7 +95,7 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
${backplane-dns-user} = {
|
${backplane-dns-user} = {
|
||||||
password-file = secrets.backplane-dns-db-password;
|
password-file = secrets.backplane-dns-db-password.target-file;
|
||||||
databases = {
|
databases = {
|
||||||
backplane_dns = {
|
backplane_dns = {
|
||||||
access = "CONNECT";
|
access = "CONNECT";
|
||||||
|
@ -134,7 +131,7 @@ in {
|
||||||
backplane = {
|
backplane = {
|
||||||
host = "backplane.fudo.org";
|
host = "backplane.fudo.org";
|
||||||
role = "service-dns";
|
role = "service-dns";
|
||||||
password-file = secrets.backplane-dns-xmpp-password.target-file;
|
password-file = cfg.backplane-dns-password-file;
|
||||||
database = {
|
database = {
|
||||||
username = backplane-dns-user;
|
username = backplane-dns-user;
|
||||||
database = backplane-dns-user;
|
database = backplane-dns-user;
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
options.fudo.france.chat = with types; {
|
||||||
|
chat-hostname = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Hostname of the chat server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
mail-server = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Email server to use for communication.";
|
||||||
|
};
|
||||||
|
|
||||||
|
database-host = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Hostname of the database server.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
|
||||||
|
cfg = config.fudo.france.chat;
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
in {
|
||||||
|
fudo = {
|
||||||
|
secrets.host-secrets.${hostname} = {
|
||||||
|
mattermost-mail-password = {
|
||||||
|
source-file = pkgs.lib.fudo.passwd.stablerandom-passwd-file
|
||||||
|
"mattermost-mail-password"
|
||||||
|
"${hostname}-mattermost-mail-password-${config.instance.build-seed}";
|
||||||
|
target-file = "/run/chat/mattermost/mail.passwd";
|
||||||
|
user = config.services.mattermost.user;
|
||||||
|
};
|
||||||
|
|
||||||
|
mattermost-db-password = {
|
||||||
|
source-file = pkgs.lib.fudo.passwd.stablerandom-passwd-file
|
||||||
|
"mattermost-db-password"
|
||||||
|
"${hostname}-mattermost-db-password-${config.instance.build-seed}";
|
||||||
|
target-file = "/run/chat/mattermost/database.passwd";
|
||||||
|
user = config.services.mattermost.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users.fudo-chat = {
|
||||||
|
uid = 20001;
|
||||||
|
primary-group = "fudo";
|
||||||
|
common-name = "Fudo Chat";
|
||||||
|
ldap-hashed-passwd =
|
||||||
|
pkgs.lib.fudo.passwd.hash-ldap-passwd "mattermost-chat"
|
||||||
|
secrets.mattermost-mail-password.source-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql = {
|
||||||
|
databases.mattermost.users =
|
||||||
|
config.instance.local-admins;
|
||||||
|
|
||||||
|
users.mattermost = {
|
||||||
|
password-file =
|
||||||
|
secrets.mattermost-db-password.target-file;
|
||||||
|
databases = {
|
||||||
|
mattermost = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" =
|
||||||
|
"SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" =
|
||||||
|
"SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
chat = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
hostname = cfg.chat-hostname;
|
||||||
|
site-name = "Fudo Chat";
|
||||||
|
smtp = {
|
||||||
|
server = cfg.mail-server;
|
||||||
|
user = "fudo-chat";
|
||||||
|
password-file = secrets.mattermost-mail-password.target-file;
|
||||||
|
};
|
||||||
|
database = {
|
||||||
|
name = "mattermost";
|
||||||
|
hostname = cfg.database-host;
|
||||||
|
user = "mattermost";
|
||||||
|
password-file = secrets.mattermost-db-password.target-file;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
|
||||||
|
cfg = config.fudo.france.dns;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.france.dns = with types; {
|
||||||
|
default-host = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "IP address to which the domain will map.";
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-ip = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "IP addresses on which to listen";
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-ipv6 = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "IPv6 addresses on which to listen";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
mail-hosts = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of mail hosts for the MX records.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = let
|
||||||
|
dom = config.instance.local-domain;
|
||||||
|
dom-cfg = config.fudo.domains.${dom};
|
||||||
|
in {
|
||||||
|
fudo = {
|
||||||
|
mail-server.alias-users.dmarc-report =
|
||||||
|
map (admin: "${admin}@${dom}") dom-cfg.local-admins;
|
||||||
|
|
||||||
|
dns = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
identity = "${hostname}.fudo.org";
|
||||||
|
|
||||||
|
listen-ips =
|
||||||
|
[ cfg.listen-ip ] ++
|
||||||
|
(optional (cfg.listen-ipv6 != null) cfg.listen-ipv6);
|
||||||
|
|
||||||
|
nameservers = {
|
||||||
|
ns1 = {
|
||||||
|
ipv4-address = cfg.listen-ip;
|
||||||
|
ipv6-address = mkIf (cfg.listen-ipv6 != null) cfg.listen-ipv6;
|
||||||
|
description = "Nameserver 1, france, in Winnipeg, MB, CA";
|
||||||
|
};
|
||||||
|
ns2 = {
|
||||||
|
ipv4-address = "209.117.102.102";
|
||||||
|
ipv6-address = "2001:470:1f16:40::2";
|
||||||
|
description = "Nameserver 2, musashi, in Winnipeg, MB, CA";
|
||||||
|
};
|
||||||
|
ns3 = {
|
||||||
|
ipv4-address = "104.131.53.95";
|
||||||
|
ipv6-address = "2604:a880:800:10::8:7001";
|
||||||
|
description =
|
||||||
|
"Nameserver 3, ns2.henchmman21.net, in New York City, NY, US";
|
||||||
|
};
|
||||||
|
ns4 = {
|
||||||
|
ipv4-address = "204.42.254.5";
|
||||||
|
ipv6-address = "2001:418:3f4::5";
|
||||||
|
description = "Nameserver 4, puck.nether.net, in Chicago, IL, US";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
domains = let
|
||||||
|
in {
|
||||||
|
${dom} = {
|
||||||
|
dnssec = true;
|
||||||
|
default-host = cfg.default-host;
|
||||||
|
gssapi-realm = dom-cfg.gssapi-realm;
|
||||||
|
mx = cfg.mail-hosts;
|
||||||
|
dmarc-report-address = "dmarc-report@${dom}";
|
||||||
|
network-definition = import ../../networks/fudo.org.nix;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ in {
|
||||||
|
|
||||||
config.fudo = {
|
config.fudo = {
|
||||||
secrets.host-secrets.${hostname}.git-database-password = {
|
secrets.host-secrets.${hostname}.git-database-password = {
|
||||||
source-file = lib.fudo.passwd.stablerandom-passwd-file
|
source-file = pkgs.lib.fudo.passwd.stablerandom-passwd-file
|
||||||
"gitea-database-passwd"
|
"gitea-database-passwd"
|
||||||
"${hostname}-gitea-database-passwd-${config.instance.build-seed}";
|
"${hostname}-gitea-database-passwd-${config.instance.build-seed}";
|
||||||
target-file = "/var/gitea/database.passwd";
|
target-file = "/var/gitea/database.passwd";
|
||||||
|
@ -55,7 +55,7 @@ in {
|
||||||
|
|
||||||
postgresql = {
|
postgresql = {
|
||||||
databases.fudo_git.users =
|
databases.fudo_git.users =
|
||||||
config.instance.local_admins;
|
config.instance.local-admins;
|
||||||
|
|
||||||
users.fudo_git = {
|
users.fudo_git = {
|
||||||
password-file =
|
password-file =
|
||||||
|
|
|
@ -5,23 +5,23 @@ let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
cfg = config.fudo.france;
|
cfg = config.fudo.france.jabber;
|
||||||
|
|
||||||
generate-auth-file = name: files: let
|
generate-auth-file = name: files: let
|
||||||
make-entry = name: passwd-file:
|
make-entry = name: passwd-file:
|
||||||
''("${name}" . "${readFile passwd-file}")'';
|
''("${name}" . "${readFile passwd-file}")'';
|
||||||
entries = mapAttrsToList make-entry files;
|
entries = mapAttrsToList make-entry files;
|
||||||
content = concatStringsSep "\n" entries;
|
content = concatStringsSep "\n" entries;
|
||||||
in writeText "${name}-backplane-auth.scm" "'(${content})'";
|
in pkgs.writeText "${name}-backplane-auth.scm" "'(${content})";
|
||||||
|
|
||||||
host-auth-file = generate-auth-file "host" cfg.host-passwd-files;
|
host-auth-file = generate-auth-file "host" cfg.backplane.host-passwd-files;
|
||||||
service-auth-file = generate-auth-filre "service" cfg.service-passwd-files;
|
service-auth-file = generate-auth-file "service" cfg.backplane.service-passwd-files;
|
||||||
|
|
||||||
ldap-password-file =
|
ldap-password-file =
|
||||||
lib.fudo.passwd.random-passwd-file "ejabberd-ldap-auth-user";
|
pkgs.lib.fudo.passwd.random-passwd-file "ejabberd-ldap-auth-user" 30;
|
||||||
|
|
||||||
ldap-hashed-password =
|
ldap-hashed-password =
|
||||||
hash-ldap-passwd "ejabberd-ldap-hashed-passwd" ldap-password-file;
|
pkgs.lib.fudo.passwd.hash-ldap-passwd "ejabberd-ldap-hashed-passwd" ldap-password-file;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.france = with types; {
|
options.fudo.france = with types; {
|
||||||
|
@ -41,28 +41,28 @@ in {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
description = "IPs on which to listen for incoming connections.";
|
description = "IPs on which to listen for incoming connections.";
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
backplane = {
|
backplane = {
|
||||||
host-passwd-files = mkOption {
|
host-passwd-files = mkOption {
|
||||||
type = attrsOf str;
|
type = attrsOf str;
|
||||||
description = "Map of hostname to password file, for backplane host authentication.";
|
description = "Map of hostname to password file, for backplane host authentication.";
|
||||||
default = {};
|
default = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
service-passwd-files = mkOption {
|
service-passwd-files = mkOption {
|
||||||
type = attrsOf str;
|
type = attrsOf str;
|
||||||
description = "Map of service to password file, for backplane service authentication.";
|
description = "Map of service to password file, for backplane service authentication.";
|
||||||
default = {};
|
default = {};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
fudo = {
|
||||||
system-users.${cfg.jabber.ldap-user} = {
|
system-users.${cfg.ldap-user} = {
|
||||||
description = "ejabberd authentication user.";
|
description = "ejabberd authentication user.";
|
||||||
hashed-password = ldap-hashed-password;
|
ldap-hashed-password = ldap-hashed-password;
|
||||||
};
|
};
|
||||||
|
|
||||||
secrets.host-secrets.${hostname} = let
|
secrets.host-secrets.${hostname} = let
|
||||||
|
@ -88,7 +88,7 @@ in {
|
||||||
jabber = {
|
jabber = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
listen-ips = cfg.jabber.listen-ips;
|
listen-ips = cfg.listen-ips;
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
FUDO_HOST_PASSWD_FILE = secrets.host-auth.target-file;
|
FUDO_HOST_PASSWD_FILE = secrets.host-auth.target-file;
|
||||||
|
@ -103,9 +103,9 @@ in {
|
||||||
"fudo.im" = {
|
"fudo.im" = {
|
||||||
site-config = {
|
site-config = {
|
||||||
auth_method = "ldap";
|
auth_method = "ldap";
|
||||||
ldap_servers = cfg.jabber.ldap-servers;
|
ldap_servers = cfg.ldap-servers;
|
||||||
ldap_port = 389;
|
ldap_port = 389;
|
||||||
ldap_rootdn = "cn=${cfg.jabber.ldap-user},dc=fudo,dc=org";
|
ldap_rootdn = "cn=${cfg.ldap-user},dc=fudo,dc=org";
|
||||||
ldap_password = ''"LDAP_PASSWD"'';
|
ldap_password = ''"LDAP_PASSWD"'';
|
||||||
ldap_base = "ou=members,dc=fudo,dc=org";
|
ldap_base = "ou=members,dc=fudo,dc=org";
|
||||||
ldap_filter = "(objectClass=posixAccount)";
|
ldap_filter = "(objectClass=posixAccount)";
|
||||||
|
|
|
@ -5,6 +5,8 @@ let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
domain-name = config.instance.local-domain;
|
domain-name = config.instance.local-domain;
|
||||||
|
|
||||||
|
cfg = config.fudo.france.mail;
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
mail-reader-dn = "mail-auth-reader";
|
mail-reader-dn = "mail-auth-reader";
|
||||||
|
@ -26,35 +28,63 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config.fudo = {
|
config.fudo = let
|
||||||
system-users = {
|
mail-reader-password =
|
||||||
username = mail-reader-dn;
|
pkgs.lib.fudo.passwd.random-passwd-file "${mail-reader-dn}-ldap-password" 30;
|
||||||
|
in {
|
||||||
|
# This is used at build time...
|
||||||
|
# secrets.host-secrets.${hostname}.mail-reader-passwd = {
|
||||||
|
# source-file = ldap-password;
|
||||||
|
# target-file = "/run/mail/${mail-reader-dn}-ldap.passwd";
|
||||||
|
# user = config.services.dovecot2.user;
|
||||||
|
# };
|
||||||
|
|
||||||
|
system-users.${mail-reader-dn} = {
|
||||||
description = "Used by the mail server to connect to LDAP for auth.";
|
description = "Used by the mail server to connect to LDAP for auth.";
|
||||||
ldap-hashed-password =
|
ldap-hashed-password =
|
||||||
pkgs.lib.fudo.passwd.hash-ldap-passwd
|
pkgs.lib.fudo.passwd.hash-ldap-passwd
|
||||||
secrets.mail-reader-passwd.target-file;
|
"${mail-reader-dn}-hashed"
|
||||||
|
mail-reader-password;
|
||||||
};
|
};
|
||||||
|
|
||||||
mail-server = {
|
mail-server = let
|
||||||
|
mail-hostname = "mail.${domain-name}";
|
||||||
|
mail-ssl-dir = config.security.acme.certs.${mail-hostname}.directory;
|
||||||
|
ssl-certificate = "${mail-ssl-dir}/cert.pem";
|
||||||
|
ssl-private-key = "${mail-ssl-dir}/key.pem";
|
||||||
|
in {
|
||||||
enableContainer = true;
|
enableContainer = true;
|
||||||
monitoring = true;
|
monitoring = true;
|
||||||
|
|
||||||
domain = domain-name;
|
domain = domain-name;
|
||||||
mail-hostname = "mail.${domain-name}";
|
mail-hostname = "mail.${domain-name}";
|
||||||
|
|
||||||
|
trusted-networks = config.instance.local-networks;
|
||||||
|
|
||||||
dovecot = {
|
dovecot = {
|
||||||
ldap = {
|
ldap = {
|
||||||
reader-dn = "cn=${mail-reader-dn},${config.fudo.auth.ldap.base}";
|
reader-dn = "cn=${mail-reader-dn},${config.fudo.authentication.base}";
|
||||||
reader-password-file = secrets.mail-reader-passwd.target-file;
|
reader-password-file = mail-reader-password;
|
||||||
server-urls = cfg.ldap-server-urls;
|
server-urls = cfg.ldap-server-urls;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
user-aliases = let
|
||||||
|
aliased-users = filterAttrs
|
||||||
|
(username: userOpts: length userOpts.email-aliases > 0)
|
||||||
|
config.fudo.users;
|
||||||
|
in mapAttrs (username: userOpts: userOpts.email-aliases) aliased-users;
|
||||||
|
|
||||||
state-directory = cfg.state-directory;
|
state-directory = cfg.state-directory;
|
||||||
mail-directory = cfg.mail-directory;
|
mail-directory = cfg.mail-directory;
|
||||||
|
|
||||||
clamav.enable = true;
|
clamav.enable = true;
|
||||||
dkim.signing = true;
|
dkim.signing = true;
|
||||||
|
|
||||||
|
ssl = {
|
||||||
|
certificate = ssl-certificate;
|
||||||
|
private-key = ssl-private-key;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ with lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
cfg = config.fudo.france.postgresql;
|
||||||
in {
|
in {
|
||||||
options.fudo.france.postgresql = with types; {
|
options.fudo.france.postgresql = with types; {
|
||||||
ssl-certificate = mkOption {
|
ssl-certificate = mkOption {
|
||||||
|
|
|
@ -8,11 +8,10 @@ let
|
||||||
|
|
||||||
secrets = config.fudo.secrets.host-secrets.${hostname};
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
static = config.fudo.static;
|
# TODO: what should go here?
|
||||||
|
static = ../../../static;
|
||||||
|
|
||||||
mail-hostname = config.france.webmail.mail-server;
|
cfg = config.fudo.france.webmail;
|
||||||
|
|
||||||
db-host = config.france.webmail.database.hostname;
|
|
||||||
|
|
||||||
db-passwd = pkgs.lib.fudo.passwd.random-passwd-file "webmail" 40;
|
db-passwd = pkgs.lib.fudo.passwd.random-passwd-file "webmail" 40;
|
||||||
|
|
||||||
|
@ -39,12 +38,12 @@ in {
|
||||||
"webmail.fudo.link" = {
|
"webmail.fudo.link" = {
|
||||||
title = "Fudo Link Webmail";
|
title = "Fudo Link Webmail";
|
||||||
favicon = "${static}/fudo.link/favicon.ico";
|
favicon = "${static}/fudo.link/favicon.ico";
|
||||||
mail-server = mail-hostname;
|
mail-server = cfg.mail-server;
|
||||||
domain = "fudo.link";
|
domain = "fudo.link";
|
||||||
edit-mode = "Plain";
|
edit-mode = "Plain";
|
||||||
layout-mode = "bottom";
|
layout-mode = "bottom";
|
||||||
database = {
|
database = {
|
||||||
hostname = db-host;
|
hostname = cfg.database.hostname;
|
||||||
password-file = db-passwd;
|
password-file = db-passwd;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -52,11 +51,11 @@ in {
|
||||||
"webmail.test.fudo.org" = {
|
"webmail.test.fudo.org" = {
|
||||||
title = "Fudo Webmail";
|
title = "Fudo Webmail";
|
||||||
favicon = "${static}/fudo.org/favicon.ico";
|
favicon = "${static}/fudo.org/favicon.ico";
|
||||||
mail-server = mail-hostname;
|
mail-server = cfg.mail-server;
|
||||||
domain = "fudo.org";
|
domain = "fudo.org";
|
||||||
edit-mode = "Plain";
|
edit-mode = "Plain";
|
||||||
database = {
|
database = {
|
||||||
hostname = db-host;
|
hostname = cfg.database.hostname;
|
||||||
password-file = db-passwd;
|
password-file = db-passwd;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -64,11 +63,11 @@ in {
|
||||||
"webmail.fudo.org" = {
|
"webmail.fudo.org" = {
|
||||||
title = "Fudo Webmail";
|
title = "Fudo Webmail";
|
||||||
favicon = "${static}/fudo.org/favicon.ico";
|
favicon = "${static}/fudo.org/favicon.ico";
|
||||||
mail-server = mail-hostname;
|
mail-server = cfg.mail-server;
|
||||||
domain = "fudo.org";
|
domain = "fudo.org";
|
||||||
edit-mode = "Plain";
|
edit-mode = "Plain";
|
||||||
database = {
|
database = {
|
||||||
hostname = db-host;
|
hostname = cfg.database.hostname;
|
||||||
password-file = db-passwd;
|
password-file = db-passwd;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -76,10 +75,10 @@ in {
|
||||||
"webmail.test.selby.ca" = {
|
"webmail.test.selby.ca" = {
|
||||||
title = "Selby Webmail";
|
title = "Selby Webmail";
|
||||||
favicon = "${static}/selby.ca/favicon.ico";
|
favicon = "${static}/selby.ca/favicon.ico";
|
||||||
mail-server = mail-hostname;
|
mail-server = cfg.mail-server;
|
||||||
domain = "selby.ca";
|
domain = "selby.ca";
|
||||||
database = {
|
database = {
|
||||||
hostname = db-host;
|
hostname = cfg.database.hostname;
|
||||||
password-file = db-passwd;
|
password-file = db-passwd;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -87,10 +86,10 @@ in {
|
||||||
"webmail.selby.ca" = {
|
"webmail.selby.ca" = {
|
||||||
title = "Selby Webmail";
|
title = "Selby Webmail";
|
||||||
favicon = "${static}/selby.ca/favicon.ico";
|
favicon = "${static}/selby.ca/favicon.ico";
|
||||||
mail-server = mail-hostname;
|
mail-server = cfg.mail-server;
|
||||||
domain = "selby.ca";
|
domain = "selby.ca";
|
||||||
database = {
|
database = {
|
||||||
hostname = db-host;
|
hostname = cfg.database.hostname;
|
||||||
password-file = db-passwd;
|
password-file = db-passwd;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = "legatus";
|
||||||
|
host-ipv4 = "91.229.23.204";
|
||||||
|
domain-name = config.fudo.hosts.${hostname}.domain;
|
||||||
|
domain = config.fudo.domains.${domain-name};
|
||||||
|
site-name = config.fudo.hosts.${hostname}.site;
|
||||||
|
site = config.fudo.sites.${site-name};
|
||||||
|
host-fqdn = "${hostname}.${domain-name}";
|
||||||
|
|
||||||
|
local-packages = with pkgs; [ ldns.examples ];
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
in {
|
||||||
|
networking = {
|
||||||
|
enableIPv6 = true;
|
||||||
|
|
||||||
|
nameservers = [ "1.1.1.1" ];
|
||||||
|
defaultGateway = {
|
||||||
|
address = site.gateway-v4;
|
||||||
|
interface = "extif0";
|
||||||
|
};
|
||||||
|
|
||||||
|
interfaces.extif0.ipv4.addresses = [{
|
||||||
|
address = host-ipv4;
|
||||||
|
prefixLength = 24;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"L /etc/adjtime - - - - /state/etc/adjtime"
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.systemPackages = local-packages;
|
||||||
|
|
||||||
|
# networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
|
|
||||||
|
# informis.cl-gemini = {
|
||||||
|
# enable = true;
|
||||||
|
|
||||||
|
# hostname = "gemini.informis.land";
|
||||||
|
# server-ip = host-ipv4;
|
||||||
|
# document-root = "/srv/gemini/root";
|
||||||
|
# textfiles-archive = "${pkgs.textfiles}";
|
||||||
|
# slynk-port = 4005;
|
||||||
|
|
||||||
|
# feeds = {
|
||||||
|
# viator = {
|
||||||
|
# title = "viator's phlog";
|
||||||
|
# path = "/home/viator/gemini-public/feed/";
|
||||||
|
# url = "gemini://informis.land/user/viator/feed/";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
fudo = {
|
||||||
|
hosts.legatus.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
|
# secrets.host-secrets.procul = let
|
||||||
|
# files = config.fudo.secrets.files;
|
||||||
|
# in {
|
||||||
|
# postgres-keytab = {
|
||||||
|
# source-file = files.service-keytabs.procul.postgres;
|
||||||
|
# target-file = "/srv/postgres/secure/postgres.keytab";
|
||||||
|
# user = "root";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# gitea-database-password = {
|
||||||
|
# source-file = files.service-passwords.procul.gitea-database;
|
||||||
|
# target-file = "/srv/gitea/secure/database.passwd";
|
||||||
|
# user = config.fudo.git.user;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# client.dns = {
|
||||||
|
# enable = true;
|
||||||
|
# ipv4 = true;
|
||||||
|
# ipv6 = true;
|
||||||
|
# user = "fudo-client";
|
||||||
|
# external-interface = "extif0";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# auth.kdc = {
|
||||||
|
# enable = true;
|
||||||
|
# realm = "INFORMIS.LAND";
|
||||||
|
# bind-addresses = [ host-ipv4 "127.0.0.1" ];
|
||||||
|
# acl = {
|
||||||
|
# "niten" = { perms = [ "add" "change-password" "list" ]; };
|
||||||
|
# "*/root" = { perms = [ "all" ]; };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# secure-dns-proxy = {
|
||||||
|
# enable = true;
|
||||||
|
# upstream-dns =
|
||||||
|
# [ "https://1.1.1.1/dns-query" "https://1.0.0.1/dns-query" ];
|
||||||
|
# bootstrap-dns = "1.1.1.1";
|
||||||
|
# listen-ips = [ "127.0.0.1" ];
|
||||||
|
# listen-port = 53;
|
||||||
|
# allowed-networks = [ "1.1.1.1/32" "1.0.0.1/32" "localhost" "link-local" ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# dns = {
|
||||||
|
# enable = true;
|
||||||
|
# identity = "procul.informis.land";
|
||||||
|
# nameservers = {
|
||||||
|
# ns1 = {
|
||||||
|
# ipv4-address = host-ipv4;
|
||||||
|
# description = "Primary Informis Nameserver";
|
||||||
|
# };
|
||||||
|
# ns2 = {
|
||||||
|
# ipv4-address = host-ipv4;
|
||||||
|
# description = "Secondary Informis Nameserver";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# listen-ips = [ host-ipv4 ];
|
||||||
|
|
||||||
|
# domains = {
|
||||||
|
# "informis.land" = {
|
||||||
|
# dnssec = true;
|
||||||
|
# default-host = host-ipv4;
|
||||||
|
# gssapi-realm = "INFORMIS.LAND";
|
||||||
|
# mx = [ "smtp.informis.land" ];
|
||||||
|
# network-definition = config.fudo.networks."informis.land";
|
||||||
|
# dmarc-report-address = "dmarc-report@informis.land";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# mail-server = {
|
||||||
|
# enable = true;
|
||||||
|
# debug = true;
|
||||||
|
|
||||||
|
# domain = domain-name;
|
||||||
|
# mail-hostname = "${host-fqdn}";
|
||||||
|
# monitoring = false;
|
||||||
|
# mail-user = "mailuser";
|
||||||
|
# mail-user-id = 525;
|
||||||
|
# mail-group = "mailgroup";
|
||||||
|
# clamav.enable = true;
|
||||||
|
# dkim.signing = true;
|
||||||
|
|
||||||
|
# dovecot = {
|
||||||
|
# ssl-certificate = acme-certificate "imap.${domain-name}";
|
||||||
|
# ssl-private-key = acme-private-key "imap.${domain-name}";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# postfix = {
|
||||||
|
# ssl-certificate = acme-certificate "smtp.${domain-name}";
|
||||||
|
# ssl-private-key = acme-private-key "smtp.${domain-name}";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# # This should NOT include the primary domain
|
||||||
|
# local-domains = [ host-fqdn "smtp.${domain-name}" ];
|
||||||
|
|
||||||
|
# mail-directory = "/srv/mailserver/mail";
|
||||||
|
# state-directory = "/srv/mailserver/state";
|
||||||
|
|
||||||
|
# trusted-networks = [ "172.86.179.16/29" "127.0.0.0/16" ];
|
||||||
|
|
||||||
|
# alias-users = {
|
||||||
|
# root = [ "niten" ];
|
||||||
|
# postmaster = [ "niten" ];
|
||||||
|
# hostmaster = [ "niten" ];
|
||||||
|
# webmaster = [ "niten" ];
|
||||||
|
# system = [ "niten" ];
|
||||||
|
# admin = [ "niten" ];
|
||||||
|
# dmarc-report = [ "niten" ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# postgresql = {
|
||||||
|
# enable = true;
|
||||||
|
# ssl-certificate = (acme-certificate host-fqdn);
|
||||||
|
# ssl-private-key = (acme-private-key host-fqdn);
|
||||||
|
# keytab = secrets.postgres-keytab.target-file;
|
||||||
|
# local-networks = local-networks;
|
||||||
|
|
||||||
|
# users = {
|
||||||
|
# gituser = {
|
||||||
|
# password-file =
|
||||||
|
# secrets.gitea-database-password.target-file;
|
||||||
|
# databases = {
|
||||||
|
# git = {
|
||||||
|
# access = "CONNECT";
|
||||||
|
# entity-access = {
|
||||||
|
# "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
# "ALL SEQUENCES IN SCHEMA public" = "SELECT, UPDATE";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# databases = { git = { users = [ "niten" ]; }; };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# git = {
|
||||||
|
# enable = true;
|
||||||
|
# hostname = "git.informis.land";
|
||||||
|
# site-name = "informis git";
|
||||||
|
# user = "gituser";
|
||||||
|
# repository-dir = /srv/git/repo;
|
||||||
|
# state-dir = /srv/git/state;
|
||||||
|
# database = {
|
||||||
|
# user = "gituser";
|
||||||
|
# password-file =
|
||||||
|
# secrets.gitea-database-password.target-file;
|
||||||
|
# hostname = "127.0.0.1";
|
||||||
|
# name = "git";
|
||||||
|
# };
|
||||||
|
# ssh = {
|
||||||
|
# listen-ip = host-ipv4;
|
||||||
|
# listen-port = 2222;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# acme = {
|
||||||
|
# enable = true;
|
||||||
|
# admin-address = "admin@${domain-name}";
|
||||||
|
# hostnames = [
|
||||||
|
# "informis.land"
|
||||||
|
# "imap.informis.land"
|
||||||
|
# "smtp.informis.land"
|
||||||
|
# "gemini.informis.land"
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -50,11 +50,12 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo.ipfs = {
|
## Until I can figure out how to use one common host API, forget this
|
||||||
enable = true;
|
# fudo.ipfs = {
|
||||||
users = [ "niten" ];
|
# enable = true;
|
||||||
api-address = "/ip4/0.0.0.0/tcp/5001";
|
# users = [ "niten" ];
|
||||||
};
|
# api-address = "/ip4/0.0.0.0/tcp/5001";
|
||||||
|
# };
|
||||||
|
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
libvirtd = {
|
libvirtd = {
|
||||||
|
|
|
@ -164,7 +164,7 @@ in {
|
||||||
debug = true;
|
debug = true;
|
||||||
|
|
||||||
domain = domain-name;
|
domain = domain-name;
|
||||||
hostname = "${host-fqdn}";
|
mail-hostname = "${host-fqdn}";
|
||||||
monitoring = false;
|
monitoring = false;
|
||||||
mail-user = "mailuser";
|
mail-user = "mailuser";
|
||||||
mail-user-id = 525;
|
mail-user-id = 525;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
description = "informis.land server.";
|
||||||
|
rp = "niten";
|
||||||
|
admin-email = "niten@fudo.org";
|
||||||
|
domain = "eur.fudo.org";
|
||||||
|
site = "worldstream";
|
||||||
|
profile = "server";
|
||||||
|
tmp-on-tmpfs = false;
|
||||||
|
enable-gui = false;
|
||||||
|
arch = "x86_64-linux";
|
||||||
|
nixos-system = true;
|
||||||
|
machine-id = "749bbf411088411b8784b76bb44bd617";
|
||||||
|
master-key = {
|
||||||
|
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIqUnzf8bfPyoJX6XjFqD6v5MZQnV8STP0152VS3uwM7";
|
||||||
|
key-path = "/state/master-key/ed25519_key";
|
||||||
|
};
|
||||||
|
# initrd-network = {
|
||||||
|
# ip = "172.86.179.18";
|
||||||
|
# interface = "enp0s25";
|
||||||
|
# keypair = {
|
||||||
|
# public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIgvl/pxPGN5XuUFsEywHV/PJMI+wPHA6NKTtE8SZC04";
|
||||||
|
# private-key-file = "/state/ssh/initrd/ssh_ed25519_key";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
description = "Fudo mailserver container";
|
||||||
|
rp = "admin";
|
||||||
|
admin-email = "admin@fudo.org";
|
||||||
|
domain = "fudo.org";
|
||||||
|
site = "portage";
|
||||||
|
profile = "container";
|
||||||
|
arch = "x86_64-linux";
|
||||||
|
machine-id = "5a907f8cf2644b0ba5a786fd45b758b3";
|
||||||
|
nixos-system = false;
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
description = "informis.land server.";
|
description = "informis.land server.";
|
||||||
docker-server = true;
|
docker-server = true;
|
||||||
rp = "niten";
|
rp = "viator";
|
||||||
admin-email = "niten@fudo.org";
|
admin-email = "viator@fudo.org";
|
||||||
domain = "informis.land";
|
domain = "informis.land";
|
||||||
site = "joes-datacenter-0";
|
site = "joes-datacenter-0";
|
||||||
profile = "server";
|
profile = "server";
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
config.fudo.networks = {
|
config.fudo.networks = {
|
||||||
|
"fudo.org" = import ./networks/fudo.org.nix;
|
||||||
"rus.selby.ca" = import ./networks/rus.selby.ca.nix;
|
"rus.selby.ca" = import ./networks/rus.selby.ca.nix;
|
||||||
"sea.fudo.org" = import ./networks/sea.fudo.org.nix;
|
"sea.fudo.org" = import ./networks/sea.fudo.org.nix;
|
||||||
"informis.land" = import ./networks/informis.land.nix;
|
"informis.land" = import ./networks/informis.land.nix;
|
||||||
|
"eur.fudo.org" = import ./networks/eur.fudo.org.nix;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
mx = [ "mail.fudo.org" ];
|
||||||
|
|
||||||
|
hosts = {
|
||||||
|
legatus.ipv4-address = "91.229.23.204";
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,8 +1,4 @@
|
||||||
{
|
{
|
||||||
mx = [ "mail.fudo.org" ];
|
|
||||||
|
|
||||||
default-host = "208.81.3.117";
|
|
||||||
|
|
||||||
aliases = {
|
aliases = {
|
||||||
pop = "mail.fudo.org.";
|
pop = "mail.fudo.org.";
|
||||||
smtp = "mail.fudo.org.";
|
smtp = "mail.fudo.org.";
|
||||||
|
@ -27,13 +23,11 @@
|
||||||
wiki = "hanover.fudo.org.";
|
wiki = "hanover.fudo.org.";
|
||||||
};
|
};
|
||||||
|
|
||||||
extra-dns-records = [
|
verbatim-dns-records = [
|
||||||
''@ IN TXT "v=spf1 mx ip4:208.81.3.112/28 ip6:2605:e200:d200::1/48 -all"''
|
''@ IN TXT "v=spf1 mx ip4:208.81.3.112/28 ip6:2605:e200:d200::1/48 -all"''
|
||||||
''@ IN SPF "v=spf1 mx ip4:208.81.3.112/28 ip6:2605:e200:d200::1/48 -all"''
|
''@ IN SPF "v=spf1 mx ip4:208.81.3.112/28 ip6:2605:e200:d200::1/48 -all"''
|
||||||
];
|
];
|
||||||
|
|
||||||
dmarc-report-address = "dmarc-report@fudo.org";
|
|
||||||
|
|
||||||
srv-records = {
|
srv-records = {
|
||||||
tcp = {
|
tcp = {
|
||||||
domain = [
|
domain = [
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||||
|
in {
|
||||||
|
config.instance = mkIf has-secret-files {
|
||||||
|
build-seed = builtins.readFile config.fudo.secrets.files.build-seed;
|
||||||
|
};
|
||||||
|
}
|
|
@ -14,131 +14,154 @@ let
|
||||||
wget
|
wget
|
||||||
];
|
];
|
||||||
|
|
||||||
|
import-paths = [
|
||||||
|
./build
|
||||||
|
./host
|
||||||
|
./user
|
||||||
|
];
|
||||||
|
|
||||||
in {
|
in {
|
||||||
environment = {
|
|
||||||
etc.nixos-live.source = ../../.;
|
|
||||||
|
|
||||||
systemPackages = global-packages;
|
imports = let
|
||||||
|
is-regular-file = filename: type: type == "regular" || type == "link";
|
||||||
|
regular-files = path:
|
||||||
|
attrNames (filterAttrs is-regular-file (builtins.readDir path));
|
||||||
|
is-nix-file = filename: (builtins.match "^(.+)\.nix$" filename) != null;
|
||||||
|
nix-files = path:
|
||||||
|
map
|
||||||
|
(file: path + "/${file}")
|
||||||
|
(filter is-nix-file (regular-files path));
|
||||||
|
in concatMap nix-files import-paths;
|
||||||
|
|
||||||
# shellInit = ''
|
config = {
|
||||||
# ${pkgs.gnupg}/bin/gpg-connect-agent /bye
|
environment = {
|
||||||
# export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)
|
etc.nixos-live.source = ../../.;
|
||||||
# '';
|
|
||||||
};
|
|
||||||
|
|
||||||
system.autoUpgrade.enable = false;
|
systemPackages = global-packages;
|
||||||
|
|
||||||
nix = {
|
# shellInit = ''
|
||||||
package = pkgs.nixFlakes;
|
# ${pkgs.gnupg}/bin/gpg-connect-agent /bye
|
||||||
extraOptions = ''
|
# export SSH_AUTH_SOCK=$(${pkgs.gnupg}/bin/gpgconf --list-dirs agent-ssh-socket)
|
||||||
|
# '';
|
||||||
|
};
|
||||||
|
|
||||||
|
system.autoUpgrade.enable = false;
|
||||||
|
|
||||||
|
nix = {
|
||||||
|
package = pkgs.nixFlakes;
|
||||||
|
extraOptions = ''
|
||||||
experimental-features = nix-command flakes
|
experimental-features = nix-command flakes
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
security.acme.acceptTerms = true;
|
|
||||||
hardware.enableRedistributableFirmware = true;
|
|
||||||
|
|
||||||
krb5 = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
appdefaults = {
|
|
||||||
forwardable = true;
|
|
||||||
proxiable = true;
|
|
||||||
encrypt = true;
|
|
||||||
forward = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
libdefaults = {
|
nixpkgs.config.allowUnfree = true;
|
||||||
allow_weak_crypto = true;
|
security.acme.acceptTerms = true;
|
||||||
dns_lookup_kdc = true;
|
hardware.enableRedistributableFirmware = true;
|
||||||
dns_lookup_realm = true;
|
|
||||||
forwardable = true;
|
|
||||||
proxiable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
kerberos = pkgs.heimdalFull;
|
krb5 = {
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
openssh = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
startWhenNeeded = true;
|
|
||||||
useDns = true;
|
appdefaults = {
|
||||||
permitRootLogin = "prohibit-password";
|
forwardable = true;
|
||||||
extraConfig = ''
|
proxiable = true;
|
||||||
|
encrypt = true;
|
||||||
|
forward = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
libdefaults = {
|
||||||
|
allow_weak_crypto = true;
|
||||||
|
dns_lookup_kdc = true;
|
||||||
|
dns_lookup_realm = true;
|
||||||
|
forwardable = true;
|
||||||
|
proxiable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
kerberos = pkgs.heimdalFull;
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
openssh = {
|
||||||
|
enable = true;
|
||||||
|
startWhenNeeded = true;
|
||||||
|
useDns = true;
|
||||||
|
permitRootLogin = "prohibit-password";
|
||||||
|
extraConfig = ''
|
||||||
GSSAPIAuthentication yes
|
GSSAPIAuthentication yes
|
||||||
GSSAPICleanupCredentials yes
|
GSSAPICleanupCredentials yes
|
||||||
GSSAPIKeyExchange yes
|
GSSAPIKeyExchange yes
|
||||||
GSSAPIStoreCredentialsOnRekey yes
|
GSSAPIStoreCredentialsOnRekey yes
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
fail2ban = let
|
||||||
|
domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
|
||||||
|
in {
|
||||||
|
enable = config.networking.firewall.enable;
|
||||||
|
bantime-increment.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
xserver = {
|
||||||
|
layout = "us";
|
||||||
|
xkbVariant = "dvp";
|
||||||
|
xkbOptions = "ctrl:nocaps";
|
||||||
|
};
|
||||||
|
|
||||||
|
# pcscd.enable = true;
|
||||||
|
# udev.packages = with pkgs; [ yubikey-personalization ];
|
||||||
};
|
};
|
||||||
|
|
||||||
fail2ban = let
|
networking.firewall = {
|
||||||
domain-name = config.fudo.hosts.${config.instance.hostname}.domain;
|
# Allow mosh connections if the firewall is enabled
|
||||||
in {
|
allowedUDPPortRanges = [{
|
||||||
enable = config.networking.firewall.enable;
|
from = 60000;
|
||||||
bantime-increment.enable = true;
|
to = 60100;
|
||||||
ignoreIP = config.instance.local-networks;
|
}];
|
||||||
};
|
};
|
||||||
|
|
||||||
xserver = {
|
console.useXkbConfig = true;
|
||||||
layout = "us";
|
|
||||||
xkbVariant = "dvp";
|
|
||||||
xkbOptions = "ctrl:nocaps";
|
|
||||||
};
|
|
||||||
|
|
||||||
# pcscd.enable = true;
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
# udev.packages = with pkgs; [ yubikey-personalization ];
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall = {
|
programs = {
|
||||||
# Allow mosh connections if the firewall is enabled
|
mosh.enable = true;
|
||||||
allowedUDPPortRanges = [{
|
|
||||||
from = 60000;
|
|
||||||
to = 60100;
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
|
|
||||||
console.useXkbConfig = true;
|
bash.enableCompletion = true;
|
||||||
|
|
||||||
i18n.defaultLocale = "en_US.UTF-8";
|
fish.enable = true;
|
||||||
|
|
||||||
programs = {
|
gnupg.agent = {
|
||||||
mosh.enable = true;
|
enable = true;
|
||||||
|
# enableSSHSupport = true;
|
||||||
|
# pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses";
|
||||||
|
};
|
||||||
|
|
||||||
bash.enableCompletion = true;
|
ssh = {
|
||||||
|
startAgent = true;
|
||||||
|
|
||||||
fish.enable = true;
|
package = pkgs.openssh_gssapi;
|
||||||
|
|
||||||
gnupg.agent = {
|
extraConfig = ''
|
||||||
enable = true;
|
|
||||||
# enableSSHSupport = true;
|
|
||||||
# pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses";
|
|
||||||
};
|
|
||||||
|
|
||||||
ssh = {
|
|
||||||
startAgent = true;
|
|
||||||
|
|
||||||
package = pkgs.openssh_gssapi;
|
|
||||||
|
|
||||||
extraConfig = ''
|
|
||||||
GSSAPIAuthentication yes
|
GSSAPIAuthentication yes
|
||||||
GSSAPIDelegateCredentials yes
|
GSSAPIDelegateCredentials yes
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
security.pam = {
|
|
||||||
enableSSHAgentAuth = true;
|
|
||||||
|
|
||||||
services = {
|
|
||||||
sshd = {
|
|
||||||
makeHomeDir = true;
|
|
||||||
sshAgentAuth = true;
|
|
||||||
# This isn't supposed to ask for a code unless ~/.google_authenticator exists...but it does
|
|
||||||
# googleAuthenticator.enable = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
security.pam = {
|
||||||
|
enableSSHAgentAuth = true;
|
||||||
|
|
||||||
|
services = {
|
||||||
|
sshd = {
|
||||||
|
makeHomeDir = true;
|
||||||
|
sshAgentAuth = true;
|
||||||
|
# This isn't supposed to ask for a code unless ~/.google_authenticator exists...but it does
|
||||||
|
# googleAuthenticator.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
home-manager = {
|
||||||
|
useGlobalPkgs = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
host-cfg = config.fudo.hosts.${hostname};
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
in {
|
||||||
|
config.fudo = {
|
||||||
|
secrets.host-secrets.${hostname} = {
|
||||||
|
backplane-passwd = {
|
||||||
|
source-file = host-cfg.backplane-password-file;
|
||||||
|
target-file = "/run/backplane/client/passwd";
|
||||||
|
user = config.fudo.client.dns.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
client.dns.password-file =
|
||||||
|
secrets.backplane-passwd.target-file;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||||
|
try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
|
||||||
|
|
||||||
|
in {
|
||||||
|
config = mkIf has-secret-files {
|
||||||
|
fudo.secrets.host-secrets.${hostname} = let
|
||||||
|
keytab-file = try-attr hostname config.fudo.secrets.files.host-keytabs;
|
||||||
|
in mkIf (keytab-file != null) {
|
||||||
|
host-keytab = {
|
||||||
|
source-file = keytab-file;
|
||||||
|
target-file = "/etc/krb5.keytab";
|
||||||
|
user = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
has-attrs = set: length (attrNames set) > 0;
|
||||||
|
read-lines = filename: splitString "\n" (fileContents filename);
|
||||||
|
has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||||
|
|
||||||
|
in {
|
||||||
|
config = mkIf has-secret-files
|
||||||
|
(let
|
||||||
|
host-keypairs =
|
||||||
|
if (hasAttr hostname config.fudo.secrets.files.host-ssh-keypairs) then
|
||||||
|
config.fudo.secrets.files.host-ssh-keypairs.${hostname}
|
||||||
|
else [];
|
||||||
|
|
||||||
|
in {
|
||||||
|
fudo = let
|
||||||
|
sshfp-filename = host: keypair: "ssh-${host}-${keypair.key-type}.sshfp-record";
|
||||||
|
|
||||||
|
dns-sshfp-records = host: keypair:
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${host}-sshfp-records";
|
||||||
|
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [ openssh ];
|
||||||
|
|
||||||
|
installPhase =
|
||||||
|
"ssh-keygen -r REMOVEME -f \"${keypair.public-key}\" | sed 's/^REMOVEME IN SSHFP //' > $out";
|
||||||
|
};
|
||||||
|
|
||||||
|
host-cfg = config.fudo.hosts.${hostname};
|
||||||
|
in {
|
||||||
|
secrets.host-secrets.${hostname} = listToAttrs
|
||||||
|
(map
|
||||||
|
(keypair: nameValuePair "host-${keypair.key-type}-private-key" {
|
||||||
|
source-file = keypair.private-key;
|
||||||
|
target-file = "/var/run/ssh/private/host-${keypair.key-type}-private-key";
|
||||||
|
user = "root";
|
||||||
|
})
|
||||||
|
host-keypairs);
|
||||||
|
|
||||||
|
hosts = mkIf (hasAttr "files" config.fudo.secrets)
|
||||||
|
(mapAttrs (hostname: keypairs: {
|
||||||
|
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
|
||||||
|
ssh-fingerprints = concatMap (keypair:
|
||||||
|
let
|
||||||
|
fingerprint-derivation = dns-sshfp-records hostname keypair;
|
||||||
|
in read-lines "${fingerprint-derivation}") keypairs;
|
||||||
|
}) config.fudo.secrets.files.host-ssh-keypairs);
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh.hostKeys = map (keypair: {
|
||||||
|
path = "/var/run/ssh/private/host-${keypair.key-type}-private-key";
|
||||||
|
type = keypair.key-type;
|
||||||
|
}) host-keypairs;
|
||||||
|
});
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ in {
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
environment = {
|
environment = {
|
||||||
serverPackages = with pkgs;
|
systemPackages = with pkgs;
|
||||||
[ emacs-nox reboot-if-necessary test-config ];
|
[ emacs-nox reboot-if-necessary test-config ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
ipfs-cfg = config.fudo.ipfs;
|
||||||
|
site-name = config.instance.site;
|
||||||
|
site = config.site.${site-name};
|
||||||
|
|
||||||
|
in {
|
||||||
|
config = {
|
||||||
|
home-manager.users = mapAttrs
|
||||||
|
(user: userOpts: {
|
||||||
|
home.sessionVariables.IPFS_PATH = ipfs-cfg.data-dir;
|
||||||
|
}) config.instance.local-users;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
list-contains = lst: item: any (i: i == item) lst;
|
||||||
|
|
||||||
|
domain-realm = domain: domainOpts: domainOpts.gssapi-realm;
|
||||||
|
|
||||||
|
user-realms = username:
|
||||||
|
mapAttrsToList domain-realm
|
||||||
|
(filterAttrs
|
||||||
|
(domain: domainOpts:
|
||||||
|
list-contains domainOpts.local-users username)
|
||||||
|
config.fudo.domains);
|
||||||
|
|
||||||
|
admin-realms = username:
|
||||||
|
mapAttrsToList domain-realm
|
||||||
|
(filterAttrs
|
||||||
|
(domain: domainOpts:
|
||||||
|
list-contains domainOpts.local-admins username)
|
||||||
|
config.fudo.domains);
|
||||||
|
|
||||||
|
user-principals = username: let
|
||||||
|
user-princs = map (realm: "${username}@${realm}") (user-realms username);
|
||||||
|
admin-princs = map (realm: "${username}/root@${realm}") (admin-realms username);
|
||||||
|
in user-princs ++ admin-princs;
|
||||||
|
|
||||||
|
user-k5login = principals: concatStringsSep "\n" principals;
|
||||||
|
|
||||||
|
user-config = username: userOpts: {
|
||||||
|
home.file.".k5login".text =
|
||||||
|
user-k5login (user-principals username);
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
config = {
|
||||||
|
home-manager.users = let
|
||||||
|
user-configs =
|
||||||
|
mapAttrs user-config config.instance.local-users;
|
||||||
|
root-config = {
|
||||||
|
root = let
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
realm = config.fudo.domains.${domain-name}.gssapi-realm;
|
||||||
|
principals = map (admin: "${admin}/root@${realm}")
|
||||||
|
config.instance.local-admins;
|
||||||
|
in {
|
||||||
|
home.file.".k5login".text =
|
||||||
|
user-k5login principals;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in user-configs // root-config;
|
||||||
|
};
|
||||||
|
}
|
|
@ -3,16 +3,16 @@
|
||||||
let local-domain = "sea.fudo.org";
|
let local-domain = "sea.fudo.org";
|
||||||
in {
|
in {
|
||||||
fileSystems = {
|
fileSystems = {
|
||||||
"/mnt/documents" = {
|
# "/mnt/documents" = {
|
||||||
device = "whitedwarf.${local-domain}:/volume1/Documents";
|
# device = "whitedwarf.${local-domain}:/volume1/Documents";
|
||||||
fsType = "nfs4";
|
# fsType = "nfs4";
|
||||||
options = [ "comment=systemd.automount" ];
|
# options = [ "comment=systemd.automount" ];
|
||||||
};
|
# };
|
||||||
"/mnt/downloads" = {
|
# "/mnt/downloads" = {
|
||||||
device = "whitedwarf.${local-domain}:/volume1/Downloads";
|
# device = "whitedwarf.${local-domain}:/volume1/Downloads";
|
||||||
fsType = "nfs4";
|
# fsType = "nfs4";
|
||||||
options = [ "comment=systemd.automount" ];
|
# options = [ "comment=systemd.automount" ];
|
||||||
};
|
# };
|
||||||
"/mnt/music" = {
|
"/mnt/music" = {
|
||||||
device = "doraemon.${local-domain}:/volume1/Music";
|
device = "doraemon.${local-domain}:/volume1/Music";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
|
|
|
@ -59,5 +59,17 @@
|
||||||
];
|
];
|
||||||
mail-server = "mail.informis.land";
|
mail-server = "mail.informis.land";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
worldstream = {
|
||||||
|
gateway-v4 = "91.229.23.204";
|
||||||
|
network = "91.229.23.0/24";
|
||||||
|
nameservers = [ "1.1.1.1" "2606:4700:4700::1111" ];
|
||||||
|
timezone = "Europe/Amsterdam";
|
||||||
|
deploy-pubkeys = [
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDPwh522lvafTJYA0X2uFdP7Ws+Um1f8gZsARK1Y5nMzf6ZcWBF1jplTOKUVSOl4isMWni0Tu0TnX4zqCcgocWUVbwIwXSIRYqdiCPvVOH+/Ibc97n1/dYxk5JPMtbrsEw6/gWZxVg0qwe0J3dQWldEMiDY7iWhlrmIr7YL+Y3PUd7DOwp3PbfWfNyzTfE1kXcz5YvTeN+txFhbbXT0oS2R2wtc1vYXFZ/KbNstjqd+i8jszAq3ZkbbwL3aNR0RO4n8+GoIILGw8Ya4eP7D6+mYk608IhAoxpGyMrUch2TC2uvOK3rd/rw1hsTxf4AKjAZbrfd/FJaYru9ZeoLjD4bRGMdVp56F1m7pLvRiWRK62pV2Q/fjx+4KjHUrgyPd601eUIP0ayS/Rfuq8ijLpBJgO5/Y/6mFus/kjZIfRR9dXfLM67IMpyEzEITYrc/R2sedWf+YHxSh6eguAZ/kLzioar1nHLR7Wzgeu0tgWkD78WQGjpXGoefAz3xHeBg3Et0="
|
||||||
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGVez4of30f+j0cWKj5kYCKeFjyNsYvG9UbOMxF5hImD2lP5MSbFBv31gFgHjx3yCG4zQRZlpuyU5uWo0qIwe9N84/LcZcB9WrWKZXDmuof7zPFy0J+Hj+LVLDQI/mVXHNwkMhBMHpPrdwA05EYDAYCYklWT4cSByu10pHtST+olF8i+A+UQgUzgNZzdJVeiYZv6MBDTYsJWptGeDUkl2B0Es3gtbGYcCCfnyS3RC7DIXlDo3NBbAr7WaHY2MBbT+R/+jicn9E3IY3NCM5jENxqmvHy9MDsxEEYgFNm7IDwq4V1VRUWy277YsvRbmEaHb+osOA5u1VNN4z3UftOZcSZgR5C/vR71cENXoPt1YQpCzu7i38ojtvL+tDVEKT7sIovrQw8q1sszNlW2nXh8RSPiIq5TMnrV73MP0egKcr9n3tfxwi1BIkLjvfom/02BkTK9R9v+VMNhYU1YwROhORCiMIgoxUGiUvtH8u38JGr7E0hhMoAjCE5k80WPUivl0="
|
||||||
|
];
|
||||||
|
mail-server = "mail.fudo.org";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,20 @@ in {
|
||||||
"niten/root@RUS.SELBY.CA"
|
"niten/root@RUS.SELBY.CA"
|
||||||
];
|
];
|
||||||
email = "niten@fudo.org";
|
email = "niten@fudo.org";
|
||||||
|
email-aliases = [
|
||||||
|
"ertian@fudo.org"
|
||||||
|
"peter@fudo.org"
|
||||||
|
"peter@fudo.link"
|
||||||
|
"pselby@fudo.org"
|
||||||
|
"yiliu@fudo.org"
|
||||||
|
"forum@selby.ca"
|
||||||
|
|
||||||
|
"peter@selby.ca"
|
||||||
|
|
||||||
|
# Used to create spotify accounts for Google Home & Tesla
|
||||||
|
"tesla@fudo.org"
|
||||||
|
"seattle-home@fudo.org"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
andrew = {
|
andrew = {
|
||||||
|
@ -99,6 +113,7 @@ in {
|
||||||
ldap-hashed-passwd = "{SSHA}YvtkEpqsReXcMdrzlui/ZmhIUKN42YO1";
|
ldap-hashed-passwd = "{SSHA}YvtkEpqsReXcMdrzlui/ZmhIUKN42YO1";
|
||||||
login-hashed-passwd =
|
login-hashed-passwd =
|
||||||
"$6$EwK9fpbH8$gYVzYY1IYw2/G0wCeUxXrZZqvjWCkCZbBqCOhxowbMuYtC5G0vp.AoYhVKWOJcHJM2c7TdPmAdnhLIe2KYStf.";
|
"$6$EwK9fpbH8$gYVzYY1IYw2/G0wCeUxXrZZqvjWCkCZbBqCOhxowbMuYtC5G0vp.AoYhVKWOJcHJM2c7TdPmAdnhLIe2KYStf.";
|
||||||
|
email-aliases = [ "kselby@selby.ca" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
reaper = {
|
reaper = {
|
||||||
|
@ -112,6 +127,12 @@ in {
|
||||||
k5login =
|
k5login =
|
||||||
[ "reaper@FUDO.ORG" "reaper/root@FUDO.ORG" "reaper/admin@FUDO.ORG" ];
|
[ "reaper@FUDO.ORG" "reaper/root@FUDO.ORG" "reaper/admin@FUDO.ORG" ];
|
||||||
email = "reaper@fudo.org";
|
email = "reaper@fudo.org";
|
||||||
|
email-aliases = [
|
||||||
|
"cricket@fudo.org"
|
||||||
|
"jstewart@fudo.org"
|
||||||
|
"jonathan@fudo.org"
|
||||||
|
"reaper@fudo.link"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
slickoil = {
|
slickoil = {
|
||||||
|
@ -133,6 +154,7 @@ in {
|
||||||
primary-group = "fudo";
|
primary-group = "fudo";
|
||||||
common-name = "Mark Swaffer";
|
common-name = "Mark Swaffer";
|
||||||
ldap-hashed-passwd = "{MD5}C5gIsLsaKSvIPydu4uzhNg==";
|
ldap-hashed-passwd = "{MD5}C5gIsLsaKSvIPydu4uzhNg==";
|
||||||
|
email-aliases = [ "mark@fudo.org" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
brian = {
|
brian = {
|
||||||
|
@ -192,6 +214,13 @@ in {
|
||||||
login-hashed-passwd =
|
login-hashed-passwd =
|
||||||
"$6$C8lYHrK7KvdKm/RE$cHZ2hg5gEOEjTV8Zoayik8sz5h.Vh0.ClCgOlQn8l/2Qx/qdxqZ7xCsAZ1GZ.IEyESfhJeJbjLpykXDwPpfVF0";
|
"$6$C8lYHrK7KvdKm/RE$cHZ2hg5gEOEjTV8Zoayik8sz5h.Vh0.ClCgOlQn8l/2Qx/qdxqZ7xCsAZ1GZ.IEyESfhJeJbjLpykXDwPpfVF0";
|
||||||
email = "xiaoxuan@fudo.org";
|
email = "xiaoxuan@fudo.org";
|
||||||
|
email-aliases = [
|
||||||
|
"xixi@fudo.org"
|
||||||
|
"claire@fudo.org"
|
||||||
|
|
||||||
|
"xixi@selby.ca"
|
||||||
|
"claire@selby.ca"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
thibor = {
|
thibor = {
|
||||||
|
@ -311,6 +340,9 @@ in {
|
||||||
primary-group = "selby";
|
primary-group = "selby";
|
||||||
common-name = "Vee Selby";
|
common-name = "Vee Selby";
|
||||||
ldap-hashed-passwd = "snoinuer";
|
ldap-hashed-passwd = "snoinuer";
|
||||||
|
email-aliases = [
|
||||||
|
"virginia@selby.ca"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
dabar = {
|
dabar = {
|
||||||
|
|
|
@ -2,34 +2,6 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
# localCopyOpts = { copy, ... }: let
|
|
||||||
# in {
|
|
||||||
# options = with types; {
|
|
||||||
# user = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description = "User to which this copy belongs.";
|
|
||||||
# };
|
|
||||||
|
|
||||||
# group = mkOption {
|
|
||||||
# type = nullOr str;
|
|
||||||
# description = "Group to which this copy belongs.";
|
|
||||||
# default = null;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# path = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description = "Path at which to store the local copy.";
|
|
||||||
# #default = "/var/run/${toplevel.config.domain}/${copy}";
|
|
||||||
# };
|
|
||||||
|
|
||||||
# service = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description = "systemd job to copy certs.";
|
|
||||||
# default = "fudo-${toplevel.config.domain}-${copy}-certs.service";
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
|
|
||||||
domainOpts = { name, ... }: let
|
domainOpts = { name, ... }: let
|
||||||
domain = name;
|
domain = name;
|
||||||
in {
|
in {
|
||||||
|
@ -140,14 +112,14 @@ in {
|
||||||
perms = copyOpts: if (copyOpts.group != null) then "0550" else "0500";
|
perms = copyOpts: if (copyOpts.group != null) then "0550" else "0500";
|
||||||
copy-paths = mapAttrsToList (copy: copyOpts:
|
copy-paths = mapAttrsToList (copy: copyOpts:
|
||||||
let
|
let
|
||||||
dir-entry = copyOpts: file: "D '${dirOf file}' ${perms copyOpts} ${copyOpts.user} ${optionalStringOr copyOpts.group "-"} - -";
|
dir-entry = copyOpts: file: "D \"${dirOf file}\" ${perms copyOpts} ${copyOpts.user} ${optionalStringOr copyOpts.group "-"} - -";
|
||||||
in map (dir-entry copyOpts) [
|
in map (dir-entry copyOpts) [
|
||||||
copyOpts.certificate
|
copyOpts.certificate
|
||||||
copyOpts.full-certificate
|
copyOpts.full-certificate
|
||||||
copyOpts.chain
|
copyOpts.chain
|
||||||
copyOpts.private-key
|
copyOpts.private-key
|
||||||
]) copies;
|
]) copies;
|
||||||
in unique copy-paths;
|
in unique (concatMap (i: unique i) copy-paths);
|
||||||
|
|
||||||
services = concatMapAttrs (domain: domainOpts:
|
services = concatMapAttrs (domain: domainOpts:
|
||||||
mapAttrs' (copy: copyOpts: let
|
mapAttrs' (copy: copyOpts: let
|
||||||
|
@ -169,7 +141,7 @@ in {
|
||||||
'';
|
'';
|
||||||
remove-certs = pkgs.writeShellScript "fudo-remove-${domain}-${copy}-certs.sh" ''
|
remove-certs = pkgs.writeShellScript "fudo-remove-${domain}-${copy}-certs.sh" ''
|
||||||
rm -f ${copyOpts.private-key}
|
rm -f ${copyOpts.private-key}
|
||||||
rm -f ${copyOpts.chainy}
|
rm -f ${copyOpts.chain}
|
||||||
rm -f ${copyOpts.full-certificate}
|
rm -f ${copyOpts.full-certificate}
|
||||||
rm -f ${copyOpts.certificate}
|
rm -f ${copyOpts.certificate}
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -4,7 +4,7 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.backplane.dns;
|
cfg = config.fudo.backplane.dns;
|
||||||
|
|
||||||
powerdns-conf-dir = "${cfg.powerdns-home}/conf.d";
|
powerdns-conf-dir = "${cfg.powerdns.home}/conf.d";
|
||||||
|
|
||||||
backplaneOpts = { ... }: {
|
backplaneOpts = { ... }: {
|
||||||
options = {
|
options = {
|
||||||
|
@ -90,6 +90,7 @@ in {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
description =
|
description =
|
||||||
"A list of services required before the DNS server can start.";
|
"A list of services required before the DNS server can start.";
|
||||||
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
|
@ -109,16 +110,24 @@ in {
|
||||||
description = "Database settings for the DNS server.";
|
description = "Database settings for the DNS server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
powerdns-home = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Directory at which to store powerdns configuration and state.";
|
|
||||||
default = "/run/backplane-dns/powerdns";
|
|
||||||
};
|
|
||||||
|
|
||||||
backplane = mkOption {
|
backplane = mkOption {
|
||||||
type = submodule backplaneOpts;
|
type = submodule backplaneOpts;
|
||||||
description = "Backplane Jabber settings for the DNS server.";
|
description = "Backplane Jabber settings for the DNS server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
powerdns = {
|
||||||
|
home = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Directory at which to store powerdns configuration and state.";
|
||||||
|
default = "/run/backplane-dns/powerdns";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Username as which to run PowerDNS.";
|
||||||
|
default = "backplane-powerdns";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
@ -130,16 +139,16 @@ in {
|
||||||
createHome = true;
|
createHome = true;
|
||||||
home = "/var/home/${cfg.user}";
|
home = "/var/home/${cfg.user}";
|
||||||
};
|
};
|
||||||
backplane-powerdns = {
|
${cfg.powerdns.user} = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
home = cfg.powerdns-home;
|
home = cfg.powerdns.home;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
groups = {
|
groups = {
|
||||||
"${cfg.group}" = { members = [ cfg.user ]; };
|
"${cfg.group}" = { members = [ cfg.user ]; };
|
||||||
backplane-powerdns = { members = [ "backplane-powerdns" ]; };
|
${cfg.powerdns.user} = { members = [ cfg.powerdns.user ]; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,7 +165,7 @@ in {
|
||||||
|
|
||||||
preStart = ''
|
preStart = ''
|
||||||
mkdir -p ${powerdns-conf-dir}
|
mkdir -p ${powerdns-conf-dir}
|
||||||
chown backplane-powerdns:backplane-powerdns ${powerdns-conf-dir}
|
chown ${cfg.powerdns.user}:${cfg.powerdns.user} ${powerdns-conf-dir}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# This builds the config in a bash script, to avoid storing the password
|
# This builds the config in a bash script, to avoid storing the password
|
||||||
|
@ -175,7 +184,7 @@ in {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
touch $TMPCONF
|
touch $TMPCONF
|
||||||
chown backplane-powerdns:backplane-powerdns $TMPCONF
|
chown ${cfg.powerdns.user}:${cfg.powerdns.user} $TMPCONF
|
||||||
chmod go-rwx $TMPCONF
|
chmod go-rwx $TMPCONF
|
||||||
PASSWORD=$(cat ${cfg.database.password-file})
|
PASSWORD=$(cat ${cfg.database.password-file})
|
||||||
echo "launch+=gpgsql" >> $TMPCONF
|
echo "launch+=gpgsql" >> $TMPCONF
|
||||||
|
@ -192,25 +201,6 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
backplane-powerdns = let
|
|
||||||
pdns-config-dir = pkgs.writeTextDir "pdns.conf" ''
|
|
||||||
local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
|
|
||||||
local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
|
|
||||||
local-port=${toString cfg.port}
|
|
||||||
launch=
|
|
||||||
include-dir=${powerdns-conf-dir}/
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
description = "Backplane PowerDNS name server";
|
|
||||||
requires = [
|
|
||||||
"postgresql.service"
|
|
||||||
"backplane-powerdns-config-generator.service"
|
|
||||||
];
|
|
||||||
after = [ "network.target" ];
|
|
||||||
path = with pkgs; [ powerdns postgresql ];
|
|
||||||
execStart = "pdns_server --setuid=backplane-powerdns --setgid=backplane-powerdns --chroot=${cfg.powerdns-home} --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${pdns-config-dir}";
|
|
||||||
};
|
|
||||||
|
|
||||||
backplane-dns = {
|
backplane-dns = {
|
||||||
description = "Fudo DNS Backplane Server";
|
description = "Fudo DNS Backplane Server";
|
||||||
restartIfChanged = true;
|
restartIfChanged = true;
|
||||||
|
@ -220,7 +210,7 @@ in {
|
||||||
user = cfg.user;
|
user = cfg.user;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
partOf = [ "backplane-dns.target" ];
|
partOf = [ "backplane-dns.target" ];
|
||||||
requires = [ "postgresql.service" ];
|
requires = cfg.required-services ++ [ "postgresql.service" ];
|
||||||
environment = {
|
environment = {
|
||||||
FUDO_DNS_BACKPLANE_XMPP_HOSTNAME = cfg.backplane.host;
|
FUDO_DNS_BACKPLANE_XMPP_HOSTNAME = cfg.backplane.host;
|
||||||
FUDO_DNS_BACKPLANE_XMPP_USERNAME = cfg.backplane.role;
|
FUDO_DNS_BACKPLANE_XMPP_USERNAME = cfg.backplane.role;
|
||||||
|
@ -243,7 +233,30 @@ in {
|
||||||
backplane-dns = {
|
backplane-dns = {
|
||||||
description = "Fudo DNS backplane services.";
|
description = "Fudo DNS backplane services.";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
requries = cfg.required-services ++ [ "postgresql.service" ];
|
after = cfg.required-services ++ [ "postgresql.service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
backplane-powerdns = let
|
||||||
|
pdns-config-dir = pkgs.writeTextDir "pdns.conf" ''
|
||||||
|
local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
|
||||||
|
local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
|
||||||
|
local-port=${toString cfg.port}
|
||||||
|
launch=
|
||||||
|
include-dir=${powerdns-conf-dir}/
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
description = "Backplane PowerDNS name server";
|
||||||
|
requires = [
|
||||||
|
"postgresql.service"
|
||||||
|
"backplane-powerdns-config-generator.service"
|
||||||
|
];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
path = with pkgs; [ powerdns postgresql ];
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "pdns_server --setuid=${cfg.powerdns.user} --setgid=${cfg.powerdns.user} --chroot=${cfg.powerdns.home} --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${pdns-config-dir}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,67 +1,71 @@
|
||||||
{ pkgs, lib, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let cfg = config.fudo.chat;
|
let
|
||||||
|
cfg = config.fudo.chat;
|
||||||
|
mattermost-config-target = "/run/chat/mattermost/mattermost-config.json";
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.chat = {
|
options.fudo.chat = with types; {
|
||||||
enable = mkEnableOption "Enable chat server";
|
enable = mkEnableOption "Enable chat server";
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Hostname at which this chat server is accessible.";
|
description = "Hostname at which this chat server is accessible.";
|
||||||
example = "chat.mydomain.com";
|
example = "chat.mydomain.com";
|
||||||
};
|
};
|
||||||
|
|
||||||
site-name = mkOption {
|
site-name = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "The name of this chat server.";
|
description = "The name of this chat server.";
|
||||||
example = "My Fancy Chat Site";
|
example = "My Fancy Chat Site";
|
||||||
};
|
};
|
||||||
|
|
||||||
smtp-server = mkOption {
|
smtp = {
|
||||||
type = types.str;
|
server = mkOption {
|
||||||
description = "SMTP server to use for sending notification emails.";
|
type = str;
|
||||||
example = "mail.my-site.com";
|
description = "SMTP server to use for sending notification emails.";
|
||||||
};
|
example = "mail.my-site.com";
|
||||||
|
};
|
||||||
|
|
||||||
smtp-user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Username with which to connect to the SMTP server.";
|
description = "Username with which to connect to the SMTP server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
smtp-password-file = mkOption {
|
password-file = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description =
|
description =
|
||||||
"Path to a file containing the password to use while connecting to the SMTP server.";
|
"Path to a file containing the password to use while connecting to the SMTP server.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Path at which to store server state data.";
|
description = "Path at which to store server state data.";
|
||||||
default = "/var/lib/mattermost";
|
default = "/var/lib/mattermost";
|
||||||
};
|
};
|
||||||
|
|
||||||
database = mkOption {
|
database = mkOption {
|
||||||
type = (types.submodule {
|
type = (submodule {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Database name.";
|
description = "Database name.";
|
||||||
};
|
};
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Database host.";
|
description = "Database host.";
|
||||||
};
|
};
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Database user.";
|
description = "Database user.";
|
||||||
};
|
};
|
||||||
|
|
||||||
password-file = mkOption {
|
password-file = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Path to file containing database password.";
|
description = "Path to file containing database password.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -85,11 +89,11 @@ in {
|
||||||
TeamSettings.SiteName = cfg.site-name;
|
TeamSettings.SiteName = cfg.site-name;
|
||||||
EmailSettings = {
|
EmailSettings = {
|
||||||
RequireEmailVerification = true;
|
RequireEmailVerification = true;
|
||||||
SMTPServer = cfg.smtp-server;
|
SMTPServer = cfg.smtp.server;
|
||||||
SMTPPort = 587;
|
SMTPPort = 587;
|
||||||
EnableSMTPAuth = true;
|
EnableSMTPAuth = true;
|
||||||
SMTPUsername = cfg.smtp-user;
|
SMTPUsername = cfg.smtp.user;
|
||||||
SMTPPassword = (fileContents cfg.smtp-password-file);
|
SMTPPassword = "__SMTP_PASSWD__";
|
||||||
SendEmailNotifications = true;
|
SendEmailNotifications = true;
|
||||||
ConnectionSecurity = "STARTTLS";
|
ConnectionSecurity = "STARTTLS";
|
||||||
FeedbackEmail = "chat@fudo.org";
|
FeedbackEmail = "chat@fudo.org";
|
||||||
|
@ -97,15 +101,26 @@ in {
|
||||||
};
|
};
|
||||||
EnableEmailInvitations = true;
|
EnableEmailInvitations = true;
|
||||||
SqlSettings.DriverName = "postgres";
|
SqlSettings.DriverName = "postgres";
|
||||||
SqlSettings.DataSource = "postgres://${cfg.database.user}:${
|
SqlSettings.DataSource = "postgres://${
|
||||||
fileContents cfg.database.password-file
|
cfg.database.user
|
||||||
}@${cfg.database.hostname}:5432/${cfg.database.name}";
|
}:__DATABASE_PASSWORD__@${
|
||||||
|
cfg.database.hostname
|
||||||
|
}:5432/${
|
||||||
|
cfg.database.name
|
||||||
|
}";
|
||||||
};
|
};
|
||||||
mattermost-config-file =
|
mattermost-config-file-template =
|
||||||
pkgs.writeText "mattermost-config.json" (builtins.toJSON modified-config);
|
pkgs.writeText "mattermost-config.json.template" (builtins.toJSON modified-config);
|
||||||
mattermost-user = "mattermost";
|
mattermost-user = "mattermost";
|
||||||
mattermost-group = "mattermost";
|
mattermost-group = "mattermost";
|
||||||
|
|
||||||
|
generate-mattermost-config = target: template: smtp-passwd-file: db-passwd-file:
|
||||||
|
pkgs.writeScript "mattermost-config-generator.sh" ''
|
||||||
|
SMTP_PASSWD=$( cat ${smtp-passwd-file} )
|
||||||
|
DATABASE_PASSWORD=$( cat ${db-passwd-file} )
|
||||||
|
sed -e 's/__SMTP_PASSWD__/"$SMTP_PASSWD"/' -e 's/__DATABASE_PASSWORD__/"$DATABASE_PASSWORD"/' ${template} > ${target}
|
||||||
|
'';
|
||||||
|
|
||||||
in {
|
in {
|
||||||
users = {
|
users = {
|
||||||
users = {
|
users = {
|
||||||
|
@ -118,48 +133,75 @@ in {
|
||||||
groups = { ${mattermost-group} = { members = [ mattermost-user ]; }; };
|
groups = { ${mattermost-group} = { members = [ mattermost-user ]; }; };
|
||||||
};
|
};
|
||||||
|
|
||||||
system.activationScripts.mattermost = ''
|
fudo.system.services.mattermost = {
|
||||||
mkdir -p ${cfg.state-directory}
|
|
||||||
'';
|
|
||||||
|
|
||||||
systemd.services.mattermost = {
|
|
||||||
description = "Mattermost Chat Server";
|
description = "Mattermost Chat Server";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
|
||||||
preStart = ''
|
preStart = ''
|
||||||
mkdir -p ${cfg.state-directory}/config
|
${generate-mattermost-config
|
||||||
cp ${mattermost-config-file} ${cfg.state-directory}/config/config.json
|
mattermost-config-target
|
||||||
ln -sf ${pkg}/bin ${cfg.state-directory}
|
mattermost-config-file-template
|
||||||
ln -sf ${pkg}/fonts ${cfg.state-directory}
|
cfg.smtp.password-file
|
||||||
ln -sf ${pkg}/i18n ${cfg.state-directory}
|
cfg.database.password-file}
|
||||||
ln -sf ${pkg}/templates ${cfg.state-directory}
|
cp ${cfg.smtp.password-file} ${cfg.state-directory}/config/config.json
|
||||||
cp -uRL ${pkg}/client ${cfg.state-directory}
|
cp -uRL ${pkg}/client ${cfg.state-directory}
|
||||||
chown -R ${mattermost-user}:${mattermost-group} ${cfg.state-directory}
|
chown ${mattermost-user}:${mattermost-group} ${cfg.state-directory}/client
|
||||||
chmod u+w -R ${cfg.state-directory}/client
|
chmod 0750 ${cfg.state-directory}/client
|
||||||
chmod o-rwx -R ${cfg.state-directory}
|
|
||||||
'';
|
'';
|
||||||
|
execStart = "${pkg}/bin/mattermost";
|
||||||
serviceConfig = {
|
workingDirectory = cfg.state-directory;
|
||||||
PermissionsStartOnly = true;
|
user = mattermost-user;
|
||||||
ExecStart = "${pkg}/bin/mattermost";
|
group = mattermost-group;
|
||||||
WorkingDirectory = cfg.state-directory;
|
|
||||||
Restart = "always";
|
|
||||||
RestartSec = "10";
|
|
||||||
LimitNOFILE = "49152";
|
|
||||||
User = mattermost-user;
|
|
||||||
Group = mattermost-group;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme.certs.${cfg.hostname}.email = config.fudo.common.admin-email;
|
systemd = {
|
||||||
|
|
||||||
|
tmpfiles.rules = [
|
||||||
|
"d ${cfg.state-directory} 0750 ${mattermost-user} ${mattermost-group} - -"
|
||||||
|
"d ${cfg.state-directory}/config 0750 ${mattermost-user} ${mattermost-group} - -"
|
||||||
|
"L ${cfg.state-directory}/bin - - - - ${pkg}/bin"
|
||||||
|
"L ${cfg.state-directory}/fonts - - - - ${pkg}/fonts"
|
||||||
|
"L ${cfg.state-directory}/i18n - - - - ${pkg}/i18n"
|
||||||
|
"L ${cfg.state-directory}/templates - - - - ${pkg}/templates"
|
||||||
|
];
|
||||||
|
|
||||||
|
# services.mattermost = {
|
||||||
|
# description = "Mattermost Chat Server";
|
||||||
|
# wantedBy = [ "multi-user.target" ];
|
||||||
|
# after = [ "network.target" ];
|
||||||
|
|
||||||
|
# preStart = ''
|
||||||
|
# ${generate-mattermost-config
|
||||||
|
# mattermost-config-target
|
||||||
|
# mattermost-config-file-template
|
||||||
|
# cfg.smtp.password-file
|
||||||
|
# cfg.database.password-file}
|
||||||
|
# cp ${cfg.smtp.password-file} ${cfg.state-directory}/config/config.json
|
||||||
|
# cp -uRL ${pkg}/client ${cfg.state-directory}
|
||||||
|
# chown ${mattermost-user}:${mattermost-group} ${cfg.state-directory}/client
|
||||||
|
# chmod 0750 ${cfg.state-directory}/client
|
||||||
|
# '';
|
||||||
|
|
||||||
|
# serviceConfig = {
|
||||||
|
# PermissionsStartOnly = true;
|
||||||
|
# ExecStart = "${pkg}/bin/mattermost";
|
||||||
|
# WorkingDirectory = cfg.state-directory;
|
||||||
|
# Restart = "always";
|
||||||
|
# RestartSec = "10";
|
||||||
|
# LimitNOFILE = "49152";
|
||||||
|
# User = mattermost-user;
|
||||||
|
# Group = mattermost-group;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
appendHttpConfig = ''
|
appendHttpConfig = ''
|
||||||
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;
|
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;
|
||||||
'';
|
'';
|
||||||
|
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
"${cfg.hostname}" = {
|
"${cfg.hostname}" = {
|
||||||
|
@ -170,48 +212,48 @@ in {
|
||||||
proxyPass = "http://127.0.0.1:8065";
|
proxyPass = "http://127.0.0.1:8065";
|
||||||
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
proxy_set_header Connection "";
|
proxy_set_header Connection "";
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header X-Frame-Options SAMEORIGIN;
|
proxy_set_header X-Frame-Options SAMEORIGIN;
|
||||||
proxy_buffers 256 16k;
|
proxy_buffers 256 16k;
|
||||||
proxy_buffer_size 16k;
|
proxy_buffer_size 16k;
|
||||||
proxy_read_timeout 600s;
|
proxy_read_timeout 600s;
|
||||||
proxy_cache mattermost_cache;
|
proxy_cache mattermost_cache;
|
||||||
proxy_cache_revalidate on;
|
proxy_cache_revalidate on;
|
||||||
proxy_cache_min_uses 2;
|
proxy_cache_min_uses 2;
|
||||||
proxy_cache_use_stale timeout;
|
proxy_cache_use_stale timeout;
|
||||||
proxy_cache_lock on;
|
proxy_cache_lock on;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
locations."~ /api/v[0-9]+/(users/)?websocket$" = {
|
locations."~ /api/v[0-9]+/(users/)?websocket$" = {
|
||||||
proxyPass = "http://127.0.0.1:8065";
|
proxyPass = "http://127.0.0.1:8065";
|
||||||
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header X-Frame-Options SAMEORIGIN;
|
proxy_set_header X-Frame-Options SAMEORIGIN;
|
||||||
proxy_buffers 256 16k;
|
proxy_buffers 256 16k;
|
||||||
proxy_buffer_size 16k;
|
proxy_buffer_size 16k;
|
||||||
client_body_timeout 60;
|
client_body_timeout 60;
|
||||||
send_timeout 300;
|
send_timeout 300;
|
||||||
lingering_timeout 5;
|
lingering_timeout 5;
|
||||||
proxy_connect_timeout 90;
|
proxy_connect_timeout 90;
|
||||||
proxy_send_timeout 300;
|
proxy_send_timeout 300;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,14 @@ let
|
||||||
|
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
|
|
||||||
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
generate-string-hash = name: str: let
|
||||||
|
string-hash-pkg = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${name}-string-hash";
|
||||||
|
phases = "installPhase";
|
||||||
|
buildInputs = [ pkgs.openssl ];
|
||||||
|
installPhase = "openssl passwd -6 ${str} > $out";
|
||||||
|
};
|
||||||
|
in string-hash-pkg;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.hosts = with types;
|
options.fudo.hosts = with types;
|
||||||
|
@ -37,9 +44,12 @@ in {
|
||||||
#defaultGateway = site.gateway-v4;
|
#defaultGateway = site.gateway-v4;
|
||||||
#defaultGateway6 = site.gateway-v6;
|
#defaultGateway6 = site.gateway-v6;
|
||||||
|
|
||||||
firewall = {
|
firewall = mkIf ((length host-cfg.external-interfaces) > 0) {
|
||||||
enable = (length host-cfg.external-interfaces) > 0;
|
enable = true;
|
||||||
allowedTCPPorts = [ 22 ];
|
allowedTCPPorts = [ 22 2112 ]; # Make sure _at least_ SSH is allowed
|
||||||
|
trustedInterfaces = let
|
||||||
|
all-interfaces = attrNames config.networking.interfaces;
|
||||||
|
in subtractLists host-cfg.external-interfaces all-interfaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
hostId = mkIf (host-cfg.machine-id != null)
|
hostId = mkIf (host-cfg.machine-id != null)
|
||||||
|
@ -79,6 +89,8 @@ in {
|
||||||
in concatStringsSep "\n" sorted-unique;
|
in concatStringsSep "\n" sorted-unique;
|
||||||
|
|
||||||
build-timestamp.text = toString config.instance.build-timestamp;
|
build-timestamp.text = toString config.instance.build-timestamp;
|
||||||
|
build-seed-hash.source =
|
||||||
|
generate-string-hash "build-seed" config.instance.build-seed;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemPackages = with pkgs;
|
systemPackages = with pkgs;
|
||||||
|
@ -89,7 +101,10 @@ in {
|
||||||
|
|
||||||
krb5.libdefaults.default_realm = domain.gssapi-realm;
|
krb5.libdefaults.default_realm = domain.gssapi-realm;
|
||||||
|
|
||||||
services.cron.mailto = domain.admin-email;
|
services = {
|
||||||
|
cron.mailto = domain.admin-email;
|
||||||
|
fail2ban.ignoreIP = config.instance.local-networks;
|
||||||
|
};
|
||||||
|
|
||||||
virtualisation.docker = mkIf (host-cfg.docker-server) {
|
virtualisation.docker = mkIf (host-cfg.docker-server) {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -97,56 +112,11 @@ in {
|
||||||
autoPrune.enable = true;
|
autoPrune.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo = let
|
|
||||||
try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
|
|
||||||
|
|
||||||
files = config.fudo.secrets.files;
|
|
||||||
|
|
||||||
keytab-file = try-attr hostname files.host-keytabs;
|
|
||||||
|
|
||||||
build-private-key-file =
|
|
||||||
mapOptional
|
|
||||||
(keypair: keypair.private-key)
|
|
||||||
(try-attr hostname files.build-keypairs);
|
|
||||||
|
|
||||||
in {
|
|
||||||
secrets.host-secrets.${hostname} = {
|
|
||||||
host-keytab = mkIf (keytab-file != null) {
|
|
||||||
source-file = keytab-file;
|
|
||||||
target-file = "/etc/krb5.keytab";
|
|
||||||
user = "root";
|
|
||||||
};
|
|
||||||
|
|
||||||
build-private-key = mkIf (build-private-key-file != null) {
|
|
||||||
source-file = build-private-key-file;
|
|
||||||
target-file = "/var/run/nix-build/host.key";
|
|
||||||
user = "root";
|
|
||||||
};
|
|
||||||
|
|
||||||
backplane-passwd = {
|
|
||||||
source-file = host-cfg.backplane-password-file;
|
|
||||||
target-file = "/run/backplane/client/passwd";
|
|
||||||
user = config.fudo.client.dns.user;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
client.dns.password-file =
|
|
||||||
host-secrets.backplane-passwd.target-file;
|
|
||||||
};
|
|
||||||
|
|
||||||
programs.adb.enable = host-cfg.android-dev;
|
programs.adb.enable = host-cfg.android-dev;
|
||||||
users.groups.adbusers = mkIf host-cfg.android-dev {
|
users.groups.adbusers = mkIf host-cfg.android-dev {
|
||||||
members = config.instance.local-admins;
|
members = config.instance.local-admins;
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.tmpOnTmpfs = host-cfg.tmp-on-tmpfs;
|
boot.tmpOnTmpfs = host-cfg.tmp-on-tmpfs;
|
||||||
|
|
||||||
home-manager.users.root.home.file = {
|
|
||||||
".k5login".text = let
|
|
||||||
realm = domain.gssapi-realm;
|
|
||||||
entries =
|
|
||||||
map (admin: "${admin}/root@${realm}") config.instance.local-admins;
|
|
||||||
in concatStringsSep "\n" entries;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,6 @@ let
|
||||||
user-group-entry = group: user:
|
user-group-entry = group: user:
|
||||||
nameValuePair user { extraGroups = [ group ]; };
|
nameValuePair user { extraGroups = [ group ]; };
|
||||||
|
|
||||||
user-home-entry = ipfs-path: user:
|
|
||||||
nameValuePair user { home.sessionVariables = { IPFS_PATH = ipfs-path; }; };
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.ipfs = with types; {
|
options.fudo.ipfs = with types; {
|
||||||
enable = mkEnableOption "Fudo IPFS";
|
enable = mkEnableOption "Fudo IPFS";
|
||||||
|
@ -53,7 +50,8 @@ in {
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
users.users = listToAttrs (map (user-group-entry cfg.group) cfg.users);
|
users.users =
|
||||||
|
mapAttrs user-group-entry config.instance.local-users;
|
||||||
|
|
||||||
services.ipfs = {
|
services.ipfs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -64,8 +62,5 @@ in {
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
dataDir = cfg.data-dir;
|
dataDir = cfg.data-dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager.users =
|
|
||||||
listToAttrs (map (user-home-entry cfg.data-dir) cfg.users);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,100 +5,7 @@ let
|
||||||
|
|
||||||
cfg = config.fudo.auth.ldap-server;
|
cfg = config.fudo.auth.ldap-server;
|
||||||
|
|
||||||
ldapSystemUserOpts = { name, ... }: {
|
user-type = import ../types/user.nix { inherit lib; };
|
||||||
options = {
|
|
||||||
description = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The description of this system user.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
hashed-password = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The password for this user, hashed with ldappasswd.
|
|
||||||
'';
|
|
||||||
default = "";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ldapGroupOpts = { name, ... }: {
|
|
||||||
options = {
|
|
||||||
gid = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
description = ''
|
|
||||||
The GID number of this group.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
description = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The description of this group.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
members = mkOption {
|
|
||||||
type = with types; listOf str;
|
|
||||||
default = [ ];
|
|
||||||
description = ''
|
|
||||||
A list of usernames representing the members of this group.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ldapUserOpts = { name, ... }: {
|
|
||||||
options = {
|
|
||||||
|
|
||||||
uid = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
description = ''
|
|
||||||
The UID number of this user.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
common-name = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The given name of this user.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The name of the user's primary group.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
login-shell = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/bin/bash";
|
|
||||||
description = ''
|
|
||||||
The user's preferred shell. Default is /bin/bash.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
description = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "Fudo Member";
|
|
||||||
description = ''
|
|
||||||
The description of this user.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
hashed-password = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The password for this user, hashed with ldappasswd.
|
|
||||||
'';
|
|
||||||
default = "";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
stringJoin = joiner: attrList:
|
stringJoin = joiner: attrList:
|
||||||
if (length attrList) == 0 then
|
if (length attrList) == 0 then
|
||||||
|
@ -107,15 +14,15 @@ let
|
||||||
foldr (lAttr: rAttr: "${lAttr}${joiner}${rAttr}") (last attrList)
|
foldr (lAttr: rAttr: "${lAttr}${joiner}${rAttr}") (last attrList)
|
||||||
(init attrList);
|
(init attrList);
|
||||||
|
|
||||||
getUserGidNumber = user: group-map: group-map.${user.group}.gid;
|
getUserGidNumber = user: group-map: group-map.${user.primary-group}.gid;
|
||||||
|
|
||||||
attrOr = attrs: attr: value: if attrs ? ${attr} then attrs.${attr} else value;
|
attrOr = attrs: attr: value: if attrs ? ${attr} then attrs.${attr} else value;
|
||||||
|
|
||||||
mkHomeDir = username: user-opts:
|
mkHomeDir = username: user-opts:
|
||||||
if (user-opts.group == "admin") then
|
if (user-opts.primary-group == "admin") then
|
||||||
"/home/${username}"
|
"/home/${username}"
|
||||||
else
|
else
|
||||||
"/home/${user-opts.group}/${username}";
|
"/home/${user-opts.primary-group}/${username}";
|
||||||
|
|
||||||
userLdif = base: name: group-map: opts: ''
|
userLdif = base: name: group-map: opts: ''
|
||||||
dn: uid=${name},ou=members,${base}
|
dn: uid=${name},ou=members,${base}
|
||||||
|
@ -131,7 +38,7 @@ let
|
||||||
shadowLastChange: 12230
|
shadowLastChange: 12230
|
||||||
shadowMax: 99999
|
shadowMax: 99999
|
||||||
shadowWarning: 7
|
shadowWarning: 7
|
||||||
userPassword: ${opts.hashed-password}
|
userPassword: ${opts.ldap-hashed-passwd}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
systemUserLdif = base: name: opts: ''
|
systemUserLdif = base: name: opts: ''
|
||||||
|
@ -140,7 +47,7 @@ let
|
||||||
objectClass: simpleSecurityObject
|
objectClass: simpleSecurityObject
|
||||||
cn: ${name}
|
cn: ${name}
|
||||||
description: ${opts.description}
|
description: ${opts.description}
|
||||||
userPassword: ${opts.hashed-password}
|
userPassword: ${opts.ldap-hashed-password}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
toMemberList = userList:
|
toMemberList = userList:
|
||||||
|
@ -242,7 +149,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
type = attrsOf (submodule ldapUserOpts);
|
type = attrsOf (submodule user-type.userOpts);
|
||||||
example = {
|
example = {
|
||||||
tester = {
|
tester = {
|
||||||
uid = 10099;
|
uid = 10099;
|
||||||
|
@ -258,7 +165,7 @@ in {
|
||||||
|
|
||||||
groups = mkOption {
|
groups = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = attrsOf (submodule ldapGroupOpts);
|
type = attrsOf (submodule user-type.groupOpts);
|
||||||
example = {
|
example = {
|
||||||
admin = {
|
admin = {
|
||||||
gid = 1099;
|
gid = 1099;
|
||||||
|
@ -272,16 +179,19 @@ in {
|
||||||
|
|
||||||
system-users = mkOption {
|
system-users = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = attrsOf (submodule ldapSystemUserOpts);
|
type = attrsOf (submodule user-type.systemUserOpts);
|
||||||
example = {
|
example = {
|
||||||
replicator = {
|
replicator = {
|
||||||
description = "System user for database sync";
|
description = "System user for database sync";
|
||||||
hashed-password = "<insert password hash>";
|
ldap-hashed-password = "<insert password hash>";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
description = ''
|
description = "System users to be added to the Fudo LDAP database.";
|
||||||
System users to be added to the Fudo LDAP database.
|
};
|
||||||
'';
|
|
||||||
|
database-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path at which to store the database.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -337,21 +247,19 @@ in {
|
||||||
|
|
||||||
services.openldap = {
|
services.openldap = {
|
||||||
enable = true;
|
enable = true;
|
||||||
suffix = cfg.base;
|
|
||||||
rootdn = "cn=admin,${cfg.base}";
|
|
||||||
rootpwFile = "${cfg.rootpw-file}";
|
|
||||||
urlList = cfg.listen-uris;
|
urlList = cfg.listen-uris;
|
||||||
database = "mdb";
|
|
||||||
|
|
||||||
settings = let
|
settings = let
|
||||||
makeAccessLine = i: attrs: perm-map: let
|
makePermEntry = dn: perm: "by ${dn} ${perm}";
|
||||||
perm-strings = mapAttrs (dn: perm: "by ${dn} ${perm}") perm-map;
|
|
||||||
perm-string = concatStringsSep " " perm-strings;
|
makeAccessLine = target: perm-map: let
|
||||||
in "${i}to ${attrs} ${perm-string}";
|
perm-entries = mapAttrsToList makePermEntry perm-map;
|
||||||
|
in "to ${target} ${concatStringsSep " " perm-entries} done";
|
||||||
|
|
||||||
makeAccess = access-map: let
|
makeAccess = access-map: let
|
||||||
pairs = mapAttrsToList (target: perm-map: [target perm-map]) access-map;
|
access-lines = mapAttrsToList makeAccessLine;
|
||||||
in imap0 (i: pair: makeAccessLine i pair[0] pair[1]) pairs;
|
numbered-access-lines = imap0 (i: line: "{${toString i}}${line}");
|
||||||
|
in numbered-access-lines (access-lines access-map);
|
||||||
|
|
||||||
in {
|
in {
|
||||||
attrs = {
|
attrs = {
|
||||||
|
@ -363,8 +271,8 @@ in {
|
||||||
olcTLSCACertificateFile = cfg.ssl-ca-certificate;
|
olcTLSCACertificateFile = cfg.ssl-ca-certificate;
|
||||||
olcSaslSecProps = "noplain,noanonymous";
|
olcSaslSecProps = "noplain,noanonymous";
|
||||||
olcAuthzRegexp = let
|
olcAuthzRegexp = let
|
||||||
authz-regex-entry = i: { regex, target}:
|
authz-regex-entry = i: { regex, target }:
|
||||||
"{${i}}\"${rx}\" \"${target}\"";
|
"{${toString i}}\"${regex}\" \"${target}\"";
|
||||||
in imap0 authz-regex-entry [
|
in imap0 authz-regex-entry [
|
||||||
{
|
{
|
||||||
regex = "^uid=auth/([^.]+).fudo.org,cn=fudo.org,cn=gssapi,cn=auth$";
|
regex = "^uid=auth/([^.]+).fudo.org,cn=fudo.org,cn=gssapi,cn=auth$";
|
||||||
|
@ -396,7 +304,7 @@ in {
|
||||||
olcAccess = makeAccess {
|
olcAccess = makeAccess {
|
||||||
"*" = {
|
"*" = {
|
||||||
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
"dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" = "manage";
|
||||||
"dn.exact=cn=admin,dc=fudo,dc=org" = "manage";
|
"dn.exact=cn=admin,${cfg.base}" = "manage";
|
||||||
"*" = "none";
|
"*" = "none";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -462,30 +370,32 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
declarativeContents = ''
|
declarativeContents = {
|
||||||
dn: ${cfg.base}
|
"dc=fudo,dc=org" = ''
|
||||||
objectClass: top
|
dn: ${cfg.base}
|
||||||
objectClass: dcObject
|
objectClass: top
|
||||||
objectClass: organization
|
objectClass: dcObject
|
||||||
o: ${cfg.organization}
|
objectClass: organization
|
||||||
|
o: ${cfg.organization}
|
||||||
|
|
||||||
dn: ou=groups,${cfg.base}
|
dn: ou=groups,${cfg.base}
|
||||||
objectClass: organizationalUnit
|
objectClass: organizationalUnit
|
||||||
description: ${cfg.organization} groups
|
description: ${cfg.organization} groups
|
||||||
|
|
||||||
dn: ou=members,${cfg.base}
|
dn: ou=members,${cfg.base}
|
||||||
objectClass: organizationalUnit
|
objectClass: organizationalUnit
|
||||||
description: ${cfg.organization} members
|
description: ${cfg.organization} members
|
||||||
|
|
||||||
dn: cn=admin,${cfg.base}
|
dn: cn=admin,${cfg.base}
|
||||||
objectClass: organizationalRole
|
objectClass: organizationalRole
|
||||||
cn: admin
|
cn: admin
|
||||||
description: "Admin User"
|
description: "Admin User"
|
||||||
|
|
||||||
${systemUsersLdif cfg.base cfg.system-users}
|
${systemUsersLdif cfg.base cfg.system-users}
|
||||||
${groupsLdif cfg.base cfg.groups}
|
${groupsLdif cfg.base cfg.groups}
|
||||||
${usersLdif cfg.base cfg.groups cfg.users}
|
${usersLdif cfg.base cfg.groups cfg.users}
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ lib, config, ... }:
|
{ pkgs, lib, config, ... }:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
|
@ -11,22 +11,18 @@ let
|
||||||
container-mail-user-id = 542;
|
container-mail-user-id = 542;
|
||||||
container-mail-group = "mailer";
|
container-mail-group = "mailer";
|
||||||
|
|
||||||
|
build-timestamp = config.instance.build-timestamp;
|
||||||
|
build-seed = config.instance.build-seed;
|
||||||
|
site = config.instance.local-site;
|
||||||
|
domain = cfg.domain;
|
||||||
|
|
||||||
|
local-networks = config.instance.local-networks;
|
||||||
|
|
||||||
in rec {
|
in rec {
|
||||||
config = mkIf (cfg.enableContainer) {
|
config = mkIf (cfg.enableContainer) {
|
||||||
# Disable postfix on this host--it'll be run in the container instead
|
# Disable postfix on this host--it'll be run in the container instead
|
||||||
services.postfix.enable = false;
|
services.postfix.enable = false;
|
||||||
|
|
||||||
fudo.acme.host-domains.${hostname}.${cfg.mail-hostname} = {
|
|
||||||
local-copies = {
|
|
||||||
postfix = {
|
|
||||||
user = "root";
|
|
||||||
};
|
|
||||||
dovecot-cert = {
|
|
||||||
user = "root";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nginx = mkIf cfg.monitoring {
|
services.nginx = mkIf cfg.monitoring {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
|
@ -36,10 +32,10 @@ in rec {
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
'';
|
'';
|
||||||
trusted-network-string =
|
trusted-network-string =
|
||||||
optionalString ((length config.instance.local-networks) > 0)
|
optionalString ((length local-networks) > 0)
|
||||||
(concatStringsSep "\n"
|
(concatStringsSep "\n"
|
||||||
(map (network: "allow ${network};")
|
(map (network: "allow ${network};")
|
||||||
config.instance.local-networks)) + ''
|
local-networks)) + ''
|
||||||
|
|
||||||
deny all;'';
|
deny all;'';
|
||||||
|
|
||||||
|
@ -85,9 +81,7 @@ in rec {
|
||||||
|
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
|
|
||||||
bindMounts = let
|
bindMounts = {
|
||||||
cert-copies = config.fudo.acme.host-domains.${hostname}.${cfg.mail-hostname}.local-copies;
|
|
||||||
in {
|
|
||||||
"${container-maildir}" = {
|
"${container-maildir}" = {
|
||||||
hostPath = cfg.mail-directory;
|
hostPath = cfg.mail-directory;
|
||||||
isReadOnly = false;
|
isReadOnly = false;
|
||||||
|
@ -98,53 +92,54 @@ in rec {
|
||||||
isReadOnly = false;
|
isReadOnly = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
"/etc/${container-shared}" = {
|
|
||||||
hostPath = "/etc/${container-shared}";
|
|
||||||
isReadOnly = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
"/run/mail/certs/postfix/cert.pem" = {
|
"/run/mail/certs/postfix/cert.pem" = {
|
||||||
hostPath = cert-copies.postfix.certificate;
|
hostPath = cfg.ssl.certificate;
|
||||||
isReadOnly = true;
|
isReadOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
"/run/mail/certs/postfix/key.pem" = {
|
"/run/mail/certs/postfix/key.pem" = {
|
||||||
hostPath = cert-copies.postfix.private-key;
|
hostPath = cfg.ssl.private-key;
|
||||||
isReadOnly = true;
|
isReadOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
"/run/mail/certs/dovecot/cert.pem" = {
|
"/run/mail/certs/dovecot/cert.pem" = {
|
||||||
hostPath = cert-copies.dovecot.certificate;
|
hostPath = cfg.ssl.certificate;
|
||||||
isReadOnly = true;
|
isReadOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
"/run/mail/certs/dovecot/key.pem" = {
|
"/run/mail/certs/dovecot/key.pem" = {
|
||||||
hostPath = cert-copies.dovecot.private-key;
|
hostPath = cfg.ssl.private-key;
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"/run/mail/passwords/dovecot/ldap-reader.passwd" = {
|
||||||
|
hostPath = cfg.dovecot.ldap.reader-password-file;
|
||||||
isReadOnly = true;
|
isReadOnly = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = let
|
|
||||||
initialize-host = import ../../initialize-host.nix;
|
|
||||||
build-timestamp = config.instance.build-timestamp;
|
|
||||||
site = config.instance.site;
|
|
||||||
domain = config.instance.domain;
|
|
||||||
profile = "container";
|
|
||||||
in [
|
|
||||||
(initialize-host {
|
|
||||||
inherit
|
|
||||||
lib
|
|
||||||
pkgs
|
|
||||||
build-timestamp
|
|
||||||
site
|
|
||||||
domain
|
|
||||||
profile;
|
|
||||||
hostname = "mail-container";
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
config = { config, pkgs, ... }: {
|
config = { config, pkgs, ... }: {
|
||||||
|
|
||||||
|
imports = let
|
||||||
|
initialize-host = import ../../initialize.nix;
|
||||||
|
profile = "container";
|
||||||
|
in [
|
||||||
|
./mail.nix
|
||||||
|
|
||||||
|
(initialize-host {
|
||||||
|
inherit
|
||||||
|
lib
|
||||||
|
pkgs
|
||||||
|
build-timestamp
|
||||||
|
site
|
||||||
|
domain
|
||||||
|
profile;
|
||||||
|
hostname = "mail-container";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
instance.build-seed = build-seed;
|
||||||
|
|
||||||
environment.etc = {
|
environment.etc = {
|
||||||
"mail-server/postfix/cert.pem" = {
|
"mail-server/postfix/cert.pem" = {
|
||||||
source = "/run/mail/certs/postfix/cert.pem";
|
source = "/run/mail/certs/postfix/cert.pem";
|
||||||
|
@ -158,59 +153,67 @@ in rec {
|
||||||
};
|
};
|
||||||
"mail-server/dovecot/cert.pem" = {
|
"mail-server/dovecot/cert.pem" = {
|
||||||
source = "/run/mail/certs/dovecot/cert.pem";
|
source = "/run/mail/certs/dovecot/cert.pem";
|
||||||
user = config.services.dovecot.user;
|
user = config.services.dovecot2.user;
|
||||||
mode = "0444";
|
mode = "0444";
|
||||||
};
|
};
|
||||||
"mail-server/dovecot/key.pem" = {
|
"mail-server/dovecot/key.pem" = {
|
||||||
source = "/run/mail/certs/dovecot/key.pem";
|
source = "/run/mail/certs/dovecot/key.pem";
|
||||||
user = config.services.dovecot.user;
|
user = config.services.dovecot2.user;
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
## The pre-script runs as root anyway...
|
||||||
|
# "mail-server/dovecot/ldap-reader.passwd" = {
|
||||||
|
# source = "/run/mail/passwords/dovecot/ldap-reader.passwd";
|
||||||
|
# user = config.services.dovecot2.user;
|
||||||
|
# mode = "0400";
|
||||||
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [ ./mail.nix ];
|
fudo = {
|
||||||
|
|
||||||
fudo.mail-server = {
|
mail-server = {
|
||||||
enable = true;
|
enable = true;
|
||||||
hostname = cfg.hostname;
|
mail-hostname = cfg.mail-hostname;
|
||||||
domain = cfg.domain;
|
domain = cfg.domain;
|
||||||
|
|
||||||
debug = cfg.debug;
|
debug = cfg.debug;
|
||||||
monitoring = cfg.monitoring;
|
monitoring = cfg.monitoring;
|
||||||
|
|
||||||
state-directory = container-statedir;
|
state-directory = container-statedir;
|
||||||
mail-directory = container-maildir;
|
mail-directory = container-maildir;
|
||||||
|
|
||||||
postfix = {
|
postfix = {
|
||||||
ssl-certificate = "/etc/mail-server/postfix/cert.pem";
|
ssl-certificate = "/etc/mail-server/postfix/cert.pem";
|
||||||
ssl-private-key = "/etc/mail-server/postfix/key.pem";
|
ssl-private-key = "/etc/mail-server/postfix/key.pem";
|
||||||
};
|
|
||||||
|
|
||||||
dovecot = {
|
|
||||||
ssl-certificate = "/etc/mail-server/dovecot/cert.pem";
|
|
||||||
ssl-private-key = "/etc/mail-server/dovecot/key.pem";
|
|
||||||
ldap = {
|
|
||||||
server-urls = cfg.dovecot.ldap.server-urls;
|
|
||||||
reader-dn = cfg.dovecot.ldap.reader-dn;
|
|
||||||
reader-passwd = cfg.dovecot.ldap.reader-passwd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dovecot = {
|
||||||
|
ssl-certificate = "/etc/mail-server/dovecot/cert.pem";
|
||||||
|
ssl-private-key = "/etc/mail-server/dovecot/key.pem";
|
||||||
|
ldap = {
|
||||||
|
server-urls = cfg.dovecot.ldap.server-urls;
|
||||||
|
reader-dn = cfg.dovecot.ldap.reader-dn;
|
||||||
|
reader-password-file = "/run/mail/passwords/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;
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ let
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.mail-server = {
|
options.fudo.mail-server = with types; {
|
||||||
enable = mkEnableOption "Fudo Email Server";
|
enable = mkEnableOption "Fudo Email Server";
|
||||||
|
|
||||||
enableContainer = mkEnableOption ''
|
enableContainer = mkEnableOption ''
|
||||||
|
@ -17,18 +17,17 @@ in {
|
||||||
'';
|
'';
|
||||||
|
|
||||||
domain = mkOption {
|
domain = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "The main and default domain name for this email server.";
|
description = "The main and default domain name for this email server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
mail-hostname = mkOption {
|
mail-hostname = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "The domain name to use for the mail server.";
|
description = "The domain name to use for the mail server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ldap-url = mkOption {
|
ldap-url = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "URL of the LDAP server to use for authentication.";
|
description = "URL of the LDAP server to use for authentication.";
|
||||||
example = "ldaps://auth.fudo.org/";
|
example = "ldaps://auth.fudo.org/";
|
||||||
};
|
};
|
||||||
|
@ -36,23 +35,25 @@ in {
|
||||||
monitoring = mkEnableOption "Enable monitoring for the mail server.";
|
monitoring = mkEnableOption "Enable monitoring for the mail server.";
|
||||||
|
|
||||||
mail-user = mkOption {
|
mail-user = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "User to use for mail delivery.";
|
description = "User to use for mail delivery.";
|
||||||
|
default = "mailuser";
|
||||||
};
|
};
|
||||||
|
|
||||||
# No group id, because NixOS doesn't seem to use it
|
# No group id, because NixOS doesn't seem to use it
|
||||||
mail-group = mkOption {
|
mail-group = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Group to use for mail delivery.";
|
description = "Group to use for mail delivery.";
|
||||||
|
default = "mailgroup";
|
||||||
};
|
};
|
||||||
|
|
||||||
mail-user-id = mkOption {
|
mail-user-id = mkOption {
|
||||||
type = types.int;
|
type = int;
|
||||||
description = "UID of mail-user.";
|
description = "UID of mail-user.";
|
||||||
};
|
};
|
||||||
|
|
||||||
local-domains = mkOption {
|
local-domains = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = "A list of domains for which we accept mail.";
|
description = "A list of domains for which we accept mail.";
|
||||||
default = ["localhost" "localhost.localdomain"];
|
default = ["localhost" "localhost.localdomain"];
|
||||||
example = [
|
example = [
|
||||||
|
@ -64,17 +65,17 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
mail-directory = mkOption {
|
mail-directory = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Path to use for mail storage.";
|
description = "Path to use for mail storage.";
|
||||||
};
|
};
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Path to use for state data.";
|
description = "Path to use for state data.";
|
||||||
};
|
};
|
||||||
|
|
||||||
trusted-networks = mkOption {
|
trusted-networks = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = "A list of trusted networks, for which we will happily relay without auth.";
|
description = "A list of trusted networks, for which we will happily relay without auth.";
|
||||||
example = [
|
example = [
|
||||||
"10.0.0.0/16"
|
"10.0.0.0/16"
|
||||||
|
@ -83,7 +84,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
sender-blacklist = mkOption {
|
sender-blacklist = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = "A list of email addresses for whom we will not send email.";
|
description = "A list of email addresses for whom we will not send email.";
|
||||||
default = [];
|
default = [];
|
||||||
example = [
|
example = [
|
||||||
|
@ -93,7 +94,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
recipient-blacklist = mkOption {
|
recipient-blacklist = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description = "A list of email addresses for whom we will not accept email.";
|
description = "A list of email addresses for whom we will not accept email.";
|
||||||
default = [];
|
default = [];
|
||||||
example = [
|
example = [
|
||||||
|
@ -103,14 +104,14 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
message-size-limit = mkOption {
|
message-size-limit = mkOption {
|
||||||
type = types.int;
|
type = int;
|
||||||
description = "Size of max email in megabytes.";
|
description = "Size of max email in megabytes.";
|
||||||
default = 30;
|
default = 30;
|
||||||
};
|
};
|
||||||
|
|
||||||
user-aliases = mkOption {
|
user-aliases = mkOption {
|
||||||
type = with types; attrsOf(listOf str);
|
type = attrsOf (listOf str);
|
||||||
description = "A map of real user to list of aliases.";
|
description = "A map of real user to list of alias emails.";
|
||||||
default = {};
|
default = {};
|
||||||
example = {
|
example = {
|
||||||
someuser = ["alias0" "alias1"];
|
someuser = ["alias0" "alias1"];
|
||||||
|
@ -118,7 +119,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
alias-users = mkOption {
|
alias-users = mkOption {
|
||||||
type = with types; attrsOf(listOf str);
|
type = attrsOf (listOf str);
|
||||||
description = "A map of email alias to a list of users.";
|
description = "A map of email alias to a list of users.";
|
||||||
example = {
|
example = {
|
||||||
alias = ["realuser0" "realuser1"];
|
alias = ["realuser0" "realuser1"];
|
||||||
|
@ -164,15 +165,27 @@ in {
|
||||||
|
|
||||||
debug = mkOption {
|
debug = mkOption {
|
||||||
description = "Enable debugging on mailservers.";
|
description = "Enable debugging on mailservers.";
|
||||||
type = types.bool;
|
type = bool;
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
max-user-connections = mkOption {
|
max-user-connections = mkOption {
|
||||||
description = "Max simultaneous connections per user.";
|
description = "Max simultaneous connections per user.";
|
||||||
type = types.int;
|
type = int;
|
||||||
default = 20;
|
default = 20;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ssl = {
|
||||||
|
certificate = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to the ssl certificate for the mail server to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
private-key = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to the ssl private key for the mail server to use.";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
@ -184,22 +197,26 @@ in {
|
||||||
];
|
];
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${cfg.mail-directory} 770 ${cfg.mail-user} ${cfg.mail-group} - -"
|
||||||
|
];
|
||||||
|
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
allowedTCPPorts = [ 25 110 143 587 993 995 ];
|
allowedTCPPorts = [ 25 110 143 587 993 995 ];
|
||||||
};
|
};
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
users = {
|
users = {
|
||||||
mailuser = {
|
${cfg.mail-user} = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
uid = cfg.mail-user-id;
|
uid = cfg.mail-user-id;
|
||||||
group = "mailgroup";
|
group = cfg.mail-group;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
groups = {
|
groups = {
|
||||||
mailgroup = {
|
${cfg.mail-group} = {
|
||||||
members = ["mailuser"];
|
members = [ cfg.mail-user ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.mail-server;
|
cfg = config.fudo.mail-server;
|
||||||
|
|
||||||
state-directory = "${cfg.state-directory}/dovecot";
|
sieve-path = "${cfg.state-directory}/dovecot/imap_sieve";
|
||||||
|
|
||||||
pipe-bin = pkgs.stdenv.mkDerivation {
|
pipe-bin = pkgs.stdenv.mkDerivation {
|
||||||
name = "pipe_bin";
|
name = "pipe_bin";
|
||||||
|
@ -23,35 +23,47 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
ldap-conf = filename: config:
|
ldap-conf-template = ldap-cfg:
|
||||||
let
|
let
|
||||||
ssl-config = if config.ca == null then ''
|
ssl-config = if (ldap-cfg.ca == null) then ''
|
||||||
tls = no
|
tls = no
|
||||||
tls_require_cert = try
|
tls_require_cert = try
|
||||||
'' else ''
|
'' else ''
|
||||||
tls_ca_cert_file = ${config.ca}
|
tls_ca_cert_file = ${ldap-cfg.ca}
|
||||||
tls = yes
|
tls = yes
|
||||||
tls_require_cert = try
|
tls_require_cert = try
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in
|
in
|
||||||
pkgs.writeText filename ''
|
pkgs.writeText "dovecot2-ldap-config.conf.template" ''
|
||||||
uris = ${concatStringsSep " " config.server-urls}
|
uris = ${concatStringsSep " " ldap-cfg.server-urls}
|
||||||
ldap_version = 3
|
ldap_version = 3
|
||||||
dn = ${config.reader-dn}
|
dn = ${ldap-cfg.reader-dn}
|
||||||
dnpass = ${config.reader-passwd}
|
dnpass = __LDAP_READER_PASSWORD__
|
||||||
auth_bind = yes
|
auth_bind = yes
|
||||||
auth_bind_userdn = uid=%u,ou=members,dc=fudo,dc=org
|
auth_bind_userdn = uid=%u,ou=members,dc=fudo,dc=org
|
||||||
base = dc=fudo,dc=org
|
base = dc=fudo,dc=org
|
||||||
${ssl-config}
|
${ssl-config}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
ldap-conf-generator = ldap-cfg: let
|
||||||
|
template = ldap-conf-template ldap-cfg;
|
||||||
|
target-dir = dirOf ldap-cfg.generated-ldap-config;
|
||||||
|
target = ldap-cfg.generated-ldap-config;
|
||||||
|
in pkgs.writeScript "dovecot2-ldap-password-swapper.sh" ''
|
||||||
|
mkdir -p ${target-dir}
|
||||||
|
touch ${target}
|
||||||
|
chmod 600 ${target}
|
||||||
|
chown ${config.services.dovecot2.user} ${target}
|
||||||
|
LDAP_READER_PASSWORD=$( cat "${ldap-cfg.reader-password-file}" )
|
||||||
|
sed 's/__LDAP_READER_PASSWORD__/$LDAP_READER_PASSWORD/' '${template}' > ${target}
|
||||||
|
'';
|
||||||
|
|
||||||
ldap-passwd-entry = ldap-config: ''
|
ldap-passwd-entry = ldap-config: ''
|
||||||
passdb {
|
passdb {
|
||||||
driver = ldap
|
driver = ldap
|
||||||
args = ${ldap-conf "ldap-passdb.conf" ldap-config}
|
args = ${ldap-conf "ldap-passdb.conf" ldap-config}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
ldapOpts = {
|
ldapOpts = {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
|
@ -61,6 +73,12 @@ let
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
base = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Base of the LDAP server database.";
|
||||||
|
example = "dc=fudo,dc=org";
|
||||||
|
};
|
||||||
|
|
||||||
server-urls = mkOption {
|
server-urls = mkOption {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
description = "A list of LDAP server URLs used for authentication.";
|
description = "A list of LDAP server URLs used for authentication.";
|
||||||
|
@ -69,16 +87,20 @@ let
|
||||||
reader-dn = mkOption {
|
reader-dn = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
DN to use for reading user information. Needs access to homeDirectory,
|
DN to use for reading user information. Needs access to homeDirectory,
|
||||||
uidNumber, gidNumber, and uid, but not password attributes.
|
uidNumber, gidNumber, and uid, but not password attributes.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
reader-passwd = mkOption {
|
reader-password-file = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = ''
|
description = "Password for the user specified in ldap-reader-dn.";
|
||||||
Password for the user specified in ldap-reader-dn.
|
};
|
||||||
'';
|
|
||||||
|
generated-ldap-config = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path at which to store the generated LDAP config file, including password.";
|
||||||
|
default = "/run/dovecot2/config/ldap.conf";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -206,8 +228,12 @@ in {
|
||||||
|
|
||||||
auth_mechanisms = login plain
|
auth_mechanisms = login plain
|
||||||
|
|
||||||
${optionalString (cfg.dovecot.ldap != null)
|
${optionalString (cfg.dovecot.ldap != null) ''
|
||||||
(ldap-passwd-entry cfg.dovecot.ldap)}
|
passdb {
|
||||||
|
driver = ldap
|
||||||
|
args = ${cfg.dovecot.ldap.generated-ldap-config}
|
||||||
|
}
|
||||||
|
''}
|
||||||
userdb {
|
userdb {
|
||||||
driver = static
|
driver = static
|
||||||
args = uid=${toString cfg.mail-user-id} home=${cfg.mail-directory}/%u
|
args = uid=${toString cfg.mail-user-id} home=${cfg.mail-directory}/%u
|
||||||
|
@ -249,12 +275,12 @@ in {
|
||||||
# From elsewhere to Spam folder
|
# From elsewhere to Spam folder
|
||||||
imapsieve_mailbox1_name = Junk
|
imapsieve_mailbox1_name = Junk
|
||||||
imapsieve_mailbox1_causes = COPY
|
imapsieve_mailbox1_causes = COPY
|
||||||
imapsieve_mailbox1_before = file:${state-directory}/imap_sieve/report-spam.sieve
|
imapsieve_mailbox1_before = file:${sieve-path}/report-spam.sieve
|
||||||
# From Spam folder to elsewhere
|
# From Spam folder to elsewhere
|
||||||
imapsieve_mailbox2_name = *
|
imapsieve_mailbox2_name = *
|
||||||
imapsieve_mailbox2_from = Junk
|
imapsieve_mailbox2_from = Junk
|
||||||
imapsieve_mailbox2_causes = COPY
|
imapsieve_mailbox2_causes = COPY
|
||||||
imapsieve_mailbox2_before = file:${state-directory}/imap_sieve/report-ham.sieve
|
imapsieve_mailbox2_before = file:${sieve-path}/report-ham.sieve
|
||||||
sieve_pipe_bin_dir = ${pipe-bin}/pipe/bin
|
sieve_pipe_bin_dir = ${pipe-bin}/pipe/bin
|
||||||
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
|
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
|
||||||
}
|
}
|
||||||
|
@ -268,19 +294,21 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.dovecot2.preStart = ''
|
systemd = {
|
||||||
mkdir -p '${state-directory}'
|
tmpfiles.rules = [
|
||||||
chown ${dovecot-user}:${cfg.mail-group} '${state-directory}'
|
"d ${sieve-path} 750 ${dovecot-user} ${cfg.mail-group} - -"
|
||||||
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}
|
services.dovecot2.preStart = ''
|
||||||
chmod g+w ${cfg.mail-directory}
|
rm -f ${sieve-path}/*
|
||||||
'';
|
cp -p ${./dovecot/imap_sieve}/*.sieve ${sieve-path}
|
||||||
|
for k in ${sieve-path}/*.sieve ; do
|
||||||
|
${pkgs.dovecot_pigeonhole}/bin/sievec "$k"
|
||||||
|
done
|
||||||
|
|
||||||
|
${optionalString (cfg.dovecot.ldap != null)
|
||||||
|
(ldap-conf-generator cfg.dovecot.ldap)}
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = cfg.domain;
|
domain = cfg.domain;
|
||||||
origin = cfg.domain;
|
origin = cfg.domain;
|
||||||
hostname = cfg.hostname;
|
hostname = cfg.mail-hostname;
|
||||||
destination = ["localhost" "localhost.localdomain"];
|
destination = ["localhost" "localhost.localdomain"];
|
||||||
# destination = ["localhost" "localhost.localdomain" cfg.hostname] ++
|
# destination = ["localhost" "localhost.localdomain" cfg.hostname] ++
|
||||||
# cfg.local-domains;;
|
# cfg.local-domains;;
|
||||||
|
@ -150,7 +150,7 @@ in {
|
||||||
# mail_spool_directory = "${cfg.mail-directory}/";
|
# mail_spool_directory = "${cfg.mail-directory}/";
|
||||||
message_size_limit = toString(cfg.message-size-limit * 1024 * 1024);
|
message_size_limit = toString(cfg.message-size-limit * 1024 * 1024);
|
||||||
|
|
||||||
smtpd_banner = "${cfg.hostname} ESMTP NO UCE";
|
smtpd_banner = "${cfg.mail-hostname} ESMTP NO UCE";
|
||||||
|
|
||||||
tls_eecdh_strong_curve = "prime256v1";
|
tls_eecdh_strong_curve = "prime256v1";
|
||||||
tls_eecdh_ultra_curve = "secp384r1";
|
tls_eecdh_ultra_curve = "secp384r1";
|
||||||
|
|
|
@ -4,6 +4,11 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.postgresql;
|
cfg = config.fudo.postgresql;
|
||||||
|
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
|
||||||
|
gssapi-realm = config.fudo.domains.${domain-name}.gssapi-realm;
|
||||||
|
|
||||||
join-lines = lib.concatStringsSep "\n";
|
join-lines = lib.concatStringsSep "\n";
|
||||||
|
|
||||||
userDatabaseOpts = { database, ... }: {
|
userDatabaseOpts = { database, ... }: {
|
||||||
|
@ -28,15 +33,15 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
userOpts = { username, ... }: {
|
userOpts = { username, ... }: {
|
||||||
options = {
|
options = with types; {
|
||||||
password-file = mkOption {
|
password-file = mkOption {
|
||||||
type = with types; nullOr str;
|
type = nullOr str;
|
||||||
description = "A file containing the user's (plaintext) password.";
|
description = "A file containing the user's (plaintext) password.";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
databases = mkOption {
|
databases = mkOption {
|
||||||
type = with types; attrsOf (submodule userDatabaseOpts);
|
type = attrsOf (submodule userDatabaseOpts);
|
||||||
description = "Map of databases to required database/table perms.";
|
description = "Map of databases to required database/table perms.";
|
||||||
default = { };
|
default = { };
|
||||||
example = {
|
example = {
|
||||||
|
@ -50,9 +55,9 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
databaseOpts = { dbname, ... }: {
|
databaseOpts = { dbname, ... }: {
|
||||||
options = {
|
options = with types; {
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
type = with types; listOf str;
|
type = listOf str;
|
||||||
description =
|
description =
|
||||||
"A list of users who should have full access to this database.";
|
"A list of users who should have full access to this database.";
|
||||||
default = [ ];
|
default = [ ];
|
||||||
|
@ -74,9 +79,7 @@ let
|
||||||
'';
|
'';
|
||||||
|
|
||||||
passwords-setter-script = users:
|
passwords-setter-script = users:
|
||||||
pkgs.writeScriptBin "postgres-set-passwords.sh" ''
|
pkgs.writeScript "postgres-set-passwords.sh" ''
|
||||||
#!${pkgs.bash}/bin/bash
|
|
||||||
|
|
||||||
if [ $# -ne 1 ]; then
|
if [ $# -ne 1 ]; then
|
||||||
echo "usage: $0 output-file.sql"
|
echo "usage: $0 output-file.sql"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -99,7 +102,7 @@ let
|
||||||
nameValuePair "DATABASE ${database}" databaseOpts.access) databases;
|
nameValuePair "DATABASE ${database}" databaseOpts.access) databases;
|
||||||
|
|
||||||
makeEntry = nw:
|
makeEntry = nw:
|
||||||
"host all all ${nw} gss include_realm=0 krb_realm=FUDO.ORG";
|
"host all all ${nw} gss include_realm=0 krb_realm=${gssapi-realm}";
|
||||||
|
|
||||||
makeNetworksEntry = networks: join-lines (map makeEntry networks);
|
makeNetworksEntry = networks: join-lines (map makeEntry networks);
|
||||||
|
|
||||||
|
@ -263,8 +266,8 @@ in {
|
||||||
local all all ident
|
local all all ident
|
||||||
|
|
||||||
# host-local
|
# host-local
|
||||||
host all all 127.0.0.1/32 gss include_realm=0 krb_realm=FUDO.ORG
|
host all all 127.0.0.1/32 gss include_realm=0 krb_realm=${gssapi-realm}
|
||||||
host all all ::1/128 gss include_realm=0 krb_realm=FUDO.ORG
|
host all all ::1/128 gss include_realm=0 krb_realm=${gssapi-realm}
|
||||||
|
|
||||||
# local networks
|
# local networks
|
||||||
${makeNetworksEntry cfg.local-networks}
|
${makeNetworksEntry cfg.local-networks}
|
||||||
|
@ -278,8 +281,7 @@ in {
|
||||||
postgresql-password-setter = let
|
postgresql-password-setter = let
|
||||||
passwords-script = passwords-setter-script cfg.users;
|
passwords-script = passwords-setter-script cfg.users;
|
||||||
password-wrapper-script =
|
password-wrapper-script =
|
||||||
pkgs.writeScriptBin "password-script-wrapper.sh" ''
|
pkgs.writeScript "password-script-wrapper.sh" ''
|
||||||
#!${pkgs.bash}/bin/bash
|
|
||||||
TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d -t postgres-XXXXXXXXXX)
|
TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d -t postgres-XXXXXXXXXX)
|
||||||
echo "using temp dir $TMPDIR"
|
echo "using temp dir $TMPDIR"
|
||||||
PASSWORD_SQL_FILE=$TMPDIR/user-passwords.sql
|
PASSWORD_SQL_FILE=$TMPDIR/user-passwords.sql
|
||||||
|
@ -287,7 +289,7 @@ in {
|
||||||
touch $PASSWORD_SQL_FILE
|
touch $PASSWORD_SQL_FILE
|
||||||
chown ${config.services.postgresql.superUser} $PASSWORD_SQL_FILE
|
chown ${config.services.postgresql.superUser} $PASSWORD_SQL_FILE
|
||||||
chmod go-rwx $PASSWORD_SQL_FILE
|
chmod go-rwx $PASSWORD_SQL_FILE
|
||||||
${passwords-script}/bin/postgres-set-passwords.sh $PASSWORD_SQL_FILE
|
${passwords-script} $PASSWORD_SQL_FILE
|
||||||
echo "executing $PASSWORD_SQL_FILE"
|
echo "executing $PASSWORD_SQL_FILE"
|
||||||
${pkgs.postgresql}/bin/psql --port ${
|
${pkgs.postgresql}/bin/psql --port ${
|
||||||
toString config.services.postgresql.port
|
toString config.services.postgresql.port
|
||||||
|
@ -306,7 +308,7 @@ in {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
User = config.services.postgresql.superUser;
|
User = config.services.postgresql.superUser;
|
||||||
};
|
};
|
||||||
script = "${password-wrapper-script}/bin/password-script-wrapper.sh";
|
script = "${password-wrapper-script}";
|
||||||
};
|
};
|
||||||
|
|
||||||
postgresql.postStart = let
|
postgresql.postStart = let
|
||||||
|
|
|
@ -86,15 +86,17 @@ in {
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:9090";
|
proxyPass = "http://127.0.0.1:9090";
|
||||||
|
|
||||||
extraConfig = ''
|
extraConfig = let
|
||||||
|
local-networks = config.instance.local-networks;
|
||||||
|
in ''
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
${optionalString ((length fudo-cfg.local-networks) > 0)
|
${optionalString ((length local-networks) > 0)
|
||||||
(concatStringsSep "\n" (map (network: "allow ${network};") fudo-cfg.local-networks)) + "\ndeny all;"}
|
(concatStringsSep "\n" (map (network: "allow ${network};") local-networks)) + "\ndeny all;"}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -185,18 +185,6 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
# users.users = {
|
|
||||||
# ${site-cfg.build-user} = mkIf
|
|
||||||
# (any (build-host: build-host == config.instance.hostname)
|
|
||||||
# (attrNames site-cfg.build-servers)) {
|
|
||||||
# isSystemUser = true;
|
|
||||||
# openssh.authorizedKeys.keys =
|
|
||||||
# concatMap (hostOpts: hostOpts.build-pubkeys)
|
|
||||||
# (attrValues site-hosts);
|
|
||||||
# shell = pkgs.bash;
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts =
|
networking.firewall.allowedTCPPorts =
|
||||||
mkIf site-cfg.enable-ssh-backdoor [ site-cfg.dropbear-ssh-port ];
|
mkIf site-cfg.enable-ssh-backdoor [ site-cfg.dropbear-ssh-port ];
|
||||||
|
|
||||||
|
|
|
@ -1,65 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
{
|
||||||
hostname = config.instance.hostname;
|
|
||||||
has-attrs = set: length (attrNames set) > 0;
|
|
||||||
host-keypairs =
|
|
||||||
if (hasAttr hostname config.fudo.secrets.files.host-ssh-keypairs) then
|
|
||||||
config.fudo.secrets.files.host-ssh-keypairs.${hostname}
|
|
||||||
else [];
|
|
||||||
|
|
||||||
|
|
||||||
sshfp-filename = host: keypair: "ssh-${host}-${keypair.key-type}.sshfp-record";
|
|
||||||
|
|
||||||
dns-sshfp-records = host: keypair: let
|
|
||||||
filename = sshfp-filename host keypair;
|
|
||||||
in pkgs.stdenv.mkDerivation {
|
|
||||||
name = "${host}-sshfp-record";
|
|
||||||
|
|
||||||
phases = [ "installPhase" ];
|
|
||||||
|
|
||||||
buildInputs = with pkgs; [ openssh ];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir $out
|
|
||||||
ssh-keygen -r REMOVEME -f "${keypair.public-key}" | sed 's/^REMOVEME IN SSHFP //' > $out/${filename}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
read-lines = filename: splitString "\n" (fileContents filename);
|
|
||||||
|
|
||||||
host-cfg = config.fudo.hosts.${hostname};
|
|
||||||
|
|
||||||
in {
|
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
|
||||||
secrets.host-secrets.${hostname} = listToAttrs
|
|
||||||
(map
|
|
||||||
(keypair: nameValuePair "host-${keypair.key-type}-private-key" {
|
|
||||||
source-file = keypair.private-key;
|
|
||||||
target-file = "/var/run/ssh/private/host-${keypair.key-type}-private-key";
|
|
||||||
user = "root";
|
|
||||||
})
|
|
||||||
host-keypairs);
|
|
||||||
|
|
||||||
hosts = mapAttrs (hostname: keypairs: {
|
|
||||||
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
|
|
||||||
ssh-fingerprints = concatMap (keypair:
|
|
||||||
let
|
|
||||||
fingerprint-derivation = dns-sshfp-records hostname keypair;
|
|
||||||
filename = sshfp-filename hostname keypair;
|
|
||||||
in read-lines "${fingerprint-derivation}/${filename}") keypairs;
|
|
||||||
}) config.fudo.secrets.files.host-ssh-keypairs;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.openssh.hostKeys = map (keypair: {
|
|
||||||
path = "/var/run/ssh/private/host-${keypair.key-type}-private-key";
|
|
||||||
type = keypair.key-type;
|
|
||||||
}) host-keypairs;
|
|
||||||
|
|
||||||
programs.ssh.knownHosts = let
|
programs.ssh.knownHosts = let
|
||||||
|
|
||||||
keyed-hosts =
|
keyed-hosts =
|
||||||
filterAttrs (h: o: o.ssh-pubkeys != [])
|
filterAttrs (h: o: o.ssh-pubkeys != [])
|
||||||
config.fudo.hosts;
|
config.fudo.hosts;
|
||||||
|
@ -75,7 +19,7 @@ in {
|
||||||
|
|
||||||
in mapAttrs (hostname: hostOpts: {
|
in mapAttrs (hostname: hostOpts: {
|
||||||
publicKeyFile = builtins.head hostOpts.ssh-pubkeys;
|
publicKeyFile = builtins.head hostOpts.ssh-pubkeys;
|
||||||
hostNames = all-hostnames hostname host-cfg;
|
hostNames = all-hostnames hostname hostOpts;
|
||||||
}) keyed-hosts;
|
}) keyed-hosts;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
# Common home-manager config
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
list-contains = lst: item: any (i: i == item) lst;
|
|
||||||
|
|
||||||
domain-realm = domain: domainOpts: domainOpts.gssapi-realm;
|
|
||||||
|
|
||||||
user-realms = username:
|
|
||||||
mapAttrsToList domain-realm
|
|
||||||
(filterAttrs (domain: domainOpts: list-contains domainOpts.local-users username)
|
|
||||||
config.fudo.domains);
|
|
||||||
|
|
||||||
user-principals = username:
|
|
||||||
map (realm: "${username}@${realm}") (user-realms username);
|
|
||||||
|
|
||||||
user-k5login = username: userOpts: let
|
|
||||||
principals = userOpts.k5login ++ (user-principals username);
|
|
||||||
in ''
|
|
||||||
${concatStringsSep "\n" principals}
|
|
||||||
'';
|
|
||||||
|
|
||||||
user-config = username: userOpts: {
|
|
||||||
home.file.".k5login" = {
|
|
||||||
source = pkgs.writeText "${username}-k5login" (user-k5login username userOpts);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
in {
|
|
||||||
config.home-manager.users = mapAttrs user-config config.instance.local-users;
|
|
||||||
}
|
|
|
@ -65,34 +65,17 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [ ./users-common.nix ];
|
|
||||||
|
|
||||||
config = let
|
config = let
|
||||||
sys = config.instance;
|
sys = config.instance;
|
||||||
in {
|
in {
|
||||||
fudo.auth.ldap-server = let
|
fudo.auth.ldap-server = {
|
||||||
ldapUsers = (filterAttrs
|
users = filterAttrs
|
||||||
(username: userOpts: userOpts.ldap-hashed-password != null))
|
(username: userOpts: userOpts.ldap-hashed-passwd != null)
|
||||||
config.fudo.users;
|
config.fudo.users;
|
||||||
|
|
||||||
in {
|
groups = config.fudo.groups;
|
||||||
users = mapAttrs (username: userOpts: {
|
|
||||||
uid = userOpts.uid;
|
|
||||||
group = userOpts.primary-group;
|
|
||||||
common-name = userOpts.common-name;
|
|
||||||
hashed-password = userOpts.ldap-hashed-password;
|
|
||||||
}) ldapUsers;
|
|
||||||
|
|
||||||
groups = mapAttrs (groupname: groupOpts: {
|
system-users = config.fudo.system-users;
|
||||||
gid = groupOpts.gid-number;
|
|
||||||
description = groupOpts.description;
|
|
||||||
members = filterExistingUsers ldapUsers groupOpts.members;
|
|
||||||
}) config.fudo.groups;
|
|
||||||
|
|
||||||
system-users = mapAttrs (username: userOpts: {
|
|
||||||
description = userOpts.description;
|
|
||||||
hashed-password = userOpts.ldap-hashed-passwd;
|
|
||||||
}) config.fudo.system-users;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.ssh.extraConfig = mkAfter ''
|
programs.ssh.extraConfig = mkAfter ''
|
||||||
|
@ -161,9 +144,6 @@ in {
|
||||||
in admin-entries // user-entries;
|
in admin-entries // user-entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO: This is NOT where this should be...
|
|
||||||
home-manager.useGlobalPkgs = true;
|
|
||||||
|
|
||||||
# Group home directories have to exist, otherwise users can't log in
|
# Group home directories have to exist, otherwise users can't log in
|
||||||
systemd.services = let
|
systemd.services = let
|
||||||
ensure-group-directories = group:
|
ensure-group-directories = group:
|
||||||
|
|
|
@ -302,7 +302,7 @@ in {
|
||||||
(site: site-cfg: let
|
(site: site-cfg: let
|
||||||
|
|
||||||
site-config-file = builtins.toFile "${site}-rainloop.cfg"
|
site-config-file = builtins.toFile "${site}-rainloop.cfg"
|
||||||
(import ./include/rainloop.nix lib site site-cfg site-pkgs.${site}.version);
|
(import ./include/rainloop.nix lib site site-cfg site-packages.${site}.version);
|
||||||
|
|
||||||
domain-config-file = builtins.toFile "${site}-domain.cfg" ''
|
domain-config-file = builtins.toFile "${site}-domain.cfg" ''
|
||||||
imap_host = "${site-cfg.mail-server}"
|
imap_host = "${site-cfg.mail-server}"
|
||||||
|
@ -342,7 +342,7 @@ in {
|
||||||
link-configs = concatStringsSep "\n" (mapAttrsToList (site: site-cfg:
|
link-configs = concatStringsSep "\n" (mapAttrsToList (site: site-cfg:
|
||||||
let
|
let
|
||||||
cfg-file = config.fudo.secrets.host-secrets.${hostname}."${site}-site-config".target-file;
|
cfg-file = config.fudo.secrets.host-secrets.${hostname}."${site}-site-config".target-file;
|
||||||
domain-cfg-file = config.fudo.secrets.host-secrets.${hostname}."${site}-doomain-config".target-file;
|
domain-cfg-file = config.fudo.secrets.host-secrets.${hostname}."${site}-domain-config".target-file;
|
||||||
in ''
|
in ''
|
||||||
${pkgs.coreutils}/bin/mkdir -p ${base-data-path}/${site}/_data_/_default_/configs
|
${pkgs.coreutils}/bin/mkdir -p ${base-data-path}/${site}/_data_/_default_/configs
|
||||||
${pkgs.coreutils}/bin/cp ${cfg-file} ${base-data-path}/${site}/_data_/_default_/configs/application.ini
|
${pkgs.coreutils}/bin/cp ${cfg-file} ${base-data-path}/${site}/_data_/_default_/configs/application.ini
|
||||||
|
|
|
@ -52,6 +52,11 @@ in {
|
||||||
description = "List of users who should have access to the local host";
|
description = "List of users who should have access to the local host";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
local-networks = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "Networks which are considered local to this host, site, or domain.";
|
||||||
|
};
|
||||||
|
|
||||||
build-seed = mkOption {
|
build-seed = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Seed used to generate configuration.";
|
description = "Seed used to generate configuration.";
|
||||||
|
@ -87,25 +92,23 @@ in {
|
||||||
filterAttrs (host: hostOpts: hostOpts.site == local-site) config.fudo.hosts;
|
filterAttrs (host: hostOpts: hostOpts.site == local-site) config.fudo.hosts;
|
||||||
|
|
||||||
local-networks =
|
local-networks =
|
||||||
host.local-networks //
|
host.local-networks ++
|
||||||
config.fudo.domains.${local-domain}.local-networks //
|
config.fudo.domains.${local-domain}.local-networks ++
|
||||||
config.fudo.sites.${local-site}.local-networks;
|
config.fudo.sites.${local-site}.local-networks;
|
||||||
|
|
||||||
local-profile = host.profile;
|
local-profile = host.profile;
|
||||||
|
|
||||||
build-seed = builtins.readFile config.fudo.secrets.files.build-seed;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
instance = {
|
instance = {
|
||||||
inherit
|
inherit
|
||||||
build-seed
|
|
||||||
local-domain
|
local-domain
|
||||||
local-site
|
local-site
|
||||||
local-users
|
local-users
|
||||||
local-admins
|
local-admins
|
||||||
local-groups
|
local-groups
|
||||||
local-hosts
|
local-hosts
|
||||||
local-profile;
|
local-profile
|
||||||
|
local-networks;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
with pkgs.lib;
|
||||||
|
let
|
||||||
|
generate-mac-address = hostname: interface: pkgs.stdenv.mkDerivation {
|
||||||
|
name = "mk-mac-${hostname}-${interface}";
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
installPhase = ''
|
||||||
|
echo ${hostname}-${interface} | sha1sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' > $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
generate-mac-address = hostname: interface: let
|
||||||
|
pkg = generate-mac-address hostname interface;
|
||||||
|
in builtins.readFile "${pkg}";
|
||||||
|
}
|
|
@ -4,9 +4,10 @@
|
||||||
lib = prev.lib;
|
lib = prev.lib;
|
||||||
in {
|
in {
|
||||||
ip = import ./ip.nix { pkgs = prev; };
|
ip = import ./ip.nix { pkgs = prev; };
|
||||||
dns = import ./dns.nix { pkgs = prev;};
|
dns = import ./dns.nix { pkgs = prev; };
|
||||||
passwd = import ./passwd.nix { pkgs = prev;};
|
passwd = import ./passwd.nix { pkgs = prev; };
|
||||||
lisp = import ./lisp.nix { pkgs = prev;};
|
lisp = import ./lisp.nix { pkgs = prev; };
|
||||||
|
network = import ./network.nix { pkgs = prev; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,23 +5,17 @@ let
|
||||||
hash-ldap-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
|
hash-ldap-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-ldap-passwd";
|
name = "${name}-ldap-passwd";
|
||||||
|
|
||||||
phases = [ "buildPhase" "installPhase" ];
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
buildInputs = with pkgs; [ openldap ];
|
buildInputs = with pkgs; [ openldap ];
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
slappasswd -T ${passwd-file} > ldap-passwd
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out
|
slappasswd -T ${passwd-file} > $out
|
||||||
mv ldap-passwd $out
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
hash-ldap-passwd = name: passwd-file: let
|
hash-ldap-passwd = name: passwd-file:
|
||||||
passwd-pkgs = hash-ldap-passwd-pkg name passwd-file;
|
builtins.readFile "${hash-ldap-passwd-pkg name passwd-file}";
|
||||||
in builtins.readFile "${passwd-pkgs}/ldap-passwd";
|
|
||||||
|
|
||||||
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-random-passwd";
|
name = "${name}-random-passwd";
|
||||||
|
@ -31,7 +25,7 @@ let
|
||||||
buildInputs = with pkgs; [ pwgen ];
|
buildInputs = with pkgs; [ pwgen ];
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
pwgen --secure --num-passwords=1 ${length} > $out
|
pwgen --secure --num-passwords=1 ${toString length} > $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -108,15 +108,21 @@ rec {
|
||||||
description = "User's primary email address.";
|
description = "User's primary email address.";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
email-aliases = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "Email aliases that should map to this user.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
groupOpts = { group-name, ... }: {
|
groupOpts = { name, ... }: {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
# group-name = mkOption {
|
group-name = mkOption {
|
||||||
# description = "Group name.";
|
description = "Group name.";
|
||||||
# default = group-name;
|
default = name;
|
||||||
# };
|
};
|
||||||
|
|
||||||
description = mkOption {
|
description = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
|
|
Loading…
Reference in New Issue