Partway to getting France back in the fold. Stuck on ACME certs.
This commit is contained in:
parent
81aae5cd8d
commit
08766dfeb6
|
@ -13,7 +13,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
"sea.fudo.org" = {
|
"sea.fudo.org" = {
|
||||||
local-networks = [ "10.0.0.0/24" ];
|
local-networks = [ "10.0.0.0/16" ];
|
||||||
|
|
||||||
local-users = [ "niten" "reaper" "xiaoxuan" "ken" ];
|
local-users = [ "niten" "reaper" "xiaoxuan" "ken" ];
|
||||||
local-groups = [ "fudo" "selby" "admin" ];
|
local-groups = [ "fudo" "selby" "admin" ];
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
"rus.selby.ca" = {
|
"rus.selby.ca" = {
|
||||||
local-networks = [ "10.0.0.0/24" ];
|
local-networks = [ "10.0.0.0/16" ];
|
||||||
|
|
||||||
local-users = [
|
local-users = [
|
||||||
"niten"
|
"niten"
|
||||||
|
|
|
@ -1,27 +1,59 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
boot = {
|
boot = {
|
||||||
loader = {
|
loader = {
|
||||||
systemd-boot.enable = true;
|
systemd-boot.enable = true;
|
||||||
efi.canTouchEfiVariables = true;
|
efi.canTouchEfiVariables = true;
|
||||||
};
|
};
|
||||||
initrd = {
|
initrd = {
|
||||||
availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "sd_mod" ];
|
availableKernelModules =
|
||||||
|
[ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
kernelModules = [ ];
|
kernelModules = [ ];
|
||||||
};
|
};
|
||||||
kernelModules = [ "kvm-intel" ];
|
kernelModules = [ "kvm-intel" ];
|
||||||
|
kernelPackages = pkgs.linuxPackages_latest;
|
||||||
extraModulePackages = [ ];
|
extraModulePackages = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems."/" = {
|
system.stateVersion = "21.05";
|
||||||
device = "/dev/disk/by-label/zbox-root";
|
|
||||||
fsType = "btrfs";
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/boot" = {
|
fileSystems = {
|
||||||
device = "/dev/disk/by-label/BOOT";
|
"/" = {
|
||||||
fsType = "vfat";
|
device = "zbox-root";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [ "mode=755" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/boot" = {
|
||||||
|
device = "/dev/disk/by-label/ZBOX-BOOT";
|
||||||
|
fsType = "vfat";
|
||||||
|
options = [ "noexec" "noatime" "nodiratime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/state" = {
|
||||||
|
device = "/dev/disk/by-label/zbox-data";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "nodiratime" "compress=zstd" "noexec" "subvol=@state" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/nix" = {
|
||||||
|
device = "/dev/disk/by-label/zbox-data";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "nodiratime" "compress=zstd" "subvol=@nix" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/var/log" = {
|
||||||
|
device = "/dev/disk/by-label/zbox-data";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "nodiratime" "compress=zstd" "noexec" "subvol=@logs" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/home" = {
|
||||||
|
device = "/dev/disk/by-label/zbox-data";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "nodiratime" "compress=zstd" "noexec" "subvol=@home" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
swapDevices = [{ device = "/dev/disk/by-label/zbox-swap"; }];
|
swapDevices = [{ device = "/dev/disk/by-label/zbox-swap"; }];
|
||||||
|
@ -34,14 +66,23 @@
|
||||||
opengl = {
|
opengl = {
|
||||||
driSupport = true;
|
driSupport = true;
|
||||||
driSupport32Bit = true;
|
driSupport32Bit = true;
|
||||||
|
extraPackages = with pkgs; [
|
||||||
# extraPackages32 = with pkgs.i686Linux; [ libva ];
|
rocm-opencl-icd
|
||||||
|
rocm-opencl-runtime
|
||||||
|
amdvlk
|
||||||
|
driversi686Linux.amdvlk
|
||||||
|
];
|
||||||
|
setLdLibraryPath = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
pulseaudio = {
|
pulseaudio = {
|
||||||
support32Bit = true;
|
support32Bit = true;
|
||||||
package = pkgs.pulseaudioFull;
|
package = pkgs.pulseaudioFull;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enableRedistributableFirmware = true;
|
||||||
|
|
||||||
|
enableAllFirmware = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
|
@ -64,4 +105,11 @@
|
||||||
|
|
||||||
nix.maxJobs = lib.mkDefault 8;
|
nix.maxJobs = lib.mkDefault 8;
|
||||||
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||||
|
|
||||||
|
systemd.targets = {
|
||||||
|
sleep.enable = false;
|
||||||
|
suspend.enable = false;
|
||||||
|
hibernate.enable = false;
|
||||||
|
hybrid-sleep.enable = false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ in {
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 22;
|
prefixLength = 16;
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
let
|
let
|
||||||
primary-ip = "208.81.3.117";
|
primary-ip = "208.81.3.117";
|
||||||
git-server-ip = "208.81.3.118";
|
git-server-ip = "208.81.3.118";
|
||||||
|
@ -9,131 +10,61 @@ let
|
||||||
host-fqdn = "${hostname}.${domain-name}";
|
host-fqdn = "${hostname}.${domain-name}";
|
||||||
mail-hostname = "mail.fudo.org";
|
mail-hostname = "mail.fudo.org";
|
||||||
|
|
||||||
|
france-secrets = config.fudo.secrets.host-secrets.france;
|
||||||
|
|
||||||
|
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
|
||||||
|
acme-certificate = hostname: "/var/lib/acme/${hostname}/fullchain.pem";
|
||||||
|
|
||||||
in {
|
in {
|
||||||
imports = [ ./france/postgresql.nix ];
|
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 nix-files ./france;
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
fudo = {
|
||||||
auth = {
|
hosts.france.external-interfaces = [ "extif0" ];
|
||||||
ldap = {
|
|
||||||
enable = true;
|
|
||||||
base = "dc=fudo,dc=org";
|
|
||||||
organization = "Fudo";
|
|
||||||
rootpw-file = "FIXME";
|
|
||||||
kerberos-host = host-fqdn;
|
|
||||||
kerberos-keytab = "FIXME";
|
|
||||||
|
|
||||||
sslCert = "FIXME";
|
|
||||||
sslKey = "FIXME";
|
|
||||||
sslCaCert = "FIXME";
|
|
||||||
|
|
||||||
listen-uris = [ "ldap:///" "ldaps:///" "ldapi:///" ];
|
|
||||||
|
|
||||||
users = config.fudo.users;
|
|
||||||
groups = config.fudo.groups;
|
|
||||||
system-users = config.fudo.system-users;
|
|
||||||
};
|
|
||||||
|
|
||||||
kdc = let realm = "FUDO.ORG";
|
|
||||||
in {
|
|
||||||
enable = true;
|
|
||||||
database-path = "FIXME";
|
|
||||||
realm = realm;
|
|
||||||
mkey-file = "FIXME";
|
|
||||||
acl = [
|
|
||||||
{
|
|
||||||
principal = "pam_migrate/*.fudo.org@${realm}";
|
|
||||||
access = "add";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
principal = "host/*.fudo.org@${realm}";
|
|
||||||
access = "add";
|
|
||||||
}
|
|
||||||
] ++ (concatMap (user: [
|
|
||||||
{
|
|
||||||
principal = "${user}@${realm}";
|
|
||||||
access = "add,list,modify";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
principal = "${user}/root@${realm}";
|
|
||||||
access = "all";
|
|
||||||
}
|
|
||||||
]) domain.admin-users);
|
|
||||||
bind-addresses = [ primary-ip "127.0.0.1" "127.0.1.1" "::1" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
prometheus = {
|
|
||||||
enable = true;
|
|
||||||
hostname = "metrics.fudo.org";
|
|
||||||
service-discovery-dns = let dns-root = "_metrics._tcp.fudo.org";
|
|
||||||
in {
|
|
||||||
node = [ "node.${dns-root}" ];
|
|
||||||
postfix = [ "postfix.${dns-root}" ];
|
|
||||||
dovecot = [ "dovecot.${dns-root}" ];
|
|
||||||
rspamd = [ "rspamd.${dns-root}" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
postgresql = {
|
|
||||||
enable = true;
|
|
||||||
# FIXME: ssl-private-key && ssl certificate
|
|
||||||
keytab = "/srv/postgres/secure/postgres.keytab";
|
|
||||||
local-networks = getHostLocalNetworks hostname;
|
|
||||||
admin-users = domain.admin-users;
|
|
||||||
};
|
|
||||||
|
|
||||||
client.dns = {
|
client.dns = {
|
||||||
enable = true;
|
enable = true;
|
||||||
ipv4 = true;
|
ipv4 = true;
|
||||||
ipv6 = true;
|
ipv6 = true;
|
||||||
user = "FIXME";
|
user = "fudo-client";
|
||||||
external-interface = "extif0";
|
external-interface = "extif0";
|
||||||
password-file = "FIXME";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mail-server = domain.mail-config // {
|
france = {
|
||||||
enableContainer = true;
|
mail = {
|
||||||
monitoring = true;
|
mail-directory = "/state/mail-server/mail";
|
||||||
|
state-directory = "/state/mail-server/var";
|
||||||
hostname = mail-hostname;
|
ldap-server-urls = [
|
||||||
|
"ldap://france.fudo.org"
|
||||||
state-directory = "FIXME";
|
];
|
||||||
mail-directory = "FIXME";
|
|
||||||
|
|
||||||
dovecot.ldap = {
|
|
||||||
reader-dn = "FIXME";
|
|
||||||
reader-password = "FIXME";
|
|
||||||
server-urls = [ "FIXME" ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
clamav.enable = true;
|
webmail = {
|
||||||
dkim.signing = true;
|
# TODO: this is not using the database!
|
||||||
};
|
mail-server = mail-hostname;
|
||||||
|
database.hostname = "localhost";
|
||||||
git = {
|
|
||||||
enable = true;
|
|
||||||
hostname = "git.fudo.org";
|
|
||||||
site-name = "Fudo Git";
|
|
||||||
user = "FIXME";
|
|
||||||
database = {
|
|
||||||
user = "FIXME";
|
|
||||||
password-file = "FIXME";
|
|
||||||
hostname = "127.0.0.1";
|
|
||||||
name = "FIXME";
|
|
||||||
};
|
};
|
||||||
repository-dir = "FIXME";
|
|
||||||
state-dir = "FIXME";
|
git = {
|
||||||
ssh = {
|
repository-directory = "/state/gitea/repo";
|
||||||
listen-ip = git-server-ip;
|
state-directory = "/state/gitea/state";
|
||||||
listen-port = 22;
|
ssh.listen-ip = git-server-ip;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
minecraft-server = {
|
minecraft-server = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.minecraft-current;
|
package = pkgs.minecraft-current;
|
||||||
data-dir = "FIXME";
|
data-dir = "/state/minecraft/selbyland";
|
||||||
world-name = "selbyland";
|
world-name = "selbyland";
|
||||||
motd = "Welcome to the Selby Minecraft server.";
|
motd = "Welcome to the Selby Minecraft server.";
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
site-name = config.instance.local-site;
|
||||||
|
fqdn = "${hostname}.${domain-name}";
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.france;
|
||||||
|
|
||||||
|
# same as genAttr, but takes back attrsets and merges them
|
||||||
|
concatGenAttrs = lst: f:
|
||||||
|
foldr (a0: a1: a0 // a1) {} (map f lst);
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.france = with types; {
|
||||||
|
ldap = {
|
||||||
|
ssl-certificate = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "SSL certificate to use for the LDAP server.";
|
||||||
|
};
|
||||||
|
ssl-private-key = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "SSL private key to use for the LDAP server.";
|
||||||
|
};
|
||||||
|
ssl-ca-certificate = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "SSL certificate authority to use for the LDAP server.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
kdc = {
|
||||||
|
state-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path at which to store kerberos state.";
|
||||||
|
};
|
||||||
|
|
||||||
|
master-key-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Heimdal database master key file.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
fudo = {
|
||||||
|
secrets.host-secrets.${hostname} = {
|
||||||
|
ldap-ssl-certificate = {
|
||||||
|
source-file = cfg.ssl-certificate;
|
||||||
|
target-file = "/var/run/ldap/ssl-certificate.pem";
|
||||||
|
user = config.services.openldap.user;
|
||||||
|
group = config.services.openldap.group;
|
||||||
|
permissions = "0444";
|
||||||
|
};
|
||||||
|
ldap-ssl-private-key = {
|
||||||
|
source-file = cfg.ssl-private-key;
|
||||||
|
target-file = "/var/run/ldap/ssl-private-key.pem";
|
||||||
|
user = config.services.openldap.user;
|
||||||
|
group = config.services.openldap.group;
|
||||||
|
permissions = "0400";
|
||||||
|
};
|
||||||
|
ldap-ssl-ca-certificate = {
|
||||||
|
source-file = cfg.ssl-ca-certificate;
|
||||||
|
target-file = "/var/run/ldap/ssl-ca-certificate.pem";
|
||||||
|
user = config.services.openldap.user;
|
||||||
|
group = config.services.openldap.group;
|
||||||
|
permissions = "0400";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
auth = {
|
||||||
|
ldap = {
|
||||||
|
enable = true;
|
||||||
|
base = "dc=fudo,dc=org";
|
||||||
|
organization = "Fudo";
|
||||||
|
rootpw-file = secrets.ldap-root-passwd;
|
||||||
|
kerberos-host = fqdn;
|
||||||
|
kerberos-keytab = secrets.ldap-keytab;
|
||||||
|
|
||||||
|
sslCert =
|
||||||
|
secrets.ldap-ssl-certificate.target-file;
|
||||||
|
sslKey =
|
||||||
|
secrets.ldap-ssl-private-key.target-file;
|
||||||
|
sslCACert =
|
||||||
|
secrets.ldap-ssl-ca-certificate.target-file;
|
||||||
|
|
||||||
|
listen-uris = [ "ldap:///" "ldaps:///" "ldapi:///" ];
|
||||||
|
|
||||||
|
users = config.fudo.users;
|
||||||
|
groups = config.fudo.groups;
|
||||||
|
system-users = config.fudo.system-users;
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: let build hosts create keys?
|
||||||
|
kdc = {
|
||||||
|
enable = true;
|
||||||
|
realm = config.domains.${domain-name}.gssapi-realm;
|
||||||
|
state-directory = cfg.state-directory;
|
||||||
|
master-key-file = cfg.master-key-file;
|
||||||
|
acl = let
|
||||||
|
admin-entries = concatGenAttrs
|
||||||
|
config.instance.local-admins
|
||||||
|
(admin: {
|
||||||
|
"${admin}" = { perms = [ "add" "list" "change-password" ]; };
|
||||||
|
"${admin}/root" = { perms = [ "all" ]; };
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
"host/*.fudo.org" = { perms = [ "add" ]; };
|
||||||
|
"pam_migrate/*.fudo.org" = { perms = [ "add" "change-password" ]; };
|
||||||
|
} // admin-entries;
|
||||||
|
bind-addresses = [ primary-ip "127.0.0.1" "127.0.1.1" "::1" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
sshOpts = { ... }: {
|
||||||
|
options = {
|
||||||
|
listen-ip = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "IP address on which to listen for SSH connections.";
|
||||||
|
};
|
||||||
|
listen-port = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Port on which to listen for SSH connections.";
|
||||||
|
default = 22;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.france.git = with types; {
|
||||||
|
repository-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to store git repositories.";
|
||||||
|
};
|
||||||
|
state-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to store git server state.";
|
||||||
|
};
|
||||||
|
database-host = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "PostGreSQL database host.";
|
||||||
|
};
|
||||||
|
ssh = mkOption {
|
||||||
|
type = submodule sshOpts;
|
||||||
|
description = "Git SSH listen options.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config.fudo = {
|
||||||
|
postgresql = {
|
||||||
|
databases.fudo_git.users =
|
||||||
|
config.instance.local_admins;
|
||||||
|
|
||||||
|
users.fudo_git = {
|
||||||
|
password-file =
|
||||||
|
secrets.git-database-password.target-file;
|
||||||
|
databases = {
|
||||||
|
fudo_git = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" =
|
||||||
|
"SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" =
|
||||||
|
"SELECT, UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
git = {
|
||||||
|
enable = true;
|
||||||
|
hostname = "git.${domain-name}";
|
||||||
|
site-name = "Fudo Git";
|
||||||
|
user = "git-fudo";
|
||||||
|
repository-dir = cfg.repository-directory;
|
||||||
|
state-dir = cfg.state-directory;
|
||||||
|
database = {
|
||||||
|
user = "fudo_git";
|
||||||
|
password-file =
|
||||||
|
secrets.git-database-password.target-file;
|
||||||
|
hostname = cfg.database-host;
|
||||||
|
name = "fudo_git";
|
||||||
|
};
|
||||||
|
ssh = {
|
||||||
|
listen-ip = cfg.ssh.listen-ip;
|
||||||
|
listen-port = cfg.ssh.listen-port;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
in {
|
||||||
|
config = {
|
||||||
|
fudo = {
|
||||||
|
jabber = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
secret-files = {
|
||||||
|
LDAP_PASSWORD = secrets.jabber-ldap-password.target-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
sites = {
|
||||||
|
"fudo.im" = {
|
||||||
|
site-config = {
|
||||||
|
auth_method = "ldap";
|
||||||
|
ldap_servers = [ "auth.fudo.org" ];
|
||||||
|
ldap_port = 389;
|
||||||
|
ldap_rootdn = "cn=jabber,dc=fudo,dc=org";
|
||||||
|
ldap_password = ''"LDAP_PASSWD"'';
|
||||||
|
ldap_base = "ou=members,dc=fudo,dc=org";
|
||||||
|
ldap_filter = "(objectClass=posixAccount)";
|
||||||
|
ldap_uids = { uid = "%u"; };
|
||||||
|
|
||||||
|
modules = {
|
||||||
|
mod_adhoc = {};
|
||||||
|
mod_announce = {};
|
||||||
|
mod_avatar = {};
|
||||||
|
mod_blocking = {};
|
||||||
|
mod_caps = {};
|
||||||
|
mod_carboncopy = {};
|
||||||
|
mod_client_state = {};
|
||||||
|
mod_configure = {};
|
||||||
|
mod_disco = {};
|
||||||
|
mod_fail2ban = {};
|
||||||
|
mod_last = {};
|
||||||
|
mod_offline = {
|
||||||
|
access_max_user_messages = 5000;
|
||||||
|
};
|
||||||
|
mod_ping = {};
|
||||||
|
mod_privacy = {};
|
||||||
|
mod_private = {};
|
||||||
|
mod_pubsub = {
|
||||||
|
access_createnode = "pubsub_createnode";
|
||||||
|
ignore_pep_from_offline = true;
|
||||||
|
last_item_cache = false;
|
||||||
|
plugins = [
|
||||||
|
"flat"
|
||||||
|
"pep"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
mod_roster = {};
|
||||||
|
mod_stream_mgmt = {};
|
||||||
|
mod_time = {};
|
||||||
|
mod_vcard = {
|
||||||
|
search = false;
|
||||||
|
};
|
||||||
|
mod_vcard_xupdate = {};
|
||||||
|
mod_version = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"backplane.fudo.org" = {
|
||||||
|
site-config = {
|
||||||
|
auth_method = "external";
|
||||||
|
extauth_program = "${pkgs.guile}/bin/guile -s ${backplane-auth}";
|
||||||
|
extauth_pool_size = 3;
|
||||||
|
auth_use_cache = true;
|
||||||
|
|
||||||
|
modules = {
|
||||||
|
mod_adhoc = {};
|
||||||
|
mod_caps = {};
|
||||||
|
mod_carboncopy = {};
|
||||||
|
mod_client_state = {};
|
||||||
|
mod_configure = {};
|
||||||
|
mod_disco = {};
|
||||||
|
mod_fail2ban = {};
|
||||||
|
mod_last = {};
|
||||||
|
mod_offline = {
|
||||||
|
access_max_user_messages = 5000;
|
||||||
|
};
|
||||||
|
mod_ping = {};
|
||||||
|
mod_pubsub = {
|
||||||
|
access_createnode = "pubsub_createnode";
|
||||||
|
ignore_pep_from_offline = true;
|
||||||
|
last_item_cache = false;
|
||||||
|
plugins = [
|
||||||
|
"flat"
|
||||||
|
"pep"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
mod_roster = {};
|
||||||
|
mod_stream_mgmt = {};
|
||||||
|
mod_time = {};
|
||||||
|
mod_version = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
mail-reader-dn = "mail-auth-reader";
|
||||||
|
in {
|
||||||
|
options.france.mail = with types; {
|
||||||
|
mail-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Directory to contain user maildirs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
state-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Directory to contain mail-server state.";
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap-server-urls = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of LDAP server URLs.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config.fudo = {
|
||||||
|
system-users = {
|
||||||
|
username = mail-reader-dn;
|
||||||
|
description = "Used by the mail server to connect to LDAP for auth.";
|
||||||
|
ldap-hashed-password =
|
||||||
|
pkgs.lib.fudo.passwd.hash-ldap-passwd
|
||||||
|
secrets.mail-reader-passwd.target-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
mail-server = {
|
||||||
|
enableContainer = true;
|
||||||
|
monitoring = true;
|
||||||
|
|
||||||
|
hostname = "mail.${domain-name}";
|
||||||
|
|
||||||
|
state-directory = cfg.state-directory;
|
||||||
|
mail-directory = cfg.mail-directory;
|
||||||
|
|
||||||
|
dovecot.ldap = {
|
||||||
|
reader-dn = "cn=mail-reader-dn,${config.fudo.auth.ldap.base}";
|
||||||
|
reader-password-file = secrets.mail-reader-passwd.target-file;
|
||||||
|
server-urls = cfg.ldap-server-urls;
|
||||||
|
};
|
||||||
|
|
||||||
|
clamav.enable = true;
|
||||||
|
dkim.signing = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
in {
|
||||||
|
config.fudo.prometheus = {
|
||||||
|
enable = true;
|
||||||
|
hostname = "metrics.${domain-name}";
|
||||||
|
service-discovery-dns = let
|
||||||
|
srv-dns = "_metrics._tcp.${domain-name}";
|
||||||
|
in {
|
||||||
|
node = [ "node.${srv-dns}" ];
|
||||||
|
postfix = [ "postfix.${srv-dns}" ];
|
||||||
|
dovecot = [ "dovecot.${srv-dns}" ];
|
||||||
|
rspamd = [ "rspamd.${srv-dns}" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
in {
|
||||||
|
config.fudo.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
local-networks = config.instance.local-networks;
|
||||||
|
admin-users = config.instance.admin-users;
|
||||||
|
|
||||||
|
ssl-private-key = secrets.postgres-ssl-key;
|
||||||
|
ssl-certificate = secrets.postgres-ssl-certificate;
|
||||||
|
keytab = secrets.postgres-keytab.target-file;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
site-name = config.instance.local-site;
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
|
static = config.fudo.static;
|
||||||
|
|
||||||
|
mail-hostname = config.france.webmail.mail-server;
|
||||||
|
|
||||||
|
db-host = config.france.webmail.database.hostname;
|
||||||
|
|
||||||
|
db-passwd = pkgs.lib.fudo.passwd.random-passwd-file "webmail" 40;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.france.webmail = with types; {
|
||||||
|
mail-server = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Mail server to use for webmail.";
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
hostname = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "PostgreSQL server.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config.fudo = {
|
||||||
|
webmail = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
sites = {
|
||||||
|
"webmail.fudo.link" = {
|
||||||
|
title = "Fudo Link Webmail";
|
||||||
|
favicon = "${static}/fudo.link/favicon.ico";
|
||||||
|
mail-server = mail-hostname;
|
||||||
|
domain = "fudo.link";
|
||||||
|
edit-mode = "Plain";
|
||||||
|
layout-mode = "bottom";
|
||||||
|
database = {
|
||||||
|
hostname = db-host;
|
||||||
|
password-file = db-passwd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"webmail.test.fudo.org" = {
|
||||||
|
title = "Fudo Webmail";
|
||||||
|
favicon = "${static}/fudo.org/favicon.ico";
|
||||||
|
mail-server = mail-hostname;
|
||||||
|
domain = "fudo.org";
|
||||||
|
edit-mode = "Plain";
|
||||||
|
database = {
|
||||||
|
hostname = db-host;
|
||||||
|
password-file = db-passwd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"webmail.fudo.org" = {
|
||||||
|
title = "Fudo Webmail";
|
||||||
|
favicon = "${static}/fudo.org/favicon.ico";
|
||||||
|
mail-server = mail-hostname;
|
||||||
|
domain = "fudo.org";
|
||||||
|
edit-mode = "Plain";
|
||||||
|
database = {
|
||||||
|
hostname = db-host;
|
||||||
|
password-file = db-passwd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"webmail.test.selby.ca" = {
|
||||||
|
title = "Selby Webmail";
|
||||||
|
favicon = "${static}/selby.ca/favicon.ico";
|
||||||
|
mail-server = mail-hostname;
|
||||||
|
domain = "selby.ca";
|
||||||
|
database = {
|
||||||
|
hostname = db-host;
|
||||||
|
password-file = db-passwd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"webmail.selby.ca" = {
|
||||||
|
title = "Selby Webmail";
|
||||||
|
favicon = "${static}/selby.ca/favicon.ico";
|
||||||
|
mail-server = mail-hostname;
|
||||||
|
domain = "selby.ca";
|
||||||
|
database = {
|
||||||
|
hostname = db-host;
|
||||||
|
password-file = db-passwd;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ in {
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 22;
|
prefixLength = 16;
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
intif1 = { useDHCP = false; };
|
intif1 = { useDHCP = false; };
|
||||||
|
|
|
@ -22,25 +22,6 @@ in {
|
||||||
# Hopefully this'll help with NFS...
|
# Hopefully this'll help with NFS...
|
||||||
boot.kernelModules = [ "rpcsec_gss_krb5" ];
|
boot.kernelModules = [ "rpcsec_gss_krb5" ];
|
||||||
|
|
||||||
fudo.hosts.nostromo.encrypted-filesystems.sea-store = {
|
|
||||||
encrypted-device = "/dev/nostromo-store/locked";
|
|
||||||
key-path = "/run/keys/sea-store";
|
|
||||||
filesystem-type = "btrfs";
|
|
||||||
options = [ "noatime" "nodiratime" "compress=zstd" "noexec" ];
|
|
||||||
mountpoints = {
|
|
||||||
"/export/documents" = {
|
|
||||||
options = [ "subvol=@documents" ];
|
|
||||||
group = "sea-documents";
|
|
||||||
users = [ "niten" ];
|
|
||||||
};
|
|
||||||
"/export/downloads" = {
|
|
||||||
options = [ "subvol=@downloads" ];
|
|
||||||
group = "sea-downloads";
|
|
||||||
users = [ "niten" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.nfs = {
|
services.nfs = {
|
||||||
# See lib/fudo/users.nix for the user@REALM -> user mapping
|
# See lib/fudo/users.nix for the user@REALM -> user mapping
|
||||||
server = {
|
server = {
|
||||||
|
@ -50,6 +31,7 @@ in {
|
||||||
exportList = [
|
exportList = [
|
||||||
"/export/documents 10.0.0.0/24(rw,sync,no_root_squash,no_subtree_check,fsid=10,sec=krb5p)"
|
"/export/documents 10.0.0.0/24(rw,sync,no_root_squash,no_subtree_check,fsid=10,sec=krb5p)"
|
||||||
"/export/downloads 10.0.0.0/24(rw,sync,no_root_squash,no_subtree_check,fsid=11,sec=krb5i)"
|
"/export/downloads 10.0.0.0/24(rw,sync,no_root_squash,no_subtree_check,fsid=11,sec=krb5i)"
|
||||||
|
"/export/projects 10.0.0.0/24(rw,sync,no_root_squash,no_subtree_check,fsid=11,sec=krb5p)"
|
||||||
];
|
];
|
||||||
in ''
|
in ''
|
||||||
${concatStringsSep "\n" exportList}
|
${concatStringsSep "\n" exportList}
|
||||||
|
@ -61,7 +43,11 @@ in {
|
||||||
# Don't start on boot
|
# Don't start on boot
|
||||||
wantedBy = mkForce [ "sea-store.target" ];
|
wantedBy = mkForce [ "sea-store.target" ];
|
||||||
# Only start after filesystem mounts are available
|
# Only start after filesystem mounts are available
|
||||||
after = [ "export-documents.mount" "export-downloads.mount" ];
|
after = [
|
||||||
|
"export-documents.mount"
|
||||||
|
"export-downloads.mount"
|
||||||
|
"export-projects.mount"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo.ipfs = {
|
fudo.ipfs = {
|
||||||
|
|
|
@ -16,7 +16,7 @@ in {
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 22;
|
prefixLength = 16;
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,12 +5,14 @@ let
|
||||||
hostname = "procul";
|
hostname = "procul";
|
||||||
host-ipv4 = "172.86.179.18";
|
host-ipv4 = "172.86.179.18";
|
||||||
git-ipv4 = "172.86.179.19";
|
git-ipv4 = "172.86.179.19";
|
||||||
domain = config.fudo.hosts.${hostname}.domain;
|
domain-name = config.fudo.hosts.${hostname}.domain;
|
||||||
site = config.fudo.hosts.${hostname}.site;
|
domain = config.fudo.domains.${domain-name};
|
||||||
host-fqdn = "${hostname}.${domain}";
|
site-name = config.fudo.hosts.${hostname}.site;
|
||||||
|
site = config.fudo.sites.${site-name};
|
||||||
|
host-fqdn = "${hostname}.${domain-name}";
|
||||||
|
|
||||||
local-networks = config.fudo.domains.${domain}.local-networks
|
local-networks =
|
||||||
++ config.fudo.sites.${site}.local-networks;
|
domain.local-networks ++ site.local-networks;
|
||||||
|
|
||||||
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
|
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
|
||||||
acme-certificate = hostname: "/var/lib/acme/${hostname}/fullchain.pem";
|
acme-certificate = hostname: "/var/lib/acme/${hostname}/fullchain.pem";
|
||||||
|
@ -18,6 +20,8 @@ let
|
||||||
|
|
||||||
local-packages = with pkgs; [ ldns.examples ];
|
local-packages = with pkgs; [ ldns.examples ];
|
||||||
|
|
||||||
|
secrets = config.fudo.secrets.host-secrets.procul;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
networking = {
|
networking = {
|
||||||
dhcpcd.enable = false;
|
dhcpcd.enable = false;
|
||||||
|
@ -26,9 +30,9 @@ in {
|
||||||
enableIPv6 = true;
|
enableIPv6 = true;
|
||||||
|
|
||||||
# FIXME: this isn't the right place
|
# FIXME: this isn't the right place
|
||||||
search = [ domain ];
|
search = [ domain-name ];
|
||||||
nameservers = [ "127.0.0.1" ];
|
nameservers = [ "127.0.0.1" ];
|
||||||
defaultGateway = "172.86.179.17";
|
defaultGateway = site.gateway-v4;
|
||||||
|
|
||||||
interfaces = {
|
interfaces = {
|
||||||
extif0 = {
|
extif0 = {
|
||||||
|
@ -81,6 +85,64 @@ in {
|
||||||
fudo = {
|
fudo = {
|
||||||
hosts.procul.external-interfaces = [ "extif0" ];
|
hosts.procul.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
|
jabber = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
secret-files = {
|
||||||
|
SECRET = secrets.jabber-ldap-password.traget-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
sites."informis.land" = {
|
||||||
|
site-config = {
|
||||||
|
auth_method = "ldap";
|
||||||
|
ldap_servers = [ "auth.fudo.org" ];
|
||||||
|
ldap_port = 636;
|
||||||
|
ldap_rootdn = "cn=jabber,dc=fudo,dc=org";
|
||||||
|
ldap_password = ''"LDAP_PASSWD"'';
|
||||||
|
ldap_base = "ou=members,dc=fudo,dc=org";
|
||||||
|
ldap_filter = "(objectClass=posixAccount)";
|
||||||
|
ldap_uids = { uid = "%u"; };
|
||||||
|
|
||||||
|
modules = {
|
||||||
|
mod_adhoc = {};
|
||||||
|
mod_announce = {};
|
||||||
|
mod_avatar = {};
|
||||||
|
mod_blocking = {};
|
||||||
|
mod_caps = {};
|
||||||
|
mod_carboncopy = {};
|
||||||
|
mod_client_state = {};
|
||||||
|
mod_configure = {};
|
||||||
|
mod_disco = {};
|
||||||
|
mod_fail2ban = {};
|
||||||
|
mod_last = {};
|
||||||
|
mod_offline = {
|
||||||
|
access_max_user_messages = 5000;
|
||||||
|
};
|
||||||
|
mod_ping = {};
|
||||||
|
mod_privacy = {};
|
||||||
|
mod_private = {};
|
||||||
|
mod_pubsub = {
|
||||||
|
access_createnode = "pubsub_createnode";
|
||||||
|
ignore_pep_from_offline = true;
|
||||||
|
last_item_cache = false;
|
||||||
|
plugins = [
|
||||||
|
"flat"
|
||||||
|
"pep"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
mod_roster = {};
|
||||||
|
mod_stream_mgmt = {};
|
||||||
|
mod_time = {};
|
||||||
|
mod_vcard = {
|
||||||
|
search = false;
|
||||||
|
};
|
||||||
|
mod_vcard_xupdate = {};
|
||||||
|
mod_version = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
secrets.host-secrets.procul = let
|
secrets.host-secrets.procul = let
|
||||||
secrets = config.fudo.secrets.files;
|
secrets = config.fudo.secrets.files;
|
||||||
in {
|
in {
|
||||||
|
@ -157,7 +219,7 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
debug = true;
|
debug = true;
|
||||||
|
|
||||||
domain = domain;
|
domain = domain-name;
|
||||||
hostname = "${host-fqdn}";
|
hostname = "${host-fqdn}";
|
||||||
monitoring = false;
|
monitoring = false;
|
||||||
mail-user = "mailuser";
|
mail-user = "mailuser";
|
||||||
|
@ -167,17 +229,17 @@ in {
|
||||||
dkim.signing = true;
|
dkim.signing = true;
|
||||||
|
|
||||||
dovecot = {
|
dovecot = {
|
||||||
ssl-certificate = acme-certificate "imap.${domain}";
|
ssl-certificate = acme-certificate "imap.${domain-name}";
|
||||||
ssl-private-key = acme-private-key "imap.${domain}";
|
ssl-private-key = acme-private-key "imap.${domain-name}";
|
||||||
};
|
};
|
||||||
|
|
||||||
postfix = {
|
postfix = {
|
||||||
ssl-certificate = acme-certificate "smtp.${domain}";
|
ssl-certificate = acme-certificate "smtp.${domain-name}";
|
||||||
ssl-private-key = acme-private-key "smtp.${domain}";
|
ssl-private-key = acme-private-key "smtp.${domain-name}";
|
||||||
};
|
};
|
||||||
|
|
||||||
# This should NOT include the primary domain
|
# This should NOT include the primary domain
|
||||||
local-domains = [ host-fqdn "smtp.${domain}" ];
|
local-domains = [ host-fqdn "smtp.${domain-name}" ];
|
||||||
|
|
||||||
mail-directory = "/srv/mailserver/mail";
|
mail-directory = "/srv/mailserver/mail";
|
||||||
state-directory = "/srv/mailserver/state";
|
state-directory = "/srv/mailserver/state";
|
||||||
|
@ -199,14 +261,13 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
ssl-certificate = (acme-certificate host-fqdn);
|
ssl-certificate = (acme-certificate host-fqdn);
|
||||||
ssl-private-key = (acme-private-key host-fqdn);
|
ssl-private-key = (acme-private-key host-fqdn);
|
||||||
keytab =
|
keytab = secrets.postgres-keytab.target-file;
|
||||||
config.fudo.secrets.host-secrets.procul.postgres-keytab.target-file;
|
|
||||||
local-networks = local-networks;
|
local-networks = local-networks;
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
gituser = {
|
gituser = {
|
||||||
password-file =
|
password-file =
|
||||||
config.fudo.secrets.host-secrets.procul.gitea-database-password.target-file;
|
secrets.gitea-database-password.target-file;
|
||||||
databases = {
|
databases = {
|
||||||
git = {
|
git = {
|
||||||
access = "CONNECT";
|
access = "CONNECT";
|
||||||
|
@ -232,7 +293,7 @@ in {
|
||||||
database = {
|
database = {
|
||||||
user = "gituser";
|
user = "gituser";
|
||||||
password-file =
|
password-file =
|
||||||
config.fudo.secrets.host-secrets.procul.gitea-database-password.target-file;
|
secrets.gitea-database-password.target-file;
|
||||||
hostname = "127.0.0.1";
|
hostname = "127.0.0.1";
|
||||||
name = "git";
|
name = "git";
|
||||||
};
|
};
|
||||||
|
@ -244,7 +305,7 @@ in {
|
||||||
|
|
||||||
acme = {
|
acme = {
|
||||||
enable = true;
|
enable = true;
|
||||||
admin-address = "admin@${domain}";
|
admin-address = "admin@${domain-name}";
|
||||||
hostnames = [
|
hostnames = [
|
||||||
"informis.land"
|
"informis.land"
|
||||||
"imap.informis.land"
|
"imap.informis.land"
|
||||||
|
|
|
@ -17,7 +17,7 @@ in {
|
||||||
interfaces.intif0 = {
|
interfaces.intif0 = {
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 22;
|
prefixLength = 16;
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
fudo.slynk.enable = true;
|
config = {
|
||||||
|
fudo.slynk.enable = true;
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
extif0 = { useDHCP = true; };
|
extif0 = { useDHCP = true; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
i18n.inputMethod = {
|
||||||
|
enabled = "fcitx5";
|
||||||
|
fcitx5.addons = with pkgs; [
|
||||||
|
fcitx5-chinese-addons
|
||||||
|
fcitx5-rime
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i18n.inputMethod = {
|
|
||||||
enabled = "fcitx5";
|
|
||||||
fcitx5.addons = with pkgs; [
|
|
||||||
fcitx5-chinese-addons
|
|
||||||
fcitx5-rime
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
system.stateVersion = "20.09";
|
config = {
|
||||||
|
fudo.slynk.enable = true;
|
||||||
|
|
||||||
# TODO: remove?
|
environment.systemPackages = with pkgs; [ opencv-java ];
|
||||||
nixpkgs.config.permittedInsecurePackages = [
|
|
||||||
"openssh-with-gssapi-8.4p1" # CVE-2021-28041
|
|
||||||
];
|
|
||||||
|
|
||||||
fudo.slynk.enable = true;
|
networking = {
|
||||||
|
useDHCP = false;
|
||||||
environment.systemPackages = with pkgs; [ opencv-java ];
|
interfaces.intif0.useDHCP = true;
|
||||||
|
};
|
||||||
networking = {
|
|
||||||
useDHCP = false;
|
i18n.inputMethod = {
|
||||||
interfaces = {
|
enabled = "fcitx5";
|
||||||
eno1.useDHCP = false;
|
fcitx5.addons = with pkgs; [
|
||||||
intif0 = { useDHCP = true; };
|
fcitx5-chinese-addons
|
||||||
|
fcitx5-rime
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
{
|
{
|
||||||
description = "Primary fudo.org server.";
|
description = "Primary fudo.org server.";
|
||||||
docker-server = true;
|
docker-server = true;
|
||||||
# ssh-fingerprints = [
|
|
||||||
# "1 1 1b6d62dafae9ebc59169dfb4ef828582a5450d94"
|
|
||||||
# "1 2 079e7a57873542541095bf3d2f97b7350bb457d027b423a6fb56f7f6aa84ac80"
|
|
||||||
# "4 1 c95a198f504a589fc62893a95424b12f0b24732d"
|
|
||||||
# "4 2 3e7dad879d6cab7f7fb6769e156d7988d0c01281618d03b793834eea2f09bc96"
|
|
||||||
# ];
|
|
||||||
rp = "admin";
|
rp = "admin";
|
||||||
admin-email = "admin@fudo.org";
|
admin-email = "admin@fudo.org";
|
||||||
domain = "fudo.org";
|
domain = "fudo.org";
|
||||||
site = "portage";
|
site = "portage";
|
||||||
profile = "server";
|
profile = "server";
|
||||||
# ssh-pubkey =
|
|
||||||
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1COad5NSK3mi66WK5uWf79NLMf5rk350kvJGsEdDmn";
|
|
||||||
arch = "x86_64-linux";
|
arch = "x86_64-linux";
|
||||||
# Just to stop this evaluating for now
|
machine-id = "d33245603a854e48ba90002639e063f8";
|
||||||
nixos-system = false;
|
nixos-system = true;
|
||||||
|
master-key = {
|
||||||
|
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMQyRAJQpFaBanQKdu3SWCu0mjqSdF7WC1WNdKdQ1edQ";
|
||||||
|
key-path = "/state/master-key/ed25519-key";
|
||||||
|
};
|
||||||
|
initrd-network = {
|
||||||
|
ip = "208.81.3.117";
|
||||||
|
interface = "enp4s0f0";
|
||||||
|
keypair = {
|
||||||
|
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOAooY0j3xhs3PS5vFDXya1ljjo7fFXT98HDICVa3yBl";
|
||||||
|
private-key-file = "/state/ssh/initrd/ssh_ed25519_key";
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,27 @@
|
||||||
key-path = "/state/master-key/key";
|
key-path = "/state/master-key/key";
|
||||||
};
|
};
|
||||||
# initrd-ip = "10.0.5.10";
|
# initrd-ip = "10.0.5.10";
|
||||||
|
encrypted-filesystems.sea-store = {
|
||||||
|
encrypted-device = "/dev/nostromo-store/locked";
|
||||||
|
key-path = "/run/keys/sea-store";
|
||||||
|
filesystem-type = "btrfs";
|
||||||
|
options = [ "noatime" "nodiratime" "compress=zstd" "noexec" ];
|
||||||
|
mountpoints = {
|
||||||
|
"/export/documents" = {
|
||||||
|
options = [ "subvol=@documents" ];
|
||||||
|
group = "sea-documents";
|
||||||
|
users = [ "niten" ];
|
||||||
|
};
|
||||||
|
"/export/downloads" = {
|
||||||
|
options = [ "subvol=@downloads" ];
|
||||||
|
group = "sea-downloads";
|
||||||
|
users = [ "niten" ];
|
||||||
|
};
|
||||||
|
"/export/projects" = {
|
||||||
|
options = [ "subvol=@projects" ];
|
||||||
|
group = "sea-projects";
|
||||||
|
users = [ "niten" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
mx = [ "mail.fudo.org" ];
|
mx = [ "mail.fudo.org" ];
|
||||||
|
|
||||||
|
|
|
@ -37,44 +37,55 @@ in {
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [ "comment=systemd.automount" ];
|
options = [ "comment=systemd.automount" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
"/net/documents" = {
|
"/net/documents" = {
|
||||||
device = "sea-store.${local-domain}:/export/documents";
|
device = "sea-store.sea.fudo.org:/export/documents";
|
||||||
fsType = "nfs";
|
fsType = "nfs4";
|
||||||
options = [
|
options = [ "comment=systemd.automount" "sec=krb5p" ];
|
||||||
"nfsvers=4.2"
|
|
||||||
"comment=systemd.automount"
|
|
||||||
"sec=krb5p"
|
|
||||||
# "noauto" ?
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
"/net/downloads" = {
|
"/net/downloads" = {
|
||||||
device = "sea-store.${local-domain}:/export/downloads";
|
device = "sea-store.sea.fudo.org:/export/downloads";
|
||||||
fsType = "nfs";
|
fsType = "nfs4";
|
||||||
options = [
|
options = [ "comment=systemd.automount" "sec=krb5i" ];
|
||||||
"nfsvers=4.2"
|
};
|
||||||
"comment=systemd.automount"
|
"/net/projects" = {
|
||||||
"sec=krb5i"
|
device = "sea-store.sea.fudo.org:/export/projects";
|
||||||
# "noauto" ?
|
fsType = "nfs4";
|
||||||
];
|
options = [ "comment=systemd.automount" "sec=krb5p" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# systemd.mounts = [
|
systemd = {
|
||||||
# {
|
tmpfiles.rules = [
|
||||||
# what = "sea-store.sea.fudo.org:/export/documents";
|
"d /net/documents - root sea-documents - -"
|
||||||
# where = "/net/documents";
|
"d /net/downloads - root sea-downloads - -"
|
||||||
# type = "nfs4";
|
"d /net/projects - root sea-projects - -"
|
||||||
# options = "sec=krb5p";
|
];
|
||||||
# description = "sea-store documents on encrypted filesysem.";
|
|
||||||
# }
|
# mounts = [
|
||||||
# {
|
# {
|
||||||
# what = "sea-store.sea.fudo.org:/export/downloads";
|
# what = "sea-store.sea.fudo.org:/export/documents";
|
||||||
# where = "/net/downloads";
|
# where = "/net/documents";
|
||||||
# type = "nfs4";
|
# type = "nfs4";
|
||||||
# options = "sec=krb5i";
|
# options = "sec=krb5p";
|
||||||
# description = "sea-store downloads on encrypted filesysem.";
|
# description = "sea-store documents on encrypted filesysem.";
|
||||||
# }
|
# }
|
||||||
# ];
|
# {
|
||||||
|
# what = "sea-store.sea.fudo.org:/export/downloads";
|
||||||
|
# where = "/net/downloads";
|
||||||
|
# type = "nfs4";
|
||||||
|
# options = "sec=krb5i";
|
||||||
|
# description = "sea-store downloads on encrypted filesysem.";
|
||||||
|
# }
|
||||||
|
# {
|
||||||
|
# what = "sea-store.sea.fudo.org:/export/projects";
|
||||||
|
# where = "/net/projects";
|
||||||
|
# type = "nfs4";
|
||||||
|
# options = "sec=krb5p";
|
||||||
|
# description = "sea-store projects on encrypted filesysem.";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
|
||||||
services.printing = {
|
services.printing = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -8,58 +8,34 @@
|
||||||
network = "10.0.0.0/16";
|
network = "10.0.0.0/16";
|
||||||
dynamic-network = "10.0.100.0/24";
|
dynamic-network = "10.0.100.0/24";
|
||||||
timezone = "America/Los_Angeles";
|
timezone = "America/Los_Angeles";
|
||||||
gateway-host = "nostromo";
|
|
||||||
deploy-pubkeys = [
|
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 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="
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGVez4of30f+j0cWKj5kYCKeFjyNsYvG9UbOMxF5hImD2lP5MSbFBv31gFgHjx3yCG4zQRZlpuyU5uWo0qIwe9N84/LcZcB9WrWKZXDmuof7zPFy0J+Hj+LVLDQI/mVXHNwkMhBMHpPrdwA05EYDAYCYklWT4cSByu10pHtST+olF8i+A+UQgUzgNZzdJVeiYZv6MBDTYsJWptGeDUkl2B0Es3gtbGYcCCfnyS3RC7DIXlDo3NBbAr7WaHY2MBbT+R/+jicn9E3IY3NCM5jENxqmvHy9MDsxEEYgFNm7IDwq4V1VRUWy277YsvRbmEaHb+osOA5u1VNN4z3UftOZcSZgR5C/vR71cENXoPt1YQpCzu7i38ojtvL+tDVEKT7sIovrQw8q1sszNlW2nXh8RSPiIq5TMnrV73MP0egKcr9n3tfxwi1BIkLjvfom/02BkTK9R9v+VMNhYU1YwROhORCiMIgoxUGiUvtH8u38JGr7E0hhMoAjCE5k80WPUivl0="
|
||||||
];
|
];
|
||||||
build-servers = {
|
# build-servers = {
|
||||||
nostromo = {
|
# nostromo = {
|
||||||
max-jobs = 4;
|
# max-jobs = 4;
|
||||||
speed-factor = 2;
|
# speed-factor = 2;
|
||||||
};
|
|
||||||
lambda = {
|
|
||||||
max-jobs = 4;
|
|
||||||
speed-factor = 2;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
enable-distributed-builds = false;
|
|
||||||
keytab-path = "/state/secrets/kerberos";
|
|
||||||
build-key-path = "/state/secrets/build-keys";
|
|
||||||
# FIXME: good idea?
|
|
||||||
# network-mounts = {
|
|
||||||
# "/mnt/documents" = {
|
|
||||||
# device = "whitedwarf:/volume1/Documents";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# };
|
# };
|
||||||
# "/mnt/downloads" = {
|
# lambda = {
|
||||||
# device = "whitedwarf:/volume1/Downloads";
|
# max-jobs = 4;
|
||||||
# fsType = "nfs4";
|
# speed-factor = 2;
|
||||||
# };
|
|
||||||
# "/mnt/music" = {
|
|
||||||
# device = "doraemon:/volume1/Music";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# };
|
|
||||||
# "/mnt/video" = {
|
|
||||||
# device = "doraemon:/volume1/Video";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# };
|
|
||||||
# "/mnt/cargo_video" = {
|
|
||||||
# device = "cargo:/volume1/video";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# };
|
|
||||||
# "/mnt/photo" = {
|
|
||||||
# device = "cargo:/volume1/pictures";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# };
|
# };
|
||||||
# };
|
# };
|
||||||
|
enable-distributed-builds = false;
|
||||||
|
mail-server = "mail.fudo.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
portage = {
|
portage = {
|
||||||
gateway-v4 = "208.81.3.113";
|
gateway-v4 = "208.81.3.113";
|
||||||
network = "208.81.3.112/28";
|
network = "208.81.3.112/28";
|
||||||
nameservers = [ "1.1.1.1" "208.81.7.14" "2606:4700:4700::1111" ];
|
nameservers = [ "208.81.7.14" "1.1.1.1" ];
|
||||||
timezone = "America/Winnipeg";
|
timezone = "America/Winnipeg";
|
||||||
|
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";
|
||||||
};
|
};
|
||||||
|
|
||||||
russell = {
|
russell = {
|
||||||
|
@ -69,18 +45,19 @@
|
||||||
dynamic-network = "10.0.1.0/24";
|
dynamic-network = "10.0.1.0/24";
|
||||||
timezone = "America/Winnipeg";
|
timezone = "America/Winnipeg";
|
||||||
gateway-host = "clunk";
|
gateway-host = "clunk";
|
||||||
|
mail-server = "mail.fudo.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
joes-datacenter-0 = {
|
joes-datacenter-0 = {
|
||||||
gateway-v4 = "172.86.179.17";
|
gateway-v4 = "172.86.179.17";
|
||||||
|
network = "172.86.179.17/29";
|
||||||
nameservers = [ "1.1.1.1" "2606:4700:4700::1111" ];
|
nameservers = [ "1.1.1.1" "2606:4700:4700::1111" ];
|
||||||
timezone = "America/Winnipeg";
|
timezone = "America/Winnipeg";
|
||||||
deploy-pubkeys = [
|
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 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="
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGVez4of30f+j0cWKj5kYCKeFjyNsYvG9UbOMxF5hImD2lP5MSbFBv31gFgHjx3yCG4zQRZlpuyU5uWo0qIwe9N84/LcZcB9WrWKZXDmuof7zPFy0J+Hj+LVLDQI/mVXHNwkMhBMHpPrdwA05EYDAYCYklWT4cSByu10pHtST+olF8i+A+UQgUzgNZzdJVeiYZv6MBDTYsJWptGeDUkl2B0Es3gtbGYcCCfnyS3RC7DIXlDo3NBbAr7WaHY2MBbT+R/+jicn9E3IY3NCM5jENxqmvHy9MDsxEEYgFNm7IDwq4V1VRUWy277YsvRbmEaHb+osOA5u1VNN4z3UftOZcSZgR5C/vR71cENXoPt1YQpCzu7i38ojtvL+tDVEKT7sIovrQw8q1sszNlW2nXh8RSPiIq5TMnrV73MP0egKcr9n3tfxwi1BIkLjvfom/02BkTK9R9v+VMNhYU1YwROhORCiMIgoxUGiUvtH8u38JGr7E0hhMoAjCE5k80WPUivl0="
|
||||||
];
|
];
|
||||||
keytab-path = "/state/secrets/kerberos";
|
mail-server = "mail.informis.land";
|
||||||
build-key-path = "/state/secrets/build-keys";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ with lib; {
|
||||||
|
|
||||||
./instance.nix
|
./instance.nix
|
||||||
|
|
||||||
|
./fudo/acme-certs.nix
|
||||||
./fudo/acme-for-hostname.nix
|
./fudo/acme-for-hostname.nix
|
||||||
./fudo/authentication.nix
|
./fudo/authentication.nix
|
||||||
./fudo/backplane
|
./fudo/backplane
|
||||||
|
@ -23,6 +24,7 @@ with lib; {
|
||||||
./fudo/host-filesystems.nix
|
./fudo/host-filesystems.nix
|
||||||
./fudo/initrd-network.nix
|
./fudo/initrd-network.nix
|
||||||
./fudo/ipfs.nix
|
./fudo/ipfs.nix
|
||||||
|
./fudo/jabber.nix
|
||||||
./fudo/kdc.nix
|
./fudo/kdc.nix
|
||||||
./fudo/ldap.nix
|
./fudo/ldap.nix
|
||||||
./fudo/local-network.nix
|
./fudo/local-network.nix
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
let
|
let
|
||||||
ip = import ./ip.nix { inherit lib; };
|
ip = import ./ip.nix { inherit lib; };
|
||||||
dns = import ./dns.nix { inherit lib; };
|
dns = import ./dns.nix { inherit lib; };
|
||||||
|
passwd = import ./passwd.nix { inherit lib; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
lib.overlays = [
|
lib.overlays = [
|
||||||
(final: prev:
|
(final: prev:
|
||||||
prev.lib // {
|
prev.lib // {
|
||||||
fudo = {
|
fudo = {
|
||||||
inherit ip dns;
|
inherit ip dns passwd;
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
localCopyOpts = { copy, ... }: let
|
||||||
|
in {
|
||||||
|
options = with types; {
|
||||||
|
inherit domain;
|
||||||
|
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 = { domain, ... }: {
|
||||||
|
options = with types; {
|
||||||
|
email = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Domain administrator email.";
|
||||||
|
default = "admin@${domain}";
|
||||||
|
};
|
||||||
|
|
||||||
|
extra-domains = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of domains to add to this certificate.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
head-or-null = lst: if (lst == []) then null else head lst;
|
||||||
|
rm-service-ext = filename:
|
||||||
|
head-or-null (builtins.match "^(.+)\.service$" filename);
|
||||||
|
|
||||||
|
concatMapAttrs = f: attrs:
|
||||||
|
foldr (a: b: a // b) {} (mapAttrsToList f attrs);
|
||||||
|
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
cfg = config.fudo.acme;
|
||||||
|
localDomains = if (hasAttr hostname cfg.host-domains) then
|
||||||
|
cfg.host-domains.${hostname} else {};
|
||||||
|
|
||||||
|
optionalStringOr = str: default:
|
||||||
|
if cond then str else default;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.acme = with types; {
|
||||||
|
host-domains = mkOption {
|
||||||
|
type = attrsOf (attrsOf (submodule domainOpts));
|
||||||
|
description = "Map of host to domains to domain options.";
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
security.acme.certs = mapAttrs (domain: domainOpts: {
|
||||||
|
email = domainOpts.email;
|
||||||
|
extraDomainNames = domainOpts.extra-domains;
|
||||||
|
}) localDomains;
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
tmpfiles.rules = let
|
||||||
|
copies = concatMapAttrs (domain: domainOpts:
|
||||||
|
domainOpts.local-copies) localDomains;
|
||||||
|
copy-paths = mapAttrsToList (copy: copyOpts:
|
||||||
|
"D '${path}' 0550 ${copyOpts.user} ${optionalStringOr copyOpts.group "-"} - -")
|
||||||
|
copies;
|
||||||
|
in copy-paths;
|
||||||
|
|
||||||
|
# TODO: Make this a Fudo service?
|
||||||
|
services = concatMapAttrs (domain: domainOpts:
|
||||||
|
mapAttrs' (copy: copyOpts: let
|
||||||
|
source = config.security.acme.certs.${domain}.directory;
|
||||||
|
target = copyOpts.path;
|
||||||
|
install-certs = pkgs.writeShellScript "fudo-install-${domain}-${site}-certs.sh" ''
|
||||||
|
for cert in cert chain fullchain full key; do
|
||||||
|
cp ${source}/$cert.pem ${target}/$cert.pem
|
||||||
|
chmod 0440 ${source}/$cert.pem
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
remove-certs = pkgs.writeShellScript "fudo-remove-${domain}-${site}-certs.sh" ''
|
||||||
|
for cert in cert chain fullchain full key; do
|
||||||
|
rm -rf ${target}/$cert.pem
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
in nameValuePair
|
||||||
|
(rm-service-ext copyOpts.service) {
|
||||||
|
description = "Copy ${domain} ACME certs for ${copy}.";
|
||||||
|
after = [ "acme-${domain}.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = install-certs;
|
||||||
|
ExecStop = remove-certs;
|
||||||
|
RemainAfterExit = true;
|
||||||
|
StandardOutput = "journal";
|
||||||
|
};
|
||||||
|
}) domainOpts.local-copies) localDomains;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ with lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
host-filesystems = config.fudo.hosts.${hostname}.encrypted-filesystems;
|
host-filesystems = config.fudo.hosts.${hostname}.encrypted-filesystems;
|
||||||
|
|
||||||
optionalOrDefault = str: default: if (str != null) then str else default;
|
optionalOrDefault = str: default: if (str != null) then str else default;
|
||||||
|
|
||||||
filesystemsToMountpointLists = mapAttrsToList
|
filesystemsToMountpointLists = mapAttrsToList
|
||||||
|
@ -12,21 +12,24 @@ let
|
||||||
|
|
||||||
concatMapAttrs = f: as: concatMap (i: i) (mapAttrsToList f as);
|
concatMapAttrs = f: as: concatMap (i: i) (mapAttrsToList f as);
|
||||||
|
|
||||||
|
concatMapAttrsToList = f: attrs:
|
||||||
|
concatMap (i: i) (mapAttrsToList f attrs);
|
||||||
|
|
||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
users.groups = let
|
users.groups = let
|
||||||
mountpointToGroups = mp: mpOpts:
|
site-name = config.instance.local-site;
|
||||||
optional (mpOpts.group != null)
|
site-hosts = filterAttrs
|
||||||
(nameValuePair mpOpts.group {
|
(hostname: hostOpts: hostOpts.site == site-name)
|
||||||
members = mpOpts.users;
|
config.fudo.hosts;
|
||||||
});
|
site-mountpoints = concatMapAttrsToList
|
||||||
mountpointListToGroups =
|
(host: hostOpts: concatMapAttrsToList
|
||||||
concatMapAttrs mountpointToGroups;
|
(fs: fsOpts: attrValues fsOpts.mountpoints)
|
||||||
mountpointListsToGroups =
|
hostOpts.encrypted-filesystems)
|
||||||
concatMap mountpointListToGroups;
|
site-hosts;
|
||||||
in listToAttrs
|
in listToAttrs
|
||||||
(mountpointListsToGroups
|
(map (mp: nameValuePair mp.group { members = mp.users; })
|
||||||
(filesystemsToMountpointLists host-filesystems));
|
site-mountpoints);
|
||||||
|
|
||||||
systemd = {
|
systemd = {
|
||||||
# Ensure the mountpoints exist
|
# Ensure the mountpoints exist
|
||||||
|
|
|
@ -42,36 +42,41 @@ in {
|
||||||
(substring 0 8 host-cfg.machine-id);
|
(substring 0 8 host-cfg.machine-id);
|
||||||
};
|
};
|
||||||
|
|
||||||
# NixOS generates a stupid hosts file, just force it
|
environment = {
|
||||||
environment.etc = {
|
etc = {
|
||||||
hosts = let
|
# NixOS generates a stupid hosts file, just force it
|
||||||
host-entries = mapAttrsToList
|
hosts = let
|
||||||
(ip: hostnames: "${ip} ${concatStringsSep " " hostnames}")
|
host-entries = mapAttrsToList
|
||||||
config.fudo.system.hostfile-entries;
|
(ip: hostnames: "${ip} ${concatStringsSep " " hostnames}")
|
||||||
in mkForce {
|
config.fudo.system.hostfile-entries;
|
||||||
text = ''
|
in mkForce {
|
||||||
|
text = ''
|
||||||
127.0.0.1 ${hostname}.${domain-name} ${hostname} localhost
|
127.0.0.1 ${hostname}.${domain-name} ${hostname} localhost
|
||||||
127.0.0.2 ${hostname} localhost
|
127.0.0.2 ${hostname} localhost
|
||||||
::1 ${hostname}.${domain-name} ${hostname} localhost
|
::1 ${hostname}.${domain-name} ${hostname} localhost
|
||||||
${concatStringsSep "\n" host-entries}
|
${concatStringsSep "\n" host-entries}
|
||||||
'';
|
'';
|
||||||
user = "root";
|
user = "root";
|
||||||
group = "root";
|
group = "root";
|
||||||
mode = "0444";
|
mode = "0444";
|
||||||
};
|
};
|
||||||
|
|
||||||
machine-id = mkIf (host-cfg.machine-id != null) {
|
machine-id = mkIf (host-cfg.machine-id != null) {
|
||||||
text = host-cfg.machine-id;
|
text = host-cfg.machine-id;
|
||||||
user = "root";
|
user = "root";
|
||||||
group = "root";
|
group = "root";
|
||||||
mode = "0444";
|
mode = "0444";
|
||||||
};
|
};
|
||||||
|
|
||||||
current-system-packages.text = with builtins; let
|
current-system-packages.text = with builtins; let
|
||||||
packages = map (p: "${p.name}")
|
packages = map (p: "${p.name}")
|
||||||
config.environment.systemPackages;
|
config.environment.systemPackages;
|
||||||
sorted-unique = sort lessThan (unique packages);
|
sorted-unique = sort lessThan (unique packages);
|
||||||
in concatStringsSep "\n" sorted-unique;
|
in concatStringsSep "\n" sorted-unique;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemPackages = with pkgs;
|
||||||
|
mkIf (host-cfg.docker-server) [ docker nix-prefetch-docker ];
|
||||||
};
|
};
|
||||||
|
|
||||||
time.timeZone = site.timezone;
|
time.timeZone = site.timezone;
|
||||||
|
@ -80,9 +85,6 @@ in {
|
||||||
|
|
||||||
services.cron.mailto = domain.admin-email;
|
services.cron.mailto = domain.admin-email;
|
||||||
|
|
||||||
environment.systemPackages = with pkgs;
|
|
||||||
mkIf (host-cfg.docker-server) [ docker nix-prefetch-docker ];
|
|
||||||
|
|
||||||
virtualisation.docker = mkIf (host-cfg.docker-server) {
|
virtualisation.docker = mkIf (host-cfg.docker-server) {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableOnBoot = true;
|
enableOnBoot = true;
|
||||||
|
@ -136,5 +138,13 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
lib: site: config: version:
|
lib: site: config: version:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
db-config = if (config.database != null) then
|
db-config = optionalString (config.database != null)
|
||||||
''
|
''
|
||||||
type = "${config.database.type}"
|
type = "${config.database.type}"
|
||||||
pdo_dsn = "${config.database.type}:host=${config.database.hostname};port=${toString config.database.port};dbname=${config.database.name}"
|
pdo_dsn = "${config.database.type}:host=${config.database.hostname};port=${toString config.database.port};dbname=${config.database.name}"
|
||||||
pdo_user = "${config.database.user}"
|
pdo_user = "${config.database.user}"
|
||||||
pdo_password = "${fileContents config.database.password-file}"
|
pdo_password = "${fileContents config.database.password-file}"
|
||||||
''
|
'';
|
||||||
else "";
|
|
||||||
in ''
|
in ''
|
||||||
[webmail]
|
[webmail]
|
||||||
title = "${config.title}"
|
title = "${config.title}"
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
|
||||||
|
siteOpts = { ... }: with types; {
|
||||||
|
options = {
|
||||||
|
enableACME = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Use ACME to get SSL certificates for this site.";
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
site-config = mkOption {
|
||||||
|
type = attrs;
|
||||||
|
description = "Site-specific configuration.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
site-copy = site: "ejabberd-${site}";
|
||||||
|
|
||||||
|
concatMapAttrs = f: attrs:
|
||||||
|
foldr (a: b: a // b) {} (mapAttrs f attrs);
|
||||||
|
|
||||||
|
concatMapAttrsToList = f: attr:
|
||||||
|
attrValues (concatMapAttrs f attr);
|
||||||
|
|
||||||
|
host-domains = config.fudo.acme.host-domains.${hostname};
|
||||||
|
|
||||||
|
siteCerts = site: let
|
||||||
|
certPath = config.fudo.acme.local-copies.${site-copy site}.path;
|
||||||
|
in [
|
||||||
|
"${certPath}/fullchain.pem"
|
||||||
|
"${certPath}/privkey.pem"
|
||||||
|
"${certPath}/chain.pem"
|
||||||
|
];
|
||||||
|
|
||||||
|
siteCertService = site:
|
||||||
|
config.fudo.acme.local-copies.${site-copy site}.service;
|
||||||
|
|
||||||
|
config-file-template = let
|
||||||
|
jabber-config = {
|
||||||
|
loglevel = cfg.log-level;
|
||||||
|
|
||||||
|
access_rules = {
|
||||||
|
c2s = { allow = "all"; };
|
||||||
|
announce = { allow = "admin"; };
|
||||||
|
configure = { allow = "admin"; };
|
||||||
|
pubsub_createnode = { allow = "local"; };
|
||||||
|
};
|
||||||
|
|
||||||
|
acl = {
|
||||||
|
admin = {
|
||||||
|
user = concatMap
|
||||||
|
(admin: map (site: "${admin}@${site}")
|
||||||
|
(attrNames cfg.sites))
|
||||||
|
cfg.admins;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
hosts = attrNames cfg.sites;
|
||||||
|
|
||||||
|
listen = [{
|
||||||
|
port = cfg.port;
|
||||||
|
module = "ejabberd_c2s";
|
||||||
|
ip = cfg.listen-ip;
|
||||||
|
starttls = true;
|
||||||
|
starttls_required = true;
|
||||||
|
}];
|
||||||
|
|
||||||
|
certfiles = concatMapAttrsToList
|
||||||
|
(site: siteOpts:
|
||||||
|
if (siteOpts.enableACME) then
|
||||||
|
(siteCerts site)
|
||||||
|
else [])
|
||||||
|
cfg.sites;
|
||||||
|
|
||||||
|
host_config =
|
||||||
|
mapAttrs (site: siteOpts: siteOpts.site-config)
|
||||||
|
cfg.sites;
|
||||||
|
};
|
||||||
|
|
||||||
|
config-file = builtins.toJSON jabber-config;
|
||||||
|
in pkgs.writeText "ejabberd.config.yml.template" config-file;
|
||||||
|
|
||||||
|
enter-secrets = template: secrets: target: let
|
||||||
|
secret-readers = concatStringsSep "\n"
|
||||||
|
(mapAttrsToList
|
||||||
|
(secret: file: "${secret}=$(cat ${file})")
|
||||||
|
secrets);
|
||||||
|
secret-swappers = map
|
||||||
|
(secret: "sed s/${secret}/\$${secret}/g")
|
||||||
|
(attrNames secrets);
|
||||||
|
swapper = concatStringsSep " | " secret-swappers;
|
||||||
|
in pkgs.writeShellScript "ejabberd-generate-config.sh" ''
|
||||||
|
cat ${template} | ${swapper} > ${target}
|
||||||
|
chown ${cfg.user}:${cfg.group} ${target}
|
||||||
|
'';
|
||||||
|
|
||||||
|
cfg = config.fudo.jabber;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.jabber = with types; {
|
||||||
|
enable = mkEnableOption "Enable ejabberd server.";
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Port on which to listen for Jabber connections.";
|
||||||
|
default = 5222;
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "User as which to run the ejabberd server.";
|
||||||
|
default = "ejabberd";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Group as which to run the ejabberd server.";
|
||||||
|
default = "ejabberd";
|
||||||
|
};
|
||||||
|
|
||||||
|
admins = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "List of admin users for the server.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
sites = mkOption {
|
||||||
|
type = attrsOf (submodule siteOpts);
|
||||||
|
description = "List of sites on which to listen for Jabber connections.";
|
||||||
|
};
|
||||||
|
|
||||||
|
secret-files = mkOption {
|
||||||
|
type = attrsOf str;
|
||||||
|
description = "Map of secret-name to file. File contents will be subbed for the name in the config.";
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
config-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Location at which to generate the configuration file.";
|
||||||
|
default = "/var/run/ejabberd/ejabberd.yaml";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
users = {
|
||||||
|
users.${cfg.user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
groups.${cfg.group} = {
|
||||||
|
members = [ cfg.user ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fudo.acme.local-copies = mapAttrs' (site: siteCfg:
|
||||||
|
nameValuePair (site-copy site)
|
||||||
|
mkif siteCfg.enableACME {
|
||||||
|
domain = site;
|
||||||
|
user = cfg.user;
|
||||||
|
group = cfg.group;
|
||||||
|
}) cfg.sites;
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
tmpfiles.rules = [
|
||||||
|
"D '${dirOf cfg.config-file}' 0550 ${cfg.user} ${cfg.group} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.ejabberd = let
|
||||||
|
config-generator = enter-secrets config-file-template cfg.secret-files cfg.config-file;
|
||||||
|
in {
|
||||||
|
wants = map (site: siteCertService site) (attrNames cfg.sites);
|
||||||
|
environment = cfg.secret-files;
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStartPre = mkAfter "${config-generator}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.ejabberd = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
user = cfg.user;
|
||||||
|
group = cfg.group;
|
||||||
|
|
||||||
|
configFile = cfg.config-file;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -63,8 +63,8 @@ let
|
||||||
}
|
}
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
kdc = FILE:/var/kerberos/kerberos.log
|
kdc = FILE:${cfg.state-directory}/kerberos.log
|
||||||
default = FILE:/var/kerberos/kerberos.log
|
default = FILE:${cfg.state-directory}/kerberos.log
|
||||||
'';
|
'';
|
||||||
|
|
||||||
aclEntry = { principal, ... }: {
|
aclEntry = { principal, ... }: {
|
||||||
|
@ -111,7 +111,9 @@ let
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.auth.kdc = with types; {
|
options.fudo.auth.kdc = with types; let
|
||||||
|
default-state-dir = "/var/kerberos";
|
||||||
|
in {
|
||||||
enable = mkEnableOption "Fudo KDC";
|
enable = mkEnableOption "Fudo KDC";
|
||||||
|
|
||||||
realm = mkOption {
|
realm = mkOption {
|
||||||
|
@ -150,31 +152,31 @@ in {
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path at which to store kerberos database.";
|
description = "Path at which to store kerberos database.";
|
||||||
default = "/var/kerberos";
|
default = default-state-dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
master-key-file = mkOption {
|
master-key-file = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "File containing the master key for the realm.";
|
description = "File containing the master key for the realm.";
|
||||||
default = "/var/kerberos/master.key";
|
default = "${default-state-dir}/master.key";
|
||||||
};
|
};
|
||||||
|
|
||||||
primary-keytab = mkOption {
|
primary-keytab = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Location of keytab for kadmind.";
|
description = "Location of keytab for kadmind.";
|
||||||
default = "/var/kerberos/host.keytab";
|
default = "${default-state-dir}/host.keytab";
|
||||||
};
|
};
|
||||||
|
|
||||||
kadmin-keytab = mkOption {
|
kadmin-keytab = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Location of keytab for kadmind.";
|
description = "Location of keytab for kadmind.";
|
||||||
default = "/var/kerberos/kadmind.keytab";
|
default = "${default-state-dir}/kadmind.keytab";
|
||||||
};
|
};
|
||||||
|
|
||||||
kpasswdd-keytab = mkOption {
|
kpasswdd-keytab = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Location of keytab for kpasswdd.";
|
description = "Location of keytab for kpasswdd.";
|
||||||
default = "/var/kerberos/kpasswdd.keytab";
|
default = "${default-state-dir}/kpasswdd.keytab";
|
||||||
};
|
};
|
||||||
|
|
||||||
kdc-internal-port = mkOption {
|
kdc-internal-port = mkOption {
|
||||||
|
@ -184,13 +186,6 @@ in {
|
||||||
default = 4088;
|
default = 4088;
|
||||||
};
|
};
|
||||||
|
|
||||||
# k5login-directory = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description =
|
|
||||||
# "Directory in which k5login files are stored for local users (equivalent to ~/.k5login).";
|
|
||||||
# default = "/var/kerberos/k5login";
|
|
||||||
# };
|
|
||||||
|
|
||||||
max-ticket-lifetime = mkOption {
|
max-ticket-lifetime = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Maximum lifetime of a single ticket in this realm.";
|
description = "Maximum lifetime of a single ticket in this realm.";
|
||||||
|
@ -208,7 +203,7 @@ in {
|
||||||
users = {
|
users = {
|
||||||
users.${cfg.user} = {
|
users.${cfg.user} = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
home = "/var/kerberos";
|
home = cfg.state-directory;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -224,7 +219,7 @@ in {
|
||||||
};
|
};
|
||||||
realms = { ${cfg.realm} = { enable-http = false; }; };
|
realms = { ${cfg.realm} = { enable-http = false; }; };
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
default = FILE:/var/kerberos/kerberos.log
|
default = FILE:${cfg.state-directory}/kerberos.log
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -169,41 +169,41 @@ let
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options = {
|
options = with types; {
|
||||||
fudo = {
|
fudo = {
|
||||||
auth = {
|
auth = {
|
||||||
ldap-server = {
|
ldap-server = {
|
||||||
enable = mkEnableOption "Fudo Authentication";
|
enable = mkEnableOption "Fudo Authentication";
|
||||||
|
|
||||||
kerberos-host = mkOption {
|
kerberos-host = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The name of the host to use for Kerberos authentication.
|
The name of the host to use for Kerberos authentication.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
kerberos-keytab = mkOption {
|
kerberos-keytab = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The path to a keytab for the LDAP server, containing a principal for ldap/<hostname>.
|
The path to a keytab for the LDAP server, containing a principal for ldap/<hostname>.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sslCert = mkOption {
|
ssl-certificate = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The path to the SSL certificate to use for the server.
|
The path to the SSL certificate to use for the server.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sslKey = mkOption {
|
ssl-private-key = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The path to the SSL key to use for the server.
|
The path to the SSL key to use for the server.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
sslCACert = mkOption {
|
ssl-ca-certificate = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
description = ''
|
description = ''
|
||||||
The path to the SSL CA cert used to sign the certificate.
|
The path to the SSL CA cert used to sign the certificate.
|
||||||
|
@ -212,14 +212,14 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
organization = mkOption {
|
organization = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The name to use for the organization.
|
The name to use for the organization.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
base = mkOption {
|
base = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The base dn of the LDAP server (eg. "dc=fudo,dc=org").
|
The base dn of the LDAP server (eg. "dc=fudo,dc=org").
|
||||||
'';
|
'';
|
||||||
|
@ -227,24 +227,23 @@ in {
|
||||||
|
|
||||||
rootpw-file = mkOption {
|
rootpw-file = mkOption {
|
||||||
default = "";
|
default = "";
|
||||||
type = types.str;
|
type = str;
|
||||||
description = ''
|
description = ''
|
||||||
The path to a file containing the root password for this database.
|
The path to a file containing the root password for this database.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
listen-uris = mkOption {
|
listen-uris = mkOption {
|
||||||
default = [ ];
|
type = listOf str;
|
||||||
type = with types; listOf str;
|
|
||||||
description = ''
|
description = ''
|
||||||
A list of URIs on which the ldap server should listen.
|
A list of URIs on which the ldap server should listen.
|
||||||
'';
|
'';
|
||||||
example = [ "ldap://auth.fudo.org" "ldaps://auth.fudo.org" ];
|
example = [ "ldap://auth.fudo.org" "ldaps://auth.fudo.org" ];
|
||||||
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
default = { };
|
type = attrsOf (submodule ldapUserOpts);
|
||||||
type = with types; attrsOf (submodule ldapUserOpts);
|
|
||||||
example = {
|
example = {
|
||||||
tester = {
|
tester = {
|
||||||
uid = 10099;
|
uid = 10099;
|
||||||
|
@ -255,11 +254,12 @@ in {
|
||||||
description = ''
|
description = ''
|
||||||
Users to be added to the Fudo LDAP database.
|
Users to be added to the Fudo LDAP database.
|
||||||
'';
|
'';
|
||||||
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
groups = mkOption {
|
groups = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = with types; attrsOf (submodule ldapGroupOpts);
|
type = attrsOf (submodule ldapGroupOpts);
|
||||||
example = {
|
example = {
|
||||||
admin = {
|
admin = {
|
||||||
gid = 1099;
|
gid = 1099;
|
||||||
|
@ -273,7 +273,7 @@ in {
|
||||||
|
|
||||||
system-users = mkOption {
|
system-users = mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = with types; attrsOf (submodule ldapSystemUserOpts);
|
type = attrsOf (submodule ldapSystemUserOpts);
|
||||||
example = {
|
example = {
|
||||||
replicator = {
|
replicator = {
|
||||||
description = "System user for database sync";
|
description = "System user for database sync";
|
||||||
|
@ -346,10 +346,10 @@ in {
|
||||||
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
|
|
||||||
TLSCertificateFile ${cfg.sslCert}
|
TLSCertificateFile ${cfg.ssl-certificate}
|
||||||
TLSCertificateKeyFile ${cfg.sslKey}
|
TLSCertificateKeyFile ${cfg.ssl-private-key}
|
||||||
${optionalString (cfg.sslCACert != null)
|
${optionalString (cfg.ssl-ca-certificate != null)
|
||||||
"TLSCACertificateFile ${cfg.sslCACert}"}
|
"TLSCACertificateFile ${cfg.ssl-ca-certificate}"}
|
||||||
|
|
||||||
authz-regexp "^uid=auth/([^.]+)\.fudo\.org,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=$1,ou=hosts,dc=fudo,dc=org"
|
authz-regexp "^uid=auth/([^.]+)\.fudo\.org,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=$1,ou=hosts,dc=fudo,dc=org"
|
||||||
authz-regexp "^uid=[^,/]+/root,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=admin,dc=fudo,dc=org"
|
authz-regexp "^uid=[^,/]+/root,cn=fudo\.org,cn=gssapi,cn=auth$" "cn=admin,dc=fudo,dc=org"
|
||||||
|
|
|
@ -52,11 +52,12 @@ let
|
||||||
path = [ pkgs.age ];
|
path = [ pkgs.age ];
|
||||||
};
|
};
|
||||||
|
|
||||||
secretOpts = { ... }: {
|
secretOpts = { name, ... }: {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
source-file = mkOption {
|
source-file = mkOption {
|
||||||
type = path; # CAREFUL: this will copy the file to nixstore...keep on deploy host
|
type = path; # CAREFUL: this will copy the file to nixstore...keep on deploy host
|
||||||
description = "File from which to load the secret.";
|
description = "File from which to load the secret. If unspecified, a random new password will be generated.";
|
||||||
|
default = "${generate-secret name}/passwd";
|
||||||
};
|
};
|
||||||
|
|
||||||
target-file = mkOption {
|
target-file = mkOption {
|
||||||
|
@ -86,7 +87,26 @@ let
|
||||||
|
|
||||||
nix-build-users = let usernames = attrNames config.users.users;
|
nix-build-users = let usernames = attrNames config.users.users;
|
||||||
in filter (user: (builtins.match "^nixbld[0-9]{1,2}$" user) != null)
|
in filter (user: (builtins.match "^nixbld[0-9]{1,2}$" user) != null)
|
||||||
usernames;
|
usernames;
|
||||||
|
|
||||||
|
generate-secret = name: pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${name}-generated-passwd";
|
||||||
|
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [ pwgen ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
echo "${name}-${config.instance.build-timestamp}" >> file.txt
|
||||||
|
pwgen --secure --symbols --num-passwords=1 --sha1=file.txt 40 > passwd
|
||||||
|
rm -f file.txt
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir $out
|
||||||
|
mv passwd $out/passwd
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.secrets = with types; {
|
options.fudo.secrets = with types; {
|
||||||
|
@ -139,7 +159,9 @@ in {
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
users.groups = {
|
users.groups = {
|
||||||
${cfg.secret-group} = { members = cfg.secret-users ++ nix-build-users; };
|
${cfg.secret-group} = {
|
||||||
|
members = cfg.secret-users ++ nix-build-users;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd = let
|
systemd = let
|
||||||
|
|
|
@ -40,12 +40,6 @@ let
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
gateway-host = mkOption {
|
|
||||||
type = nullOr str;
|
|
||||||
description = "Identity of the host to act as a gateway.";
|
|
||||||
default = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
local-groups = mkOption {
|
local-groups = mkOption {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
description = "List of groups which should exist at this site.";
|
description = "List of groups which should exist at this site.";
|
||||||
|
@ -135,24 +129,9 @@ let
|
||||||
default = [ ];
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
keytab-path = mkOption {
|
mail-server = mkOption {
|
||||||
type = nullOr str;
|
type = str;
|
||||||
description = ''
|
description = "Hostname of the mail server to use for this site.";
|
||||||
Directory containing site keytabs (files named $hostname.keytab).
|
|
||||||
|
|
||||||
Should exist only on build host.
|
|
||||||
'';
|
|
||||||
default = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
build-key-path = mkOption {
|
|
||||||
type = nullOr str;
|
|
||||||
description = ''
|
|
||||||
Directory containing host build keys (files named $hostname.key).
|
|
||||||
|
|
||||||
Should exist only on build host.
|
|
||||||
'';
|
|
||||||
default = null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
|
hostname = config.instance.hostname;
|
||||||
|
|
||||||
cfg = config.fudo.webmail;
|
cfg = config.fudo.webmail;
|
||||||
|
|
||||||
inherit (lib.strings) concatStringsSep;
|
webmail-user = cfg.user;
|
||||||
|
webmail-group = cfg.group;
|
||||||
|
|
||||||
webmail-user = "webmail-php";
|
base-data-path = "/var/run/rainloop";
|
||||||
webmail-group = "webmail-php";
|
|
||||||
|
|
||||||
base-data-path = "/var/rainloop";
|
|
||||||
|
|
||||||
fastcgi-conf = builtins.toFile "fastcgi.conf" ''
|
fastcgi-conf = builtins.toFile "fastcgi.conf" ''
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
@ -54,87 +54,81 @@ let
|
||||||
'';
|
'';
|
||||||
})) cfg.sites;
|
})) cfg.sites;
|
||||||
|
|
||||||
siteOpts = { site-host, ... }: {
|
siteOpts = { site-host, ... }: with types; {
|
||||||
options = {
|
options = {
|
||||||
title = mkOption {
|
title = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Webmail site title";
|
description = "Webmail site title";
|
||||||
example = "My Webmail";
|
example = "My Webmail";
|
||||||
};
|
};
|
||||||
|
|
||||||
debug = mkOption {
|
debug = mkOption {
|
||||||
type = types.bool;
|
type = bool;
|
||||||
description = "Turn debug logs on.";
|
description = "Turn debug logs on.";
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
mail-server = mkOption {
|
mail-server = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Mail server from which to send & recieve email.";
|
description = "Mail server from which to send & recieve email.";
|
||||||
default = "mail.fudo.org";
|
default = "mail.fudo.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
favicon = mkOption {
|
favicon = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "URL of the site favicon";
|
description = "URL of the site favicon";
|
||||||
example = "https://www.somepage.com/fav.ico";
|
example = "https://www.somepage.com/fav.ico";
|
||||||
};
|
};
|
||||||
|
|
||||||
messages-per-page = mkOption {
|
messages-per-page = mkOption {
|
||||||
type = types.int;
|
type = int;
|
||||||
description = "Default number of messages to show per page";
|
description = "Default number of messages to show per page";
|
||||||
default = 30;
|
default = 30;
|
||||||
};
|
};
|
||||||
|
|
||||||
max-upload-size = mkOption {
|
max-upload-size = mkOption {
|
||||||
type = types.int;
|
type = int;
|
||||||
description = "Size limit in MB for uploaded files";
|
description = "Size limit in MB for uploaded files";
|
||||||
default = 30;
|
default = 30;
|
||||||
};
|
};
|
||||||
|
|
||||||
theme = mkOption {
|
theme = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Default theme to use for this webmail site.";
|
description = "Default theme to use for this webmail site.";
|
||||||
default = "Default";
|
default = "Default";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Ideally, don't even allow admin logins, since they'll just add state that can be clobbered
|
|
||||||
# admin-password = mkOption {
|
|
||||||
# type = types.str;
|
|
||||||
# description = "Password to use for the admin user";
|
|
||||||
# };
|
|
||||||
|
|
||||||
domain = mkOption {
|
domain = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Domain for which the server acts as webmail server";
|
description = "Domain for which the server acts as webmail server";
|
||||||
};
|
};
|
||||||
|
|
||||||
edit-mode = mkOption {
|
edit-mode = mkOption {
|
||||||
type = types.enum [ "Plain" "Html" "PlainForced" "HtmlForced" ];
|
type = enum [ "Plain" "Html" "PlainForced" "HtmlForced" ];
|
||||||
description = "Default text editing mode for email";
|
description = "Default text editing mode for email";
|
||||||
default = "Html";
|
default = "Html";
|
||||||
};
|
};
|
||||||
|
|
||||||
layout-mode = mkOption {
|
layout-mode = mkOption {
|
||||||
type = types.enum [ "side" "bottom" ];
|
type = enum [ "side" "bottom" ];
|
||||||
description = "Layout mode to use for email preview.";
|
description = "Layout mode to use for email preview.";
|
||||||
default = "side";
|
default = "side";
|
||||||
};
|
};
|
||||||
|
|
||||||
enable-threading = mkOption {
|
enable-threading = mkOption {
|
||||||
type = types.bool;
|
type = bool;
|
||||||
description = "Whether to enable threading for email.";
|
description = "Whether to enable threading for email.";
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
enable-mobile = mkOption {
|
enable-mobile = mkOption {
|
||||||
type = types.bool;
|
type = bool;
|
||||||
description = "Whether to enable a mobile site view.";
|
description = "Whether to enable a mobile site view.";
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
database = mkOption {
|
database = mkOption {
|
||||||
type = with types; nullOr (submodule databaseOpts);
|
type = nullOr (submodule databaseOpts);
|
||||||
description = "Database configuration for storing contact data.";
|
description = "Database configuration for storing contact data.";
|
||||||
example = {
|
example = {
|
||||||
name = "my_db";
|
name = "my_db";
|
||||||
|
@ -146,58 +140,63 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
admin-email = mkOption {
|
admin-email = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Email of administrator of this site.";
|
description = "Email of administrator of this site.";
|
||||||
default = "admin@fudo.org";
|
default = "admin@fudo.org";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
databaseOpts = { ... }: {
|
databaseOpts = { ... }: with types; {
|
||||||
options = {
|
options = {
|
||||||
type = mkOption {
|
type = mkOption {
|
||||||
type = types.enum [ "pgsql" "mysql" ];
|
type = enum [ "pgsql" "mysql" ];
|
||||||
description = "Driver to use when connecting to the database.";
|
description = "Driver to use when connecting to the database.";
|
||||||
default = "pgsql";
|
default = "pgsql";
|
||||||
};
|
};
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "Name of host running the database.";
|
description = "Name of host running the database.";
|
||||||
example = "my-db.domain.com";
|
example = "my-db.domain.com";
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.int;
|
type = int;
|
||||||
description = "Port on which the database server is listening.";
|
description = "Port on which the database server is listening.";
|
||||||
default = 5432;
|
default = 5432;
|
||||||
};
|
};
|
||||||
|
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description =
|
description =
|
||||||
"Name of the database containing contact info. <user> must have access.";
|
"Name of the database containing contact info. <user> must have access.";
|
||||||
default = "rainloop_contacts";
|
default = "rainloop_webmail";
|
||||||
};
|
};
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = str;
|
||||||
description = "User as which to connect to the database.";
|
description = "User as which to connect to the database.";
|
||||||
|
default = "webmail";
|
||||||
};
|
};
|
||||||
|
|
||||||
password-file = mkOption {
|
password-file = mkOption {
|
||||||
type = types.str;
|
type = nullOr str;
|
||||||
description = "Password to use when connecting to the database.";
|
description = ''
|
||||||
|
Password to use when connecting to the database.
|
||||||
|
|
||||||
|
If unset, a random password will be generated.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.webmail = {
|
options.fudo.webmail = with types; {
|
||||||
enable = mkEnableOption "Enable a RainLoop webmail server.";
|
enable = mkEnableOption "Enable a RainLoop webmail server.";
|
||||||
|
|
||||||
sites = mkOption {
|
sites = mkOption {
|
||||||
type = with types; (attrsOf (submodule siteOpts));
|
type = attrsOf (submodule siteOpts);
|
||||||
description = "A map of webmail sites to site configurations.";
|
description = "A map of webmail sites to site configurations.";
|
||||||
example = {
|
example = {
|
||||||
"webmail.domain.com" = {
|
"webmail.domain.com" = {
|
||||||
|
@ -208,6 +207,18 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "User as which webmail will run.";
|
||||||
|
default = "webmail-php";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Group as which webmail will run.";
|
||||||
|
default = "webmail-php";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
@ -226,13 +237,12 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme.certs = mapAttrs'
|
security.acme.certs = mapAttrs
|
||||||
(site: site-cfg: nameValuePair site { email = site-cfg.admin-email; })
|
(site: site-cfg: { email = site-cfg.admin-email; })
|
||||||
cfg.sites;
|
cfg.sites;
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
phpfpm = {
|
phpfpm = {
|
||||||
|
|
||||||
pools.webmail = {
|
pools.webmail = {
|
||||||
settings = {
|
settings = {
|
||||||
"pm" = "dynamic";
|
"pm" = "dynamic";
|
||||||
|
@ -285,43 +295,63 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fudo.secrets.host-secrets.${hostname} = concatMapAttrs
|
||||||
|
(site: site-cfg: let
|
||||||
|
|
||||||
|
site-config-file = builtins.toFile "${site}-rainloop.cfg"
|
||||||
|
(import ./include/rainloop.nix lib site site-cfg site-pkgs.${site}.version);
|
||||||
|
|
||||||
|
domain-cfg-file = builtins.toFile "${site}-domain.cfg" ''
|
||||||
|
imap_host = "${site-cfg.mail-server}"
|
||||||
|
imap_port = 143
|
||||||
|
imap_secure = "TLS"
|
||||||
|
imap_short_login = On
|
||||||
|
sieve_use = Off
|
||||||
|
sieve_allow_raw = Off
|
||||||
|
sieve_host = ""
|
||||||
|
sieve_port = 4190
|
||||||
|
sieve_secure = "None"
|
||||||
|
smtp_host = "${site-cfg.mail-server}"
|
||||||
|
smtp_port = 587
|
||||||
|
smtp_secure = "TLS"
|
||||||
|
smtp_short_login = On
|
||||||
|
smtp_auth = On
|
||||||
|
smtp_php_mail = Off
|
||||||
|
white_list = ""
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
"${site}-site-config" = {
|
||||||
|
source-file = site-config-file;
|
||||||
|
target-file = "/var/run/webmail/rainloop/site-${site}-rainloop.cfg";
|
||||||
|
user = cfg.user;
|
||||||
|
};
|
||||||
|
|
||||||
|
"${site}-domain-config" = {
|
||||||
|
source-file = domain-config-file;
|
||||||
|
target-file = "/var/run/webmail/rainloop/domain-${site}-rainloop.cfg";
|
||||||
|
user = cfg.user;
|
||||||
|
};
|
||||||
|
}) cfg.sites;
|
||||||
|
|
||||||
|
# TODO: make this a fudo service
|
||||||
systemd.services = {
|
systemd.services = {
|
||||||
webmail-init = let
|
webmail-init = let
|
||||||
link-configs = concatStringsSep "\n" (mapAttrsToList (site: site-cfg:
|
link-configs = concatStringsSep "\n" (mapAttrsToList (site: site-cfg:
|
||||||
let
|
let
|
||||||
cfg-file = builtins.toFile "${site}-rainloop.cfg"
|
cfg-file = config.fudo.secrets.host-secrets.${hostname}."${site}-site-config".target-file;
|
||||||
(import ./include/rainloop.nix lib site site-cfg
|
domain-cfg-file = config.fudo.secrets.host-secrets.${hostname}."${site}-doomain-config".target-file;
|
||||||
site-packages.${site}.version);
|
|
||||||
domain-cfg = builtins.toFile "${site}-domain.cfg" ''
|
|
||||||
imap_host = "${site-cfg.mail-server}"
|
|
||||||
imap_port = 143
|
|
||||||
imap_secure = "TLS"
|
|
||||||
imap_short_login = On
|
|
||||||
sieve_use = Off
|
|
||||||
sieve_allow_raw = Off
|
|
||||||
sieve_host = ""
|
|
||||||
sieve_port = 4190
|
|
||||||
sieve_secure = "None"
|
|
||||||
smtp_host = "${site-cfg.mail-server}"
|
|
||||||
smtp_port = 587
|
|
||||||
smtp_secure = "TLS"
|
|
||||||
smtp_short_login = On
|
|
||||||
smtp_auth = On
|
|
||||||
smtp_php_mail = Off
|
|
||||||
white_list = ""
|
|
||||||
'';
|
|
||||||
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
|
||||||
|
|
||||||
${pkgs.coreutils}/bin/mkdir -p ${base-data-path}/${site}/_data_/_default_/domains/
|
${pkgs.coreutils}/bin/mkdir -p ${base-data-path}/${site}/_data_/_default_/domains/
|
||||||
${pkgs.coreutils}/bin/cp ${domain-cfg} ${base-data-path}/${site}/_data_/_default_/domains/${site-cfg.domain}.ini
|
${pkgs.coreutils}/bin/cp ${domain-cfg-file} ${base-data-path}/${site}/_data_/_default_/domains/${site-cfg.domain}.ini
|
||||||
'') cfg.sites);
|
'') cfg.sites);
|
||||||
scriptPkg = (pkgs.writeScriptBin "webmail-init.sh" ''
|
scriptPkg = (pkgs.writeScriptBin "webmail-init.sh" ''
|
||||||
#!${pkgs.bash}/bin/bash -e
|
#!${pkgs.bash}/bin/bash -e
|
||||||
${link-configs}
|
${link-configs}
|
||||||
${pkgs.coreutils}/bin/chown -R ${webmail-user}:${webmail-group} ${base-data-path}
|
${pkgs.coreutils}/bin/chown -R ${webmail-user}:${webmail-group} ${base-data-path}
|
||||||
${pkgs.coreutils}/bin/chmod -R ug+w ${base-data-path}
|
${pkgs.coreutils}/bin/chmod -R u+w ${base-data-path}
|
||||||
'');
|
'');
|
||||||
in {
|
in {
|
||||||
requiredBy = [ "nginx.service" ];
|
requiredBy = [ "nginx.service" ];
|
||||||
|
|
|
@ -80,6 +80,12 @@ in {
|
||||||
|
|
||||||
local-hosts =
|
local-hosts =
|
||||||
filterAttrs (host: hostOpts: hostOpts.site == local-site) config.fudo.hosts;
|
filterAttrs (host: hostOpts: hostOpts.site == local-site) config.fudo.hosts;
|
||||||
|
|
||||||
|
local-networks =
|
||||||
|
host.local-networks //
|
||||||
|
config.fudo.domains.${local-domain}.local-networks //
|
||||||
|
config.fudo.sites.${local-site}.local-networks;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
instance = {
|
instance = {
|
||||||
local-domain = local-domain;
|
local-domain = local-domain;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
{ lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
hash-ldap-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${name}-ldap-passwd";
|
||||||
|
|
||||||
|
phases = [ "buildPhase" "installPhase" ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [ openldap ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
slappasswd -T ${passwd-file} > ldap-passwd
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir $out
|
||||||
|
mv ldap-passwd $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
hash-ldap-passwd = name: passwd-file: let
|
||||||
|
passwd-pkgs = hash-ldap-passwd-pkg name passwd-file;
|
||||||
|
in builtins.readFile "${passwd-pkgs}/ldap-passwd";
|
||||||
|
|
||||||
|
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${name}-random-passwd";
|
||||||
|
|
||||||
|
phases = [ "buildPhase" "installPhase" ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [ pwgen ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
pwgen --symbols --num-passwords=1 ${length} > passwd
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir $out
|
||||||
|
mv passwd $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
hash-ldap-passwd = hash-ldap-passwd;
|
||||||
|
|
||||||
|
random-passwd-file = name: length:
|
||||||
|
toPath "${generate-random-passwd name length}/passwd";
|
||||||
|
}
|
Loading…
Reference in New Issue