Commit to move

This commit is contained in:
niten 2023-05-16 22:40:08 -07:00
parent f45e9a377a
commit de24170e88
40 changed files with 5188 additions and 936 deletions

View File

@ -1,14 +1,13 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let fudo = config.fudo.domains."fudo.org";
fudo = config.fudo.domains."fudo.org";
in { in {
config.fudo.domains."sea.fudo.org" = { config.fudo.domains."sea.fudo.org" = {
local-networks = fudo.local-networks; local-networks = fudo.local-networks;
gssapi-realm = fudo.gssapi-realm; # gssapi-realm = fudo.gssapi-realm;
kerberos-master = fudo.kerberos-master; # kerberos-master = fudo.kerberos-master;
kerberos-slaves = fudo.kerberos-slaves; # kerberos-slaves = fudo.kerberos-slaves;
primary-mailserver = fudo.primary-mailserver; primary-mailserver = fudo.primary-mailserver;

75
config/hardware/jazz.nix Normal file
View File

@ -0,0 +1,75 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot = {
initrd = {
availableKernelModules =
[ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
kernelModules = [ ];
};
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
kernelModules = [ "kvm-amd" ];
extraModulePackages = [ ];
};
fileSystems = {
"/" = {
device = "jazz-root";
fsType = "tmpfs";
options = [ "mode=755" "noexec" ];
};
"/boot" = {
device = "/dev/disk/by-label/JAZZ-BOOT";
fsType = "vfat";
options = [ "noatime" "noexec" ];
};
"/nix" = {
device = "/dev/disk/by-label/jazz-data";
fsType = "btrfs";
options = [ "subvol=@nix" "noatime" "compress=zstd" ];
};
"/state" = {
device = "/dev/disk/by-label/jazz-data";
fsType = "btrfs";
options = [ "subvol=@state" "noatime" "compress=zstd" ];
};
"/home" = {
device = "/dev/disk/by-label/jazz-data";
fsType = "btrfs";
options = [ "subvol=@home" "noatime" "compress=zstd" ];
};
"/var/log" = {
device = "/dev/disk/by-label/jazz-data";
fsType = "btrfs";
options = [ "subvol=@log" "noatime" "compress=zstd" "noexec" ];
};
};
swapDevices = [{ device = "/dev/disk/by-label/jazz-swap"; }];
hardware = {
enableAllFirmware = true;
cpu.amd.updateMicrocode = true;
};
networking = {
useDHCP = false;
macvlans = {
intif0 = {
interface = "enp5s0";
mode = "bridge";
};
};
interfaces.intif0.macAddress = "02:57:9a:a4:10:d3";
};
}

View File

@ -1,13 +1,22 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, modulesPath, ... }:
with lib; with lib;
let let generateMac = pkgs.lib.network.generate-mac-address;
in { in {
system.stateVersion = "21.05"; imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
config = {
system.stateVersion = "22.05";
boot = { boot = {
initrd = { initrd = {
luks.devices.lambda-unlocked = {
device = "/dev/disk/by-uuid/e90c9dda-4e4c-4ca1-8897-39fcebc03479";
allowDiscards = true;
};
availableKernelModules = [ availableKernelModules = [
"uhci_hcd" "uhci_hcd"
"ehci_pci" "ehci_pci"
@ -18,68 +27,72 @@ in {
"sd_mod" "sd_mod"
"sr_mod" "sr_mod"
]; ];
kernelModules = [ ]; kernelModules = [ "dm-snapshot" ];
}; };
kernelModules = [ "kvm-intel" ]; kernelModules = [ "kvm-intel" ];
supportedFilesystems = [ "zfs" ]; kernelPackages = pkgs.linuxPackages_latest;
loader.grub = { loader.grub = {
enable = true; enable = true;
version = 2; version = 2;
device = "/dev/disk/by-id/wwn-0x600508b1001cecf6b880f591f9b18b29"; device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121";
}; };
}; };
fileSystems = { fileSystems = {
"/" = {
device = "lambda-root";
fsType = "tmpfs";
options = [ "mode=755" "size=32G" "noexec" ];
};
"/boot" = { "/boot" = {
device = "/dev/disk/by-label/lambda-boot"; device = "/dev/disk/by-label/lambda-boot";
fsType = "ext4"; fsType = "ext4";
options = [ "noexec" "noatime" "nodiratime" ]; options = [ "noatime" "noexec" ];
}; };
"/" = {
device = "none";
fsType = "tmpfs";
options = [ "noexec" "mode=755" ];
};
"/nix" = {
device = "lambda/transient/nix";
fsType = "zfs";
options = [ "noatime" "nodiratime" ];
};
"/var/log" = {
device = "lambda/transient/logs";
fsType = "zfs";
neededForBoot = true;
options = [ "noexec" "noatime" "nodiratime" ];
};
"/state" = { "/state" = {
device = "lambda/persistent/state"; device = "/dev/mapper/lambda-unlocked";
fsType = "zfs"; fsType = "btrfs";
options = [ "noexec" "noatime" "nodiratime" ]; options = [ "noatime" "compress=zstd" "noexec" "subvol=@state" ];
};
"/nix" = {
device = "/dev/mapper/lambda-unlocked";
fsType = "btrfs";
options = [ "noatime" "compress=zstd" "subvol=@nix" ];
};
"/home" = {
device = "/dev/mapper/lambda-unlocked";
fsType = "btrfs";
options = [ "noatime" "compress=zstd" "noexec" "subvol=@home" ];
};
"/var/log" = {
device = "/dev/mapper/lambda-unlocked";
fsType = "btrfs";
options = [ "noatime" "compress=zstd" "noexec" "subvol=@log" ];
}; };
}; };
swapDevices = [{ device = "/dev/disk/by-label/lambda-swap"; }]; swapDevices = [{
device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121-part2";
randomEncryption.enable = true;
}];
nix.settings.max-jobs = lib.mkDefault 12; nix.settings.max-jobs = lib.mkDefault 24;
networking = { networking = {
useDHCP = false;
macvlans = { macvlans = {
intif0 = { intif0 = {
interface = "enp3s0f1"; interface = "enp4s0f1";
mode = "bridge"; mode = "bridge";
}; };
}; };
interfaces = { interfaces = {
intif0 = { intif0 = {
# output of: echo lambda-intif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' macAddress = generateMac config.instance.hostname "intif0";
macAddress = "02:f5:fe:8c:22:fe"; };
}; };
}; };
}; };

View File

@ -34,7 +34,7 @@
}; };
}; };
nix.maxJobs = lib.mkDefault 24; nix.settings.max-jobs = lib.mkDefault 24;
hardware.bluetooth.enable = false; hardware.bluetooth.enable = false;

View File

@ -35,7 +35,7 @@
swapDevices = [{ device = "/dev/disk/by-label/swap"; }]; swapDevices = [{ device = "/dev/disk/by-label/swap"; }];
nix.maxJobs = lib.mkDefault 8; nix.settings.max-jobs = lib.mkDefault 8;
hardware.bluetooth.enable = false; hardware.bluetooth.enable = false;

View File

@ -0,0 +1,75 @@
{ config, lib, pkgs, ... }:
{
system.stateVersion = "22.05";
boot = {
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
initrd = {
availableKernelModules =
[ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
kernelModules = [ ];
};
kernelModules = [ "kvm-amd" ];
extraModulePackages = [ ];
};
fileSystems = {
"/" = {
device = "toothless-root";
fsType = "tmpfs";
options = [ "mode=755" "noexec" ];
};
"/boot" = {
device = "/dev/disk/by-label/TOOTH-BOOT";
fsType = "vfat";
options = [ "noatime" "noexec" ];
};
"/nix" = {
device = "/dev/disk/by-label/toothless-data";
fsType = "btrfs";
options = [ "subvol=@nix" "noatime" "compress=zstd" ];
};
"/state" = {
device = "/dev/disk/by-label/toothless-data";
fsType = "btrfs";
options = [ "subvol=@state" "noatime" "compress=zstd" "noexec" ];
};
"/home" = {
device = "/dev/disk/by-label/toothless-data";
fsType = "btrfs";
options = [ "subvol=@home" "noatime" "compress=zstd" "noexec" ];
};
"/var/log" = {
device = "/dev/disk/by-label/toothless-data";
fsType = "btrfs";
options = [ "subvol=@log" "noatime" "compress=zstd" "noexec" ];
};
};
swapDevices = [{ device = "/dev/disk/by-label/toothless-swap"; }];
hardware = {
enableAllFirmware = true;
cpu.amd.updateMicrocode = true;
};
networking = {
useDHCP = false;
macvlans = {
intif0 = {
interface = "enp42s0";
mode = "bridge";
};
};
interfaces.intif0.macAddress = "02:ee:76:17:99:ed";
};
}

View File

@ -0,0 +1,41 @@
{ config, lib, pkgs, ... }:
with lib;
let stateDir = "/state";
in {
fudo = { wallfly.location = "family_room"; };
networking = {
interfaces.intif0.useDHCP = true;
firewall.enable = false;
};
systemd.tmpfiles.rules = [
"L /etc/adjtime - - - - ${stateDir}/etc/adjtime"
"d ${stateDir}/lib/cups 755 root root - -"
"d ${stateDir}/lib/flatpak 755 root root - -"
];
fileSystems = {
"/var/lib/cups" = {
device = "${stateDir}/lib/cups";
options = [ "bind" ];
};
"/var/lib/flatpak" = {
device = "${stateDir}/lib/flatpak";
options = [ "bind" ];
};
};
environment.etc = {
nixos.source = "/etc/nixos-live";
NIXOS.source = "${stateDir}/etc/NIXOS";
};
systemd.targets = {
sleep.enable = false;
suspend.enable = false;
hibernate.enable = false;
hybrid-sleep.enable = false;
};
}

View File

@ -1,15 +1,10 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let primaryIp = "10.0.0.11";
state-dir = "/state"; # This must be a string!
generate-mac = pkgs.lib.network.generate-mac-address;
in { in {
boot = { config = {
loader.grub.copyKernels = true; boot = { loader.grub.copyKernels = true; };
#kernelModules = [ "rpcsec_gss_krb5" ];
};
networking = { networking = {
interfaces = { interfaces = {
@ -18,59 +13,28 @@ in {
enp4s0f0.useDHCP = false; enp4s0f0.useDHCP = false;
enp4s0f1.useDHCP = false; enp4s0f1.useDHCP = false;
intif0.useDHCP = true; intif0 = {
useDHCP = false;
ipv4.addresses = [{
address = primaryIp;
prefixLength = 16;
}];
}; };
}; };
systemd.tmpfiles.rules = [ defaultGateway = {
"L /root/.gnupg - - - - ${state-dir}/user/root/gnupg" address = "10.0.0.1";
"L /root/.ssh/id_rsa - - - - ${state-dir}/user/root/ssh/id_rsa" interface = "intif0";
"L /root/.ssh/id_rsa.pub - - - - ${state-dir}/user/root/ssh/id_rsa.pub" };
"L /root/.ssh/known_hosts - - - - ${state-dir}/user/root/ssh/known_hosts" };
];
services.openssh.hostKeys = [ environment = {
{ etc = {
path = "${state-dir}/ssh/ssh_host_rsa_key";
type = "rsa";
bits = 4096;
}
{
path = "${state-dir}/ssh/ssh_host_ed25519_key";
type = "ed25519";
bits = 4096;
}
];
environment.etc = {
"ssh/ssh_host_rsa_key" = {
source = "${state-dir}/ssh/ssh_host_rsa_key";
user = "root";
group = "root";
mode = "0400";
};
"ssh/ssh_host_rsa_key.pub" = {
source = "${state-dir}/ssh/ssh_host_rsa_key.pub";
user = "root";
group = "root";
mode = "0444";
};
"ssh/ssh_host_ed25519_key" = {
source = "${state-dir}/ssh/ssh_host_ed25519_key";
user = "root";
group = "root";
mode = "0400";
};
"ssh/ssh_host_ed25519_key.pub" = {
source = "${state-dir}/ssh/ssh_host_ed25519_key.pub";
user = "root";
group = "root";
mode = "0444";
};
nixos.source = "/etc/nixos-live"; nixos.source = "/etc/nixos-live";
adjtime.source = "/state/host/adjtime";
NIXOS.source = "/state/host/NIXOS"; NIXOS.source = "/state/host/NIXOS";
}; };
systemPackages = with pkgs; [ nixopsUnstable openssl ];
};
security.sudo.extraConfig = '' security.sudo.extraConfig = ''
# Due to rollback, sudo will lecture after every reboot # Due to rollback, sudo will lecture after every reboot
@ -81,14 +45,28 @@ in {
secrets = { secrets = {
secret-group = "fudo-secrets"; secret-group = "fudo-secrets";
secret-users = [ "niten" ]; secret-users = [ "niten" ];
secret-paths = [ "/state/secrets" ]; secret-paths = [ "/secrets" ];
};
hosts.lambda.encrypted-filesystems.secrets = {
encrypted-device =
"/dev/disk/by-id/scsi-3600508b1001c2f439e343270a365a5bd-part1";
key-path = "/state/secrets-key/key";
filesystem-type = "btrfs";
remove-key = false;
type = "luks2";
mountpoints = {
"/secrets" = {
options = [ "noatime" "compress=zstd" ];
group = "fudo-secrets";
users = [ "niten" ];
world-readable = false;
};
};
};
}; };
minecraft-clj = { systemd = {
enable = true; tmpfiles.rules = [ "L /etc/adjtime - - - - /state/etc/adjtime" ];
state-directory = "/state/services/minecraft-clj";
admins = [ "fudoniten" ];
worlds = { REPLand = { allocated-memory = 16; }; };
}; };
}; };
} }

View File

@ -55,8 +55,8 @@ in {
ldap.state-directory = "/state/auth/ldap"; ldap.state-directory = "/state/auth/ldap";
kerberos = { kerberos = {
state-directory = "/state/auth/kerberos"; state-directory = "/state/auth/kerberos";
master-key-file = host-secrets.heimdal-master-key.target-file; # master-key-file = host-secrets.heimdal-master-key.target-file;
ipropd-keytab = host-secrets.heimdal-ipropd-keytab.target-file; # ipropd-keytab = host-secrets.heimdal-ipropd-keytab.target-file;
}; };
}; };
@ -64,15 +64,17 @@ in {
state-directory = "/state/services/chat"; state-directory = "/state/services/chat";
external-interface = "extif0"; external-interface = "extif0";
}; };
nexus.dns-server.listen-addresses = [ host-ipv4 ];
}; };
secrets.host-secrets.legatus = let files = config.fudo.secrets.files; secrets.host-secrets.legatus = let files = config.fudo.secrets.files;
in { in {
postgres-keytab = { # postgres-keytab = {
source-file = files.service-keytabs.procul.postgres; # source-file = files.service-keytabs.procul.postgres;
target-file = "/srv/postgres/secure/postgres.keytab"; # target-file = "/srv/postgres/secure/postgres.keytab";
user = "root"; # user = "root";
}; # };
# gitea-database-password = { # gitea-database-password = {
# source-file = files.service-passwords.procul.gitea-database; # source-file = files.service-passwords.procul.gitea-database;
@ -80,17 +82,17 @@ in {
# user = config.fudo.git.user; # user = config.fudo.git.user;
# }; # };
heimdal-master-key = { # heimdal-master-key = {
source-file = files.realm-master-keys."FUDO.ORG"; # source-file = files.realm-master-keys."FUDO.ORG";
target-file = "/run/heimdal/master-key"; # target-file = "/run/heimdal/master-key";
user = config.fudo.auth.kdc.user; # user = config.fudo.auth.kdc.user;
}; # };
heimdal-ipropd-keytab = { # heimdal-ipropd-keytab = {
source-file = files.service-keytabs.legatus.ipropd; # source-file = files.service-keytabs.legatus.ipropd;
target-file = "/run/heimdal/ipropd.keytab"; # target-file = "/run/heimdal/ipropd.keytab";
user = config.fudo.auth.kdc.user; # user = config.fudo.auth.kdc.user;
}; # };
}; };
client.dns = { client.dns = {

View File

@ -93,6 +93,8 @@ in {
prometheus.state-directory = "/state/services/prometheus"; prometheus.state-directory = "/state/services/prometheus";
}; };
auth.kerberos.state-directory = "/state/services/heimdal-kdc";
# wireguard-gateway = { # wireguard-gateway = {
# enable = true; # enable = true;
# network = "10.0.200.0/24"; # network = "10.0.200.0/24";

View File

@ -21,12 +21,19 @@ in {
firewall.enable = false; firewall.enable = false;
}; };
environment.systemPackages = [ pkgs.kdcConvertDatabase ];
# Hopefully this'll help with NFS... # Hopefully this'll help with NFS...
boot.kernelModules = [ "rpcsec_gss_krb5" ]; boot.kernelModules = [ "rpcsec_gss_krb5" ];
services = { services = {
murmur.enable = true; murmur.enable = true;
# objectifier = {
# enable = true;
# listen-addresses = [ "0.0.0.0" ];
# };
nfs = { nfs = {
# See ../user-config.nix for the user@REALM -> user mapping # See ../user-config.nix for the user@REALM -> user mapping
server = { server = {
@ -117,6 +124,8 @@ in {
}; };
ldap.base-dn = "dc=fudo,dc=org"; ldap.base-dn = "dc=fudo,dc=org";
}; };
auth.kerberos.state-directory = "/state/services/heimdal-kdc";
}; };
postgresql = { postgresql = {

View File

@ -7,7 +7,7 @@
data-dir = "/state/minecraft/data"; data-dir = "/state/minecraft/data";
world-name = "selbyland"; world-name = "selbyland";
game-mode = "creative"; game-mode = "creative";
difficulty = 0; difficulty = 2;
allow-cheats = true; allow-cheats = true;
allocated-memory = 14; allocated-memory = 14;
}; };

View File

@ -1,6 +1,6 @@
{ config, lib, pkgs, ... }: { config, pkgs, ... }:
with lib; with pkgs.lib;
let let
hostname = "nutboy3"; hostname = "nutboy3";
host-fqdn = config.instance.host-fqdn; host-fqdn = config.instance.host-fqdn;
@ -32,6 +32,8 @@ in {
]; ];
config = { config = {
boot.kernelModules = [ "veth" ];
networking = { networking = {
nameservers = [ "1.1.1.1" ]; nameservers = [ "1.1.1.1" ];
defaultGateway = { defaultGateway = {
@ -65,24 +67,22 @@ in {
secrets.host-secrets.${hostname} = let files = config.fudo.secrets.files; secrets.host-secrets.${hostname} = let files = config.fudo.secrets.files;
in { in {
heimdal-master-key = { # heimdal-master-key = {
source-file = files.realm-master-keys."FUDO.ORG"; # source-file = files.realm-master-keys."FUDO.ORG";
target-file = "/run/heimdal/master-key"; # target-file = "/run/heimdal/master-key";
user = config.fudo.auth.kdc.user; # user = config.fudo.auth.kdc.user;
}; # };
ldap-keytab = { ldap-keytab = {
source-file = files.service-keytabs.${hostname}.openldap; # files.service-keytabs.${hostname}.openldap;
source-file = extractFudoKeytab {
realm = domain.gssapi-realm;
principals = [ "ldap/${host-fqdn}" ];
};
target-file = "/run/openldap/ldap.keytab"; target-file = "/run/openldap/ldap.keytab";
user = config.services.openldap.user; user = config.services.openldap.user;
}; };
postgresql-keytab = {
source-file = files.service-keytabs.nutboy3.postgres;
target-file = "/run/postgresql/postgres.keytab";
user = postgresql-user;
};
grafana-database-password = { grafana-database-password = {
source-file = grafana-database-passwd-file; source-file = grafana-database-passwd-file;
target-file = "/run/metrics/grafana/db.passwd"; target-file = "/run/metrics/grafana/db.passwd";
@ -129,15 +129,17 @@ in {
auth = { auth = {
ldap.state-directory = "/state/auth/ldap"; ldap.state-directory = "/state/auth/ldap";
kerberos = { kerberos = {
state-directory = "/state/auth/kerberos"; state-directory = "/state/services/heimdal-kdc";
master-key-file = host-secrets.heimdal-master-key.target-file; # master-key-file = host-secrets.heimdal-master-key.target-file;
}; };
}; };
postgresql = { postgresql = {
state-directory = "/state/services/postgresql"; state-directory = "/state/services/postgresql";
keytab = keytab = extractFudoKeytab {
config.fudo.secrets.files.service-keytabs.${hostname}.postgres; realm = domain.gssapi-realm;
principals = [ "postgres/${host-fqdn}" ];
};
}; };
metrics = { metrics = {

View File

@ -6,19 +6,14 @@ let
host-ipv4 = "199.87.154.175"; host-ipv4 = "199.87.154.175";
local-packages = with pkgs; [ local-packages = with pkgs; [ bind emacs-nox mtr vim ];
bind
emacs-nox
mtr
vim
];
fudo-zone = pkgs.lib.dns.zoneToZonefile fudo-zone =
config.instance.build-timestamp "fudo.org" pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp "fudo.org"
config.fudo.zones."fudo.org"; config.fudo.zones."fudo.org";
selby-zone = pkgs.lib.dns.zoneToZonefile selby-zone =
config.instance.build-timestamp "selby.ca" pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp "selby.ca"
config.fudo.zones."selby.ca"; config.fudo.zones."selby.ca";
in { in {
@ -36,12 +31,14 @@ in {
{ {
ipv4-address = "209.177.102.102"; ipv4-address = "209.177.102.102";
ipv6-address = "2001:470:1f16:40::2"; ipv6-address = "2001:470:1f16:40::2";
description = "Nameserver 2, Musashi.100percenthost.net, in Winnipeg, MB, CA"; description =
"Nameserver 2, Musashi.100percenthost.net, in Winnipeg, MB, CA";
} }
{ {
ipv4-address = "104.131.53.95"; ipv4-address = "104.131.53.95";
ipv6-address = "2604:a880:800:10::8:7001"; ipv6-address = "2604:a880:800:10::8:7001";
description = "Nameserver 3, ns2.henchmman21.net, in New York City, NY, US"; description =
"Nameserver 3, ns2.henchmman21.net, in New York City, NY, US";
} }
{ {
ipv4-address = "204.42.254.5"; ipv4-address = "204.42.254.5";
@ -52,12 +49,12 @@ in {
}; };
"selby.ca" = { "selby.ca" = {
enable = true; enable = true;
external-nameservers = map (n: let external-nameservers = map (n:
i = toString n; let i = toString n;
in { in {
authoritative-hostname = "ns${i}.fudo.org"; authoritative-hostname = "ns${i}.fudo.org";
description = "Nameserver ${i}, ns${i}.fudo.org."; description = "Nameserver ${i}, ns${i}.fudo.org.";
}) [2 3 4]; }) [ 2 3 4 ];
}; };
}; };
@ -82,9 +79,7 @@ in {
"rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org." "rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org."
]; ];
}; };
"selby.ca" = { "selby.ca" = { default-host = host-ipv4; };
default-host = host-ipv4;
};
}; };
}; };
@ -117,17 +112,15 @@ in {
interfaces = [ "eno2" ]; interfaces = [ "eno2" ];
config = { config, ... }: { config = { config, ... }: {
boot.kernelModules = [ "veth" ];
nixpkgs.pkgs = pkgs; nixpkgs.pkgs = pkgs;
environment = { environment = {
systemPackages = local-packages; systemPackages = local-packages;
etc = { etc = {
"generated-zones/fudo.org" = { "generated-zones/fudo.org" = { text = fudo-zone; };
text = fudo-zone; "generated-zones/selby.ca" = { text = selby-zone; };
};
"generated-zones/selby.ca" = {
text = selby-zone;
};
}; };
}; };
@ -144,17 +137,8 @@ in {
]; ];
}; };
groups = { groups = {
wheel.members = [ wheel.members = [ "niten" "reaper" ];
"niten" dns = { members = [ "niten" "reaper" "named" ]; };
"reaper"
];
dns = {
members = [
"niten"
"reaper"
"named"
];
};
}; };
}; };

View File

@ -1,6 +1,6 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib; with pkgs.lib;
let let
hostname = "procul"; hostname = "procul";
@ -58,16 +58,14 @@ in {
networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedTCPPorts = [ 80 443 ];
security.acme.email = "viator@informis.land"; security.acme.defaults.email = "viator@informis.land";
users = { users = {
users = { users.gituser = {
gituser = {
isSystemUser = true; isSystemUser = true;
group = "nogroup"; group = "nogroup";
}; };
}; groups.acme.members = [ "nginx" ];
groups = { acme = { members = [ "nginx" ]; }; };
}; };
informis = { informis = {
@ -154,11 +152,11 @@ in {
user = config.services.postgresql.superUser; user = config.services.postgresql.superUser;
}; };
heimdal-master-key = { # heimdal-master-key = {
source-file = files.realm-master-keys."INFORMIS.LAND"; # source-file = files.realm-master-keys."INFORMIS.LAND";
target-file = "/run/heimdal/master-key"; # target-file = "/run/heimdal/master-key";
user = config.fudo.auth.kdc.user; # user = config.fudo.auth.kdc.user;
}; # };
chute-staging-credentials = { chute-staging-credentials = {
source-file = files.service-secrets.procul."chute-staging.env"; source-file = files.service-secrets.procul."chute-staging.env";
@ -260,7 +258,11 @@ in {
}; };
postgresql = { postgresql = {
state-directory = "/state/services/postgresql"; state-directory = "/state/services/postgresql";
keytab = config.fudo.secrets.files.service-keytabs.procul.postgres; keytab = extractFudoHostKeytab {
inherit hostname;
realm = domain.gssapi-realm;
services = [ "postgres" ];
};
}; };
logging.loki.state-directory = "/state/services/loki"; logging.loki.state-directory = "/state/services/loki";
metrics = { metrics = {

View File

@ -1,6 +1,8 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib; { with lib;
let state-dir = "/state";
in {
fudo = { fudo = {
slynk.enable = true; slynk.enable = true;
wallfly.location = "office"; wallfly.location = "office";
@ -16,6 +18,15 @@ with lib; {
fcitx5.addons = with pkgs; [ fcitx5-chinese-addons fcitx5-rime ]; fcitx5.addons = with pkgs; [ fcitx5-chinese-addons fcitx5-rime ];
}; };
systemd.tmpfiles.rules = [ "d ${state-dir}/lib/cups 755 root root - -" ];
fileSystems = {
"/var/lib/cups" = {
device = "${state-dir}/lib/cups";
options = [ "bind" ];
};
};
# fudo.adguard-dns-proxy = { # fudo.adguard-dns-proxy = {
# enable = true; # enable = true;
# http.listen-ip = "10.0.0.108"; # http.listen-ip = "10.0.0.108";

View File

@ -20,6 +20,7 @@ in {
"L /root/.ssh/known_hosts - - - - ${state-dir}/user/root/ssh/known_hosts" "L /root/.ssh/known_hosts - - - - ${state-dir}/user/root/ssh/known_hosts"
"L /var/lib/flatpak - - - - ${state-dir}/lib/flatpak" "L /var/lib/flatpak - - - - ${state-dir}/lib/flatpak"
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime" "L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
"d ${state-dir}/lib/cups 755 root root - -"
]; ];
services = { services = {
@ -38,6 +39,13 @@ in {
]; ];
}; };
fileSystems = {
"/var/lib/cups" = {
device = "${state-dir}/lib/cups";
options = [ "bind" ];
};
};
environment.etc = { environment.etc = {
nixos.source = "/etc/nixos-live"; nixos.source = "/etc/nixos-live";
NIXOS.source = "${state-dir}/etc/NIXOS"; NIXOS.source = "${state-dir}/etc/NIXOS";

View File

@ -0,0 +1,55 @@
{ config, lib, pkgs, ... }:
let
stateDir = "/state";
primaryIp = "10.0.0.12";
generateMac = pkgs.lib.network.generate-mac-address;
in {
networking = {
useDHCP = false;
defaultGateway = {
address = "10.0.0.1";
interface = "intif0";
};
interfaces.intif0 = {
ipv4.addresses = [{
address = primaryIp;
prefixLength = 16;
}];
};
};
security.sudo.extraConfig = ''
# Due to rollback, sudo will lecture after every reboot
Defaults lecture = never
'';
fudo = {
minecraft-clj = {
enable = true;
state-directory = "/state/services/minecraft-clj";
admins = [ "fudoniten" ];
worlds = {
REPLand = { allocated-memory = 8; };
wof = {
world-name = "WorldOfFun";
world-seed = 2059666523504992;
port = 25567;
difficulty = "medium";
game-mode = "survival";
motd = "Welcome to the World of Fun!";
allow-cheats = true;
allocated-memory = 16;
pvp = false;
};
};
};
};
systemd.targets = {
sleep.enable = false;
suspend.enable = false;
hibernate.enable = false;
hybrid-sleep.enable = false;
};
}

View File

@ -6,13 +6,10 @@ let
primary-ip = "10.0.0.3"; primary-ip = "10.0.0.3";
state-dir = "/state"; state-dir = "/state";
zigbee2mqtt-statedir = "${state-dir}/services/zigbee2mqtt"; zigbee2mqtt-statedir = "${state-dir}/services/zigbee2mqtt";
mosquitto-statedir = "${state-dir}/services/mosquitto";
home-assistant-port = 8123; home-assistant-port = 8123;
zigbee2mqtt-user = config.systemd.services.zigbee2mqtt.serviceConfig.User; zigbee2mqtt-user = config.systemd.services.zigbee2mqtt.serviceConfig.User;
mosquitto-user = config.systemd.services.mosquitto.serviceConfig.User;
zigbee2mqtt-passwd-file = zigbee2mqtt-passwd-file =
pkgs.lib.passwd.stablerandom-passwd-file "zigbee2mqtt-passwd" pkgs.lib.passwd.stablerandom-passwd-file "zigbee2mqtt-passwd"
config.instance.build-seed; config.instance.build-seed;
@ -54,31 +51,21 @@ in {
dhcpcd.extraConfig = concatStringsSep "\n" [ "nogateway" ]; dhcpcd.extraConfig = concatStringsSep "\n" [ "nogateway" ];
}; };
fudo.secrets.host-secrets.${hostname} = { fudo.services.mqtt = {
mosquitto-zigbee2mqtt-passwd = { enable = true;
source-file = zigbee2mqtt-passwd-file; state-directory = "${state-dir}/services/mosquitto";
target-file = "/run/mosquitto-secrets/zigbee2mqtt.passwd"; private = {
user = mosquitto-user; enable = true;
users = {
zigbee2mqtt = {
password-file = zigbee2mqtt-passwd-file;
acl = [ "readwrite #" ];
}; };
mosquitto-home-assistant-passwd = { home-assistant = {
source-file = host-passwds.mosquitto-home-assistant; password-file = host-passwds.mosquitto-home-assistant;
target-file = "/run/mosquitto-secrets/home-assistant.passwd"; acl = [ "readwrite #" ];
user = mosquitto-user;
}; };
mosquitto-niten-passwd = {
source-file = host-passwds.mosquitto-niten;
target-file = "/run/mosquitto-secrets/niten.passwd";
user = mosquitto-user;
}; };
mosquitto-xiaoxuan-passwd = {
source-file = host-passwds.mosquitto-xiaoxuan;
target-file = "/run/mosquitto-secrets/xiaoxuan.passwd";
user = mosquitto-user;
};
mosquitto-wallfly-passwd = {
source-file = host-passwds.mosquitto-wallfly;
target-file = "/run/mosquitto-secrets/wallfly.passwd";
user = mosquitto-user;
}; };
}; };
@ -95,15 +82,6 @@ in {
RemainAfterExit = true; RemainAfterExit = true;
}; };
}; };
zigbee2mqtt = {
after = [ config.fudo.secrets.secret-target "mosquitto.service" ];
restartIfChanged = true;
};
mosquitto = {
after = [ config.fudo.secrets.secret-target ];
restartIfChanged = true;
};
}; };
tmpfiles.rules = [ tmpfiles.rules = [
@ -114,7 +92,6 @@ in {
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime" "L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
"d /state/services 0711 root root - -" "d /state/services 0711 root root - -"
"d ${zigbee2mqtt-statedir} 0700 ${zigbee2mqtt-user} - - -" "d ${zigbee2mqtt-statedir} 0700 ${zigbee2mqtt-user} - - -"
"d ${mosquitto-statedir} 0700 ${mosquitto-user} - - -"
]; ];
}; };
@ -149,39 +126,39 @@ in {
}; };
}; };
mosquitto = { # mosquitto = {
enable = true; # enable = true;
dataDir = mosquitto-statedir; # dataDir = mosquitto-statedir;
listeners = [{ # listeners = [{
settings.allow_anonymous = false; # settings.allow_anonymous = false;
port = 1883; # port = 1883;
address = "0.0.0.0"; # address = "0.0.0.0";
users = { # users = {
zigbee2mqtt = { # zigbee2mqtt = {
passwordFile = # passwordFile =
host-secrets.mosquitto-zigbee2mqtt-passwd.target-file; # host-secrets.mosquitto-zigbee2mqtt-passwd.target-file;
acl = [ "readwrite #" ]; # acl = [ "readwrite #" ];
}; # };
home-assistant = { # home-assistant = {
passwordFile = # passwordFile =
host-secrets.mosquitto-home-assistant-passwd.target-file; # host-secrets.mosquitto-home-assistant-passwd.target-file;
acl = [ "readwrite #" ]; # acl = [ "readwrite #" ];
}; # };
# niten = { # niten = {
# passwordFile = host-secrets.mosquitto-niten-passwd.target-file; # passwordFile = host-secrets.mosquitto-niten-passwd.target-file;
# acl = [ "readwrite #" ]; # acl = [ "readwrite #" ];
# }; # };
# xiaoxuan = { # # xiaoxuan = {
# passwordFile = host-secrets.mosquitto-xiaoxuan-passwd.target-file; # # passwordFile = host-secrets.mosquitto-xiaoxuan-passwd.target-file;
# acl = [ "readwrite #" ]; # # acl = [ "readwrite #" ];
# # };
# # wallfly = {
# # passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
# # acl = [ "readwrite homeassistant/binary_sensor/#" ];
# # };
# }; # };
# wallfly = { # }];
# passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
# acl = [ "readwrite homeassistant/binary_sensor/#" ];
# }; # };
};
}];
};
zigbee2mqtt = { zigbee2mqtt = {
enable = true; enable = true;
@ -191,8 +168,11 @@ in {
homeassistant = true; homeassistant = true;
permit_join = true; permit_join = true;
serial.port = "/dev/ttyUSB0"; serial.port = "/dev/ttyUSB0";
mqtt = { mqtt = let
server = "mqtt://127.0.0.1:1883"; mqttHost = config.fudo.services.mqtt.mqtt-hostname;
mqttPort = config.fudo.services.mqtt.private.port;
in {
server = "mqtt://${mqttHost}:${toString mqttPort}";
user = "zigbee2mqtt"; user = "zigbee2mqtt";
password = readFile zigbee2mqtt-passwd-file; password = readFile zigbee2mqtt-passwd-file;
# TODO: could make a yaml file containing password # TODO: could make a yaml file containing password

View File

@ -1,5 +1,6 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
let state-dir = "/state"; let state-dir = "/state";
in { in {
config = { config = {
@ -19,12 +20,20 @@ in {
}; };
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d ${state-dir}/lib/cups 755 root root - -"
"d ${state-dir}/lib/flatpak 0755 root root - -" "d ${state-dir}/lib/flatpak 0755 root root - -"
"d ${state-dir}/etc 0755 root root - -" "d ${state-dir}/etc 0755 root root - -"
"L /var/lib/flatpak - - - - ${state-dir}/lib/flatpak" "L /var/lib/flatpak - - - - ${state-dir}/lib/flatpak"
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime" "L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
]; ];
fileSystems = {
"/var/lib/cups" = {
device = "${state-dir}/lib/cups";
options = [ "bind" ];
};
};
hardware = { hardware = {
bluetooth = { bluetooth = {
enable = true; enable = true;
@ -32,5 +41,11 @@ in {
}; };
xpadneo.enable = true; xpadneo.enable = true;
}; };
services.xserver = {
layout = "us";
xkbVariant = mkForce "";
xkbOptions = mkForce "";
};
}; };
} }

View File

@ -1,10 +1,10 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib; with lib;
let let has-secret-files = hasAttr "files" config.fudo.secrets;
has-secret-files = hasAttr "files" config.fudo.secrets;
in { in {
config.instance = mkIf has-secret-files { config.instance = mkIf has-secret-files {
# TODO: This has a newline, I think...
build-seed = builtins.readFile config.fudo.secrets.files.build-seed; build-seed = builtins.readFile config.fudo.secrets.files.build-seed;
}; };
} }

View File

@ -106,4 +106,7 @@ in {
}; };
in [ factorio ]; in [ factorio ];
}; };
fudo.services.tattler.enable-notifications =
trace "${hostname}: ${toString enable-gui}" enable-gui;
} }

View File

@ -31,7 +31,7 @@ in {
in concatMap nix-files import-paths; in concatMap nix-files import-paths;
config = { config = {
fudo.hosts.${hostname}.local-networks = [ "::1/128" ]; fudo = { hosts.${hostname}.local-networks = [ "::1/128" ]; };
system.autoUpgrade.enable = false; system.autoUpgrade.enable = false;
@ -49,28 +49,7 @@ in {
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
hardware.enableRedistributableFirmware = true; hardware.enableAllFirmware = true;
krb5 = {
enable = true;
appdefaults = {
forwardable = true;
proxiable = true;
encrypt = true;
forward = true;
};
libdefaults = {
allow_weak_crypto = true;
dns_lookup_kdc = true;
dns_lookup_realm = true;
forwardable = true;
proxiable = true;
};
kerberos = pkgs.heimdal;
};
services = { services = {
openssh = { openssh = {
@ -78,12 +57,12 @@ in {
startWhenNeeded = true; startWhenNeeded = true;
useDns = true; useDns = true;
permitRootLogin = "prohibit-password"; permitRootLogin = "prohibit-password";
extraConfig = '' # extraConfig = ''
GSSAPIAuthentication yes # GSSAPIAuthentication yes
GSSAPICleanupCredentials yes # GSSAPICleanupCredentials yes
GSSAPIKeyExchange yes # GSSAPIKeyExchange yes
GSSAPIStoreCredentialsOnRekey yes # GSSAPIStoreCredentialsOnRekey yes
''; # '';
# FIXME: This is temporary! Getting error: Unsupported KEX algorithm "sntrup761x25519-sha512@openssh.com" # FIXME: This is temporary! Getting error: Unsupported KEX algorithm "sntrup761x25519-sha512@openssh.com"
kexAlgorithms = [ kexAlgorithms = [
"curve25519-sha256" "curve25519-sha256"
@ -102,7 +81,7 @@ in {
xserver = { xserver = {
layout = "us"; layout = "us";
xkbVariant = "dvp"; xkbVariant = "dvp";
xkbOptions = ""; xkbOptions = "ctrl:nocaps";
}; };
btrfs.autoScrub.enable = let btrfs.autoScrub.enable = let
@ -111,7 +90,10 @@ in {
in length btrfsFilesystems > 0; in length btrfsFilesystems > 0;
pcscd.enable = true; pcscd.enable = true;
udev.packages = with pkgs; [ yubikey-personalization ]; udev = {
enable = true;
packages = with pkgs; [ yubikey-personalization ];
};
}; };
networking.firewall = { networking.firewall = {
@ -139,16 +121,7 @@ in {
# pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses"; # pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses";
}; };
ssh = { ssh = { startAgent = true; };
startAgent = true;
package = pkgs.openssh_gssapi;
extraConfig = ''
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
'';
};
}; };
security = { security = {

View File

@ -7,8 +7,9 @@ let
try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null; try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
in { in {
config = mkIf has-secret-files config = mkIf has-secret-files (let
(let keytab-file = try-attr hostname config.fudo.secrets.files.host-keytabs; keytab-file =
try-attr hostname config.fudo.secrets.files.kerberos.host-keytabs;
in mkIf (keytab-file != null) { in mkIf (keytab-file != null) {
## This doesn't seem to work...timing? ## This doesn't seem to work...timing?
# environment.etc."krb5.keytab" = mkIf (keytab-file != null) { # environment.etc."krb5.keytab" = mkIf (keytab-file != null) {
@ -19,6 +20,22 @@ in {
# mode = "0400"; # mode = "0400";
# }; # };
krb5 = {
domain_realm = let
krbDoms = filterAttrs (_: domCfg: domCfg.gssapi-realm != null)
config.fudo.domains;
domClauses = dom: domCfg: [
(nameValuePair dom domCfg.gssapi-realm)
(nameValuePair ".${dom}" domCfg.gssapi-realm)
];
concatMapAttrs = f: lst:
listToAttrs (concatMap (i: i) (mapAttrsToList f lst));
in concatMapAttrs domClauses krbDoms;
libdefaults.default_etypes =
"aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96";
};
systemd = let systemd = let
host-keytab = host-keytab =
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file; config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;

View File

@ -8,16 +8,17 @@ let
has-secret-files = hasAttr "files" config.fudo.secrets; has-secret-files = hasAttr "files" config.fudo.secrets;
in { in {
config = mkIf has-secret-files config = mkIf has-secret-files (let
(let
host-keypairs = host-keypairs =
if (hasAttr hostname config.fudo.secrets.files.host-ssh-keypairs) then if (hasAttr hostname config.fudo.secrets.files.ssh.host-keypairs) then
config.fudo.secrets.files.host-ssh-keypairs.${hostname} config.fudo.secrets.files.ssh.host-keypairs.${hostname}
else []; else
[ ];
in { in {
fudo = let fudo = let
sshfp-filename = host: keypair: "ssh-${host}-${keypair.key-type}.sshfp-record"; sshfp-filename = host: keypair:
"ssh-${host}-${keypair.key-type}.sshfp-record";
dns-sshfp-records = host: keypair: dns-sshfp-records = host: keypair:
pkgs.stdenv.mkDerivation { pkgs.stdenv.mkDerivation {
@ -27,36 +28,33 @@ in {
buildInputs = with pkgs; [ openssh ]; buildInputs = with pkgs; [ openssh ];
installPhase = installPhase = ''
"ssh-keygen -r REMOVEME -f \"${keypair.public-key}\" | sed 's/^REMOVEME IN SSHFP //' > $out"; ssh-keygen -r REMOVEME -f "${keypair.public-key}" | sed 's/^REMOVEME IN SSHFP //' > $out'';
}; };
host-cfg = config.fudo.hosts.${hostname}; host-cfg = config.fudo.hosts.${hostname};
in { in {
secrets.host-secrets.${hostname} = listToAttrs secrets.host-secrets.${hostname} = listToAttrs (map (keypair:
(map nameValuePair "host-${keypair.key-type}-private-key" {
(keypair: nameValuePair "host-${keypair.key-type}-private-key" {
source-file = keypair.private-key; source-file = keypair.private-key;
target-file = "/run/openssh/private/host-${keypair.key-type}-private-key"; target-file =
"/run/openssh/private/host-${keypair.key-type}-private-key";
user = "root"; user = "root";
}) }) host-keypairs);
host-keypairs);
hosts = mkIf (hasAttr "files" config.fudo.secrets) hosts = mkIf (hasAttr "files" config.fudo.secrets) (mapAttrs
(mapAttrs (hostname: keypairs: { (hostname: keypairs: {
ssh-pubkeys = map (keypair: keypair.public-key) keypairs; ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
ssh-fingerprints = concatMap (keypair: ssh-fingerprints = concatMap (keypair:
let let fingerprint-derivation = dns-sshfp-records hostname keypair;
fingerprint-derivation = dns-sshfp-records hostname keypair;
in read-lines "${fingerprint-derivation}") keypairs; in read-lines "${fingerprint-derivation}") keypairs;
}) config.fudo.secrets.files.host-ssh-keypairs); }) config.fudo.secrets.files.ssh.host-keypairs);
}; };
services.openssh.hostKeys = let services.openssh.hostKeys =
host-secrets = config.fudo.secrets.host-secrets.${hostname}; let host-secrets = config.fudo.secrets.host-secrets."${hostname}";
in map (keypair: { in map (keypair: {
path = path = host-secrets."host-${keypair.key-type}-private-key".target-file;
host-secrets."host-${keypair.key-type}-private-key".target-file;
type = keypair.key-type; type = keypair.key-type;
}) host-keypairs; }) host-keypairs;
}); });

View File

@ -3,16 +3,16 @@
with lib; with lib;
let let
hostname = config.instance.hostname; hostname = config.instance.hostname;
domain-name = config.fudo.hosts.${hostname}.domain; domain-name = config.fudo.hosts."${hostname}".domain;
domain = config.fudo.domains.${domain-name}; domain = config.fudo.domains."${domain-name}";
zone-name = config.fudo.domains.${domain-name}.zone; zone-name = config.fudo.domains."${domain-name}".zone;
host-fqdn = hostname: "${hostname}.${config.fudo.hosts.${hostname}.domain}"; host-fqdn = hostname: "${hostname}.${domain-name}";
postgresql-server = domain.postgresql-server; postgresql-server = domain.postgresql-server;
isDatabase = hostname == postgresql-server; isDatabaseServer = hostname == postgresql-server;
isJabber = elem hostname domain.xmpp-servers; isJabberServer = elem hostname domain.xmpp-servers;
isDNSBackplane = hostname == domain.backplane.dns-service; isDNSBackplane = hostname == domain.backplane.dns-service;
backplaneEnabled = domain.backplane != null; backplaneEnabled = domain.backplane != null;
isNameserver = hostname == domain.backplane.nameserver; isNameserver = hostname == domain.backplane.nameserver;
@ -73,18 +73,18 @@ in {
user = config.fudo.backplane.dns.user; user = config.fudo.backplane.dns.user;
}; };
database-powerdns-passwd = mkIf isDatabase { database-powerdns-passwd = mkIf isDatabaseServer {
source-file = powerdns-password; source-file = powerdns-password;
target-file = "/run/postgres/powerdns.passwd"; target-file = "/run/postgres/powerdns.passwd";
user = config.services.postgresql.superUser; user = config.services.postgresql.superUser;
}; };
database-backplane-passwd = mkIf isDatabase { database-backplane-passwd = mkIf isDatabaseServer {
source-file = backplane-database-password; source-file = backplane-database-password;
target-file = "/run/postgres/backplane-database.passwd"; target-file = "/run/postgres/backplane-database.passwd";
user = config.services.postgresql.superUser; user = config.services.postgresql.superUser;
}; };
ejabberd-backplane-passwd = mkIf isJabber { ejabberd-backplane-passwd = mkIf isJabberServer {
source-file = xmpp-password; source-file = xmpp-password;
target-file = "/run/backplane-jabber/service-dns.passwd"; target-file = "/run/backplane-jabber/service-dns.passwd";
user = config.services.ejabberd.user; user = config.services.ejabberd.user;
@ -106,7 +106,7 @@ in {
aliases = { backplane = "${backplane-host-fqdn}."; }; aliases = { backplane = "${backplane-host-fqdn}."; };
}; };
postgresql = mkIf isDatabase { postgresql = mkIf isDatabaseServer {
required-services = [ "fudo-passwords.target" ]; required-services = [ "fudo-passwords.target" ];
users = { users = {
@ -136,7 +136,7 @@ in {
}; };
backplane = { backplane = {
enable = isJabber; enable = isJabberServer;
client-hosts = mapAttrs (hostname: hostOpts: { client-hosts = mapAttrs (hostname: hostOpts: {
password-file = host-password-files.${hostname}; password-file = host-password-files.${hostname};

View File

@ -1,4 +1,4 @@
{ config, lib, pkgs, ... } @ toplevel: { config, lib, pkgs, ... }@toplevel:
with lib; with lib;
let let
@ -6,6 +6,18 @@ let
cfg = config.fudo.services.dns; cfg = config.fudo.services.dns;
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
domain-name = config.instance.local-domain;
domain = config.fudo.domains.${domain-name};
primary-nameserver = domain.primary-nameserver;
primary-nameserver-ip = pkgs.lib.network.host-ipv4 config primary-nameserver;
primary-nameserver-fqdn = "${primary-nameserver}.${domain-name}";
is-primary-nameserver = primary-nameserver == hostname;
zoneKeySecret = zone: "${zone}-ksk";
nameserverOpts = { name, ... }: { nameserverOpts = { name, ... }: {
options = with types; { options = with types; {
hostname = mkOption { hostname = mkOption {
@ -39,8 +51,8 @@ let
}; };
}; };
zoneOpts = { name, ... }: let zoneOpts = { name, ... }:
zone-name = name; let zone-name = name;
in { in {
options = with types; { options = with types; {
enable = mkOption { enable = mkOption {
@ -51,14 +63,15 @@ let
default-host = mkOption { default-host = mkOption {
type = nullOr str; type = nullOr str;
description = "IP which will respond to requests for the base domain."; description =
"IP which will respond to requests for the base domain.";
default = null; default = null;
}; };
external-nameservers = mkOption { external-nameservers = mkOption {
type = listOf (submodule nameserverOpts); type = listOf (submodule nameserverOpts);
description = "Off-network secondary nameservers."; description = "Off-network secondary nameservers.";
default = []; default = [ ];
}; };
domain = mkOption { domain = mkOption {
@ -66,29 +79,56 @@ let
description = "Domain which this zone serves."; description = "Domain which this zone serves.";
default = zone-name; default = zone-name;
}; };
};
};
pthru = obj: ksk = mkOption {
builtins.trace "TRACE: ${ obj }" obj; type = nullOr (submodule {
options = {
private-key = mkOption {
type = path;
description = "KSK private key.";
};
public-key = mkOption {
type = path;
description = "KSK public key.";
};
ds = mkOption {
type = path;
description = "KSK ds record.";
};
};
});
description =
"Location of the zone-signing private & public keys and DS record.";
default =
toplevel.config.fudo.secrets.files.dns.key-signing-keys."${zone-name}";
};
};
};
in { in {
options.fudo.services.dns = with types; { options.fudo.services.dns = with types; {
zones = mkOption { zones = mkOption {
type = attrsOf (submodule zoneOpts); type = attrsOf (submodule zoneOpts);
description = "Map of served zone to extra zone details."; description = "Map of served zone to extra zone details.";
default = {}; default = { };
}; };
}; };
config.fudo = { config.fudo = {
zones = mapAttrs (zone-name: zone-cfg: let secrets.host-secrets."${hostname}" = mkIf is-primary-nameserver (mapAttrs'
(zone: zone-cfg:
nameValuePair (zoneKeySecret zone) {
source-file = zone-cfg.ksk.private-key;
target-file = "/run/nsd/${baseNameOf zone-cfg.ksk.private-key}";
user = config.fudo.nsd.user;
}) cfg.zones);
zones = mapAttrs (zone-name: zone-cfg:
let
domain-name = zone-cfg.domain; domain-name = zone-cfg.domain;
domain = config.fudo.domains.${domain-name}; domain = config.fudo.domains.${domain-name};
make-srv-record = port: host: { make-srv-record = port: host: { inherit port host; };
inherit port host;
};
served-domain = domain.primary-nameserver != null; served-domain = domain.primary-nameserver != null;
@ -96,8 +136,8 @@ in {
is-primary-nameserver = hostname == primary-nameserver; is-primary-nameserver = hostname == primary-nameserver;
internal-nameserver-hostnames = internal-nameserver-hostnames = [ domain.primary-nameserver ]
[domain.primary-nameserver] ++ domain.secondary-nameservers; ++ domain.secondary-nameservers;
get-host-deets = description: hostname: { get-host-deets = description: hostname: {
ipv4-address = pkgs.lib.network.host-ipv4 config hostname; ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
@ -105,7 +145,8 @@ in {
description = description; description = description;
}; };
get-ns-deets = hostname: let get-ns-deets = hostname:
let
host-domain = config.fudo.hosts.${hostname}.domain; host-domain = config.fudo.hosts.${hostname}.domain;
desc = "${domain-name} nameserver ${hostname}.${host-domain}."; desc = "${domain-name} nameserver ${hostname}.${host-domain}.";
in get-host-deets desc hostname; in get-host-deets desc hostname;
@ -115,13 +156,11 @@ in {
in internal-nameservers ++ zone-cfg.external-nameservers; in internal-nameservers ++ zone-cfg.external-nameservers;
has-auth-hostname = ns-host: ns-opts: has-auth-hostname = ns-host: ns-opts:
(hasAttr "authoritative-hostname" ns-opts) && (hasAttr "authoritative-hostname" ns-opts)
(ns-opts.authoritative-hostname != null); && (ns-opts.authoritative-hostname != null);
all-nameservers = listToAttrs all-nameservers = listToAttrs
(imap1 (imap1 (i: nsOpts: nameValuePair "ns${toString i}" nsOpts)
(i: nsOpts:
nameValuePair "ns${toString i}" nsOpts)
nameserver-deets); nameserver-deets);
nameserver-aliases = nameserver-aliases =
@ -130,53 +169,55 @@ in {
nameserver-hosts = mapAttrs (hostname: opts: { nameserver-hosts = mapAttrs (hostname: opts: {
inherit (opts) ipv4-address ipv6-address description; inherit (opts) ipv4-address ipv6-address description;
}) (filterAttrs (hostname: opts: ! has-auth-hostname hostname opts) }) (filterAttrs (hostname: opts: !has-auth-hostname hostname opts)
all-nameservers); all-nameservers);
dns-srv-records = let dns-srv-records = let
nameserver-srv-records = mapAttrsToList nameserver-srv-records = mapAttrsToList (hostname: hostOpts:
(hostname: hostOpts: let let
target-host = if (has-auth-hostname hostname hostOpts) then target-host = if (has-auth-hostname hostname hostOpts) then
"${hostOpts.authoritative-hostname}" else "${hostOpts.authoritative-hostname}"
else
"${hostname}.${domain-name}"; "${hostname}.${domain-name}";
in make-srv-record 53 target-host) in make-srv-record 53 target-host) all-nameservers;
all-nameservers;
in { in {
tcp.domain = nameserver-srv-records; tcp.domain = nameserver-srv-records;
udp.domain = nameserver-srv-records; udp.domain = nameserver-srv-records;
}; };
# TODO: move this to a mail service # # TODO: move this to a mail service
mail-srv-records = optionalAttrs (domain.primary-mailserver != null) { # mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
tcp = let # tcp = let
mailserver-domain = config.fudo.hosts.${domain.primary-mailserver}.domain; # mailserver-domain =
fqdn = "mail.${mailserver-domain}"; # config.fudo.hosts.${domain.primary-mailserver}.domain;
in { # fqdn = "mail.${mailserver-domain}";
smtp = [(make-srv-record 25 fqdn)]; # in {
submission = [(make-srv-record 587 fqdn)]; # smtp = [ (make-srv-record 25 fqdn) ];
imap = [(make-srv-record 143 fqdn)]; # submission = [ (make-srv-record 587 fqdn) ];
imaps = [(make-srv-record 993 fqdn)]; # imap = [ (make-srv-record 143 fqdn) ];
pop3 = [(make-srv-record 110 fqdn)]; # imaps = [ (make-srv-record 993 fqdn) ];
pop3s = [(make-srv-record 995 fqdn)]; # pop3 = [ (make-srv-record 110 fqdn) ];
}; # pop3s = [ (make-srv-record 995 fqdn) ];
}; # };
# };
in { in {
gssapi-realm = domain.gssapi-realm; gssapi-realm = domain.gssapi-realm;
hosts = nameserver-hosts // { hosts = nameserver-hosts // {
mail = mkIf (domain.primary-nameserver != null) (let mail = mkIf (domain.primary-nameserver != null) (let
mailserver-deets = host: let mailserver-deets = host:
host-domain = config.fudo.hosts.${host}.domain; let host-domain = config.fudo.hosts.${host}.domain;
in get-host-deets "Primary ${domain-name} mailserver ${host}.${host-domain}." host; in get-host-deets
"Primary ${domain-name} mailserver ${host}.${host-domain}." host;
in mailserver-deets domain.primary-nameserver); in mailserver-deets domain.primary-nameserver);
}; };
aliases = nameserver-aliases; aliases = nameserver-aliases;
mx = optional (domain.primary-mailserver != null) mx = optional (domain.primary-mailserver != null) (let
(let mail-domain-name =
mail-domain-name = config.fudo.hosts.${domain.primary-mailserver}.domain; config.fudo.hosts.${domain.primary-mailserver}.domain;
in "mail.${mail-domain-name}"); in "mail.${mail-domain-name}");
dmarc-report-address = "dmarc-report@${domain-name}"; dmarc-report-address = "dmarc-report@${domain-name}";
@ -187,18 +228,15 @@ in {
(attrNames nameserver-hosts); (attrNames nameserver-hosts);
in internal ++ direct-external; in internal ++ direct-external;
srv-records = dns-srv-records // mail-srv-records; srv-records = dns-srv-records; # // mail-srv-records;
verbatim-dns-records = mkIf (zone-cfg.ksk != null) [
(readFile zone-cfg.ksk.public-key)
(readFile zone-cfg.ksk.ds)
];
}) cfg.zones; }) cfg.zones;
dns = let dns = {
domain-name = config.instance.local-domain;
domain = config.fudo.domains.${domain-name};
primary-nameserver = domain.primary-nameserver;
primary-nameserver-ip = pkgs.lib.network.host-ipv4 config primary-nameserver;
primary-nameserver-fqdn = "${primary-nameserver}.${domain-name}";
is-primary-nameserver = primary-nameserver == hostname;
in {
enable = is-primary-nameserver; enable = is-primary-nameserver;
identity = "${hostname}.${domain-name}"; identity = "${hostname}.${domain-name}";
@ -207,9 +245,9 @@ in {
(pkgs.lib.network.host-ips config hostname); (pkgs.lib.network.host-ips config hostname);
domains = mapAttrs' (zone-name: zone-cfg: domains = mapAttrs' (zone-name: zone-cfg:
nameValuePair zone-cfg.domain nameValuePair zone-cfg.domain {
{ dnssec = zone-cfg.ksk != null;
dnssec = true; ksk.key-file = host-secrets."${zoneKeySecret zone-name}".target-file;
zone-definition = config.fudo.zones.${zone-name}; zone-definition = config.fudo.zones.${zone-name};
}) cfg.zones; }) cfg.zones;
}; };

View File

@ -1,11 +1,13 @@
{ config, lib, pkgs, ... }: { config, pkgs, ... }:
with lib; with pkgs.lib;
let let
hostname = config.instance.hostname; hostname = config.instance.hostname;
domain-name = config.fudo.services.auth.domain; domain-name = config.fudo.services.auth.domain;
domain = config.fudo.domains.${domain-name}; domain = config.fudo.domains.${domain-name};
realm = domain.gssapi-realm;
zone-name = domain.zone; zone-name = domain.zone;
ldap-server = elem hostname domain.ldap-servers; ldap-server = elem hostname domain.ldap-servers;
@ -19,6 +21,11 @@ let
cfg = config.fudo.services.auth; cfg = config.fudo.services.auth;
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
krb-user = config.fudo.auth.kerberos.user;
krb-group = config.fudo.auth.kerberos.group;
in { in {
options.fudo.services.auth = with types; { options.fudo.services.auth = with types; {
domain = mkOption { domain = mkOption {
@ -30,20 +37,23 @@ in {
ldap = { ldap = {
hostname = mkOption { hostname = mkOption {
type = str; type = str;
description = "Fully-qualified (and public-addressable) domain name of this host."; description =
"Fully-qualified (and public-addressable) domain name of this host.";
default = config.instance.host-fqdn; default = config.instance.host-fqdn;
}; };
state-directory = mkOption { state-directory = mkOption {
type = str; type = str;
description = "Directory at which to store peristent ldap-related data."; description =
"Directory at which to store peristent ldap-related data.";
}; };
}; };
kerberos = { kerberos = {
hostname = mkOption { hostname = mkOption {
type = str; type = str;
description = "Fully-qualified (and public-addressable) domain name of this host."; description =
"Fully-qualified (and public-addressable) domain name of this host.";
default = config.instance.host-fqdn; default = config.instance.host-fqdn;
}; };
@ -56,15 +66,64 @@ in {
type = str; type = str;
description = "Path (on the build server) to the KDC master key file."; description = "Path (on the build server) to the KDC master key file.";
}; };
ipropd-keytab = mkOption {
type = nullOr str;
description = "ipropd keytab for kerberos database propagation.";
};
}; };
}; };
config = { config = {
systemd = {
tmpfiles.rules = mkIf (kerberos-master || kerberos-slave) [
"d ${cfg.kerberos.state-directory} 0700 ${krb-user} ${krb-group} - -"
];
paths.heimdal-kdc-initialize = mkIf kerberos-master {
wantedBy = [ "heimdal-kdc.service" ];
pathConfig = {
PathModified = host-secrets.kdc-principals.target-file;
};
};
services = {
heimdal-kdc-initialize = mkIf (kerberos-master || kerberos-slave) {
requires = [
host-secrets.kdc-principals.service
host-secrets.realm-master-key.service
];
description = "Initialize and update the Heimdal KDC database.";
path = with pkgs; [ kdcMergePrincipals coreutils ];
serviceConfig = {
User = krb-user;
Group = krb-group;
ExecStart = let
db = config.fudo.auth.kerberos.kdc.database;
principals = host-secrets.kdc-principals.target-file;
master-key = host-secrets.realm-master-key.target-file;
init-db-cmd = concatStringsSep " " [
"${pkgs.kdcMergePrincipals}/bin/kdc-merge-principals"
"--create"
"--database=${db}"
"--principals=${principals}"
"--key=${master-key}"
"--realm=${realm}"
"--verbose"
];
in pkgs.writeShellScript "heimdal-kdc-initialize.sh" ''
${init-db-cmd}
chown ${krb-user}:${krb-group} ${db}
chmod 0700 ${db}
'';
};
};
heimdal-kdc = mkIf kerberos-master {
requires = [ "heimdal-kdc-initialize.service" ];
after = [ "heimdal-kdc-initialize.service" ];
};
heimdal-kdc-secondary = mkIf kerberos-slave {
requires = [ "heimdal-kdc-initialize.service" ];
after = [ "heimdal-kdc-initialize.service" ];
};
};
};
fudo = { fudo = {
acme.host-domains.${hostname} = mkIf (ldap-server) { acme.host-domains.${hostname} = mkIf (ldap-server) {
${cfg.ldap.hostname}.local-copies.openldap = { ${cfg.ldap.hostname}.local-copies.openldap = {
@ -73,9 +132,66 @@ in {
}; };
}; };
secrets.host-secrets."${hostname}" = let
realm-key =
config.fudo.secrets.files.kerberos.realm-master-keys."${realm}";
in {
realm-master-key = mkIf (kerberos-master || kerberos-slave) {
source-file = realm-key;
target-file = "/run/kdc/realm.key";
user = krb-user;
group = krb-group;
};
kdc-principals = mkIf (kerberos-master || kerberos-slave) {
source-file =
config.fudo.secrets.files.kerberos.realm-principals."${realm}";
target-file = "/run/kdc/realm.principals";
user = krb-user;
group = krb-group;
};
kadmind-keytab = mkIf kerberos-master {
source-file = extractFudoKeytab {
inherit realm;
principals = [ "kadmin/admin" ];
};
target-file = "/run/kdc/kadmind.keytab";
user = krb-user;
group = krb-group;
};
kpasswdd-keytab = mkIf kerberos-master {
source-file = extractFudoKeytab {
inherit realm;
principals = [ "kadmin/changepw" ];
};
target-file = "/run/kdc/kpasswdd.keytab";
user = krb-user;
group = krb-group;
};
hprop-keytab =
mkIf (kerberos-master && (domain.kerberos-slaves != [ ])) {
source-file = extractFudoKeytab {
inherit realm;
principals = [ "kadmin/hprop" ];
};
target-file = "/run/kdc/hprop.keytab";
user = krb-user;
group = krb-group;
};
hpropd-keytab = mkIf kerberos-slave {
source-file = extractFudoHostKeytab {
inherit hostname realm;
services = [ "hprop" ];
};
target-file = "/run/kdc/hpropd.keytab";
user = krb-user;
group = krb-group;
};
};
auth = { auth = {
ldap-server = mkIf (ldap-server) ldap-server = mkIf ldap-server (let
(let
ldap-cert-copy = ldap-cert-copy =
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap; config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
in { in {
@ -98,27 +214,28 @@ in {
ssl-ca-certificate = "${pkgs.letsencrypt-ca}"; ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
}); });
kerberos = {
inherit realm;
kdc = mkIf (kerberos-master || kerberos-slave) { kdc = mkIf (kerberos-master || kerberos-slave) {
enable = true;
realm = domain.gssapi-realm;
bind-addresses =
(pkgs.lib.network.host-ips config hostname) ++
[ "127.0.0.1" ] ++ (optional config.networking.enableIPv6 "::1");
state-directory = cfg.kerberos.state-directory; state-directory = cfg.kerberos.state-directory;
master-key-file = cfg.kerberos.master-key-file; master-key-file = host-secrets.realm-master-key.target-file;
master-config = mkIf (kerberos-master) { primary = mkIf kerberos-master {
enable = true;
acl = let acl = let
admin-entries = genAttrs config.instance.local-admins adminEntries = genAttrs config.instance.local-admins
(admin: { (admin: { perms = [ "add" "change-password" "list" ]; });
perms = [ "add" "change-password" "list" ]; in adminEntries // { "*/root".perms = [ "all" ]; };
}); secondary-servers = map getHostFqdn domain.kerberos-slaves;
in admin-entries // { keytabs = {
"*/root".perms = [ "all" ]; kadmind = host-secrets.kadmind-keytab.target-file;
kpasswdd = host-secrets.kpasswdd-keytab.target-file;
hprop = host-secrets.hprop-keytab.target-file;
}; };
}; };
slave-config = mkIf (kerberos-slave) { secondary = mkIf kerberos-slave {
master-host = domain.kerberos-master; enable = true;
ipropd-keytab = cfg.kerberos.ipropd-keytab; keytabs.hpropd = host-secrets.hpropd-keytab.target-file;
};
}; };
}; };
}; };
@ -129,19 +246,20 @@ in {
host = hostname; host = hostname;
}; };
get-fqdn = host: get-fqdn = host: "${host}.${config.fudo.hosts.${host}.domain}";
"${host}.${config.fudo.hosts.${host}.domain}";
kerberos-master-hosts = optional (kerberized-domain) kerberos-master-hosts =
domain.kerberos-master; optional (kerberized-domain) domain.kerberos-master;
kerberos-servers = map get-fqdn kerberos-servers =
(kerberos-master-hosts ++ domain.kerberos-slaves); map get-fqdn (kerberos-master-hosts ++ domain.kerberos-slaves);
kerberos-masters = map get-fqdn kerberos-master-hosts; kerberos-masters = map get-fqdn kerberos-master-hosts;
ldap-servers = map get-fqdn domain.ldap-servers; ldap-servers = map get-fqdn domain.ldap-servers;
in { in {
gssapi-realm = realm;
srv-records = { srv-records = {
tcp = { tcp = {
kerberos = map (make-srv-record 88) kerberos-servers; kerberos = map (make-srv-record 88) kerberos-servers;

View File

@ -12,7 +12,7 @@ let
mailserver-domain-name = config.fudo.hosts.${mailserver-host}.domain; mailserver-domain-name = config.fudo.hosts.${mailserver-host}.domain;
mailserver-domain = config.fudo.domains.${mailserver-domain-name}; mailserver-domain = config.fudo.domains.${mailserver-domain-name};
mailserver-host-fqdn = "${mailserver-host}.${mailserver-domain-name}"; mailserver-fqdn = "${mailserver-host}.${mailserver-domain-name}";
isMailServer = hostname == mailserver-host; isMailServer = hostname == mailserver-host;
@ -94,15 +94,12 @@ in {
}; };
}; };
zones = mkIf isLocalMailserver { zones = {
${mailserver-domain.zone} = let ${mailserver-domain.zone} = let
server-ipv4 = pkgs.lib.network.host-ipv4 config mailserver-host; server-ipv4 = pkgs.lib.network.host-ipv4 config mailserver-host;
server-ipv6 = pkgs.lib.network.host-ipv6 config mailserver-host; server-ipv6 = pkgs.lib.network.host-ipv6 config mailserver-host;
srv-record = host: port: [{ srv-record = host: port: [{ inherit host port; }];
host = "${host}.${mailserver-domain-name}";
port = port;
}];
in { in {
hosts = genAttrs [ "imap" "smtp" ] (alias: { hosts = genAttrs [ "imap" "smtp" ] (alias: {
@ -114,18 +111,17 @@ in {
mx = [ "smtp.${mailserver-domain-name}" ]; mx = [ "smtp.${mailserver-domain-name}" ];
aliases = aliases = mkIf metricsEnabled { mail-stats = "${mailserver-fqdn}."; };
mkIf metricsEnabled { mail-stats = "${mailserver-host-fqdn}."; };
srv-records.tcp = { srv-records.tcp = {
pop3 = srv-record "imap" 110; pop3 = srv-record mailserver-fqdn 110;
pop3s = srv-record "imap" 995; pop3s = srv-record mailserver-fqdn 995;
imap = srv-record "imap" 143; imap = srv-record mailserver-fqdn 143;
imaps = srv-record "imap" 993; imaps = srv-record mailserver-fqdn 993;
smtp = srv-record "smtp" 25; smtp = srv-record mailserver-fqdn 25;
submission = srv-record "smtp" 587; submission = srv-record mailserver-fqdn 587;
}; };
metric-records = mkIf metricsEnabled metric-records = mkIf metricsEnabled
@ -167,8 +163,7 @@ in {
ssl-private-key = cert-copy.private-key; ssl-private-key = cert-copy.private-key;
}; };
local-domains = local-domains = [ mailserver-fqdn "smtp.${mailserver-domain-name}" ];
[ mailserver-host-fqdn "smtp.${mailserver-domain-name}" ];
mail-directory = "${cfg.state-directory}/mail"; mail-directory = "${cfg.state-directory}/mail";
state-directory = "${cfg.state-directory}/state"; state-directory = "${cfg.state-directory}/state";

164
config/service/mqtt.nix Normal file
View File

@ -0,0 +1,164 @@
{ config, lib, pkgs, ... }@toplevel:
with lib;
let
cfg = config.fudo.services.mqtt;
hostname = config.instance.hostname;
isMqttServer = cfg.host == hostname;
aclOption = with types;
mkOption {
type = listOf str;
description = "Topic filter to which this user has access.";
example = [ "some/topic/#" "other/specific/topic" ];
};
userOpts = { name, ... }: {
options = with types; {
username = mkOption {
type = str;
default = name;
};
password-file = mkOption {
type = str;
description =
"Path to file (on the BUILD HOST) containing the user's password.";
};
acl = aclOption;
};
};
mosquittoUser = config.systemd.services.mosquitto.serviceConfig.User;
pwTarget = type: username: "/run/mqtt/${type}-${username}.passwd";
mqttDomain = config.fudo.hosts."${cfg.host}".domain;
in {
options.fudo.services.mqtt = with types; {
enable = mkEnableOption "Enable MQTT server.";
host = mkOption {
type = str;
description =
"Hostname of the MQTT server for this site/domain/whatever.";
};
listen-address = mkOption {
type = str;
description = "IP address on which to listen.";
default = "0.0.0.0";
};
private = {
enable = mkOption {
type = bool;
description = "Enable a private (authenticated) MQTT server.";
default = true;
};
port = mkOption {
type = port;
description = "Port at which to listen for incoming MQTT requests.";
default = 1883;
};
users = mkOption {
type = attrsOf (submodule userOpts);
default = { };
};
};
public = {
enable = mkEnableOption "Enable a public (anonymous) MQTT server.";
port = mkOption {
type = port;
description = "Port at which to listen for incoming MQTT requests.";
default = 1884;
};
users = mkOption {
type = attrsOf (submodule userOpts);
default = { };
};
acl = aclOption;
};
state-directory = mkOption {
type = str;
description = "Directory where server can store persistent state.";
};
mqtt-hostname = let
mqtt-host = toplevel.config.fudo.services.mqtt.host;
mqtt-domain = toplevel.config.fudo.hosts."${mqtt-host}".domain;
in mkOption {
type = str;
description = "Hostname at which the MQTT server can be reached.";
default = "mqtt.${mqtt-domain}";
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts =
(optional cfg.private.enable cfg.private.port)
++ (optional cfg.public.enable cfg.public.port);
systemd = {
services.mosquitto = {
after = [ config.fudo.secrets.secret-target ];
restartIfChanged = true;
};
tmpfiles.rules = optional isMqttServer
"d ${cfg.state-directory} 0700 ${mosquittoUser} - - -";
};
fudo = {
zones."${mqttDomain}".aliases.mqtt = cfg.host;
secrets.host-secrets."${hostname}" = mkIf isMqttServer (let
publicUsers = mapAttrs' (_: userOpts:
nameValuePair "mqtt-public-user-${userOpts.username}" {
source-file = userOpts.password-file;
target-file = pwTarget "public" userOpts.username;
user = mosquittoUser;
}) cfg.public.users;
privateUsers = mapAttrs' (_: userOpts:
nameValuePair "mqtt-private-user-${userOpts.username}" {
source-file = userOpts.password-file;
target-file = pwTarget "private" userOpts.username;
user = mosquittoUser;
}) cfg.private.users;
in publicUsers // privateUsers);
};
services.mosquitto = mkIf isMqttServer {
enable = true;
dataDir = cfg.state-directory;
listeners = (optional cfg.private.enable {
settings.allow_anonymous = false;
port = cfg.private.port;
address = cfg.listen-address;
users = mapAttrs' (_: userOpts:
nameValuePair userOpts.username {
acl = userOpts.acl;
passwordFile = pwTarget "private" userOpts.username;
}) cfg.private.users;
}) ++ (optional cfg.public.enable {
settings.allow_anonymous = true;
acl = map (line: "topic ${line}") cfg.public.acl;
port = cfg.public.port;
address = cfg.listen-address;
users = mapAttrs' (_: userOpts:
nameValuePair userOpts.username {
acl = userOpts.acl;
passwordFile = pwTarget "public" userOpts.username;
}) cfg.public.users;
});
};
};
}

260
config/service/nexus.nix Normal file
View File

@ -0,0 +1,260 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.fudo.services.nexus;
hostname = config.instance.hostname;
domainName = config.fudo.hosts."${hostname}".domain;
domain = config.fudo.domains."${domainName}";
siteName = config.fudo.hosts."${hostname}".site;
site = config.fudo.sites."${siteName}";
hostNexusDomainList = host:
let
domainName = config.fudo.hosts."${host}".domain;
domain = config.fudo.domains."${domainName}";
siteName = config.fudo.hosts."${host}".site;
site = config.fudo.sites."${siteName}";
in unique (domain.nexus.domains ++ site.nexus.domains);
isEmpty = lst: lst == [ ];
localNexusDomains = getAttrs (hostNexusDomainList hostname)
(listKeys config.fudo.nexus.domains);
isServer = let
servers = concatMap (domainOpts: domainOpts.servers)
(attrValues config.fudo.nexus.domains);
in elem hostname servers;
isDnsServer = let
servers = concatMap (domainOpts: domainOpts.dns-servers)
(attrValues config.fudo.nexus.domains);
in elem hostname servers;
isDatabase = hostname == domain.postgresql-server;
enableClient = !isEmpty (hostNexusDomainList hostname);
enable = isServer || isDnsServer || isDatabase || enableClient;
servedDomains = filterAttrs (_: domainOpts:
(elem hostname domainOpts.servers)
|| (elem hostname domainOpts.dns-servers)) config.fudo.nexus.domains;
clientHosts = filter (hostname:
!isEmpty
(intersectLists (hostNexusDomainList hostname) (attrNames servedDomains)))
(attrNames config.fudo.hosts);
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
hostFqdn = hostname: "${hostname}.${domainName}";
databaseName = "nexus_dns";
serverUser = "nexus_server";
dnsServerUser = "nexus_dns";
concatMapAttrsToList = f: as: concatLists (mapAttrsToList f as);
genServerRecords = name: domain: servers:
imap0 (i: host: {
inherit host domain;
alias = "${name}${toString i}";
}) servers;
serverList = concatMapAttrsToList
(domain: domainOpts: genServerRecords "nexus-" domain domainOpts.servers)
config.fudo.nexus.domains;
dnsServerList = concatMapAttrsToList
(domain: domainOpts: genServerRecords "ns" domain domainOpts.dns-servers)
config.fudo.nexus.domains;
genSshfp = path:
pkgs.stdenv.mkDerivation {
name = "sshfp-${baseNameOf path}";
buildInputs = with pkgs; [ openssh ];
phases = [ "installPhase" ];
installPhase =
"ssh-keygen -r PLACEHOLDER -f ${path} | sed 's/PLACEHOLDER IN SSHFP //' > $out";
};
in {
options.fudo.services.nexus.dns-server = with types; {
listen-addresses = mkOption {
type = nullOr (listOf str);
description =
"Listen addresses. Defaults to 0.0.0.0 (i.e. all addresses).";
default = null;
};
};
config = mkIf enable {
nexus = {
database = {
database = databaseName;
host = pkgs.lib.getDomainPostgresqlServer domainName;
};
domains = mapAttrs (domain: domainOpts: {
admin = "admin@${domain}";
inherit (domainOpts) gssapi-realm;
trusted-networks = domainOpts.trusted-networks
++ config.instance.local-networks;
# aliases = let
# mkAlias = { host, alias, ... }:
# nameValuePair alias (pkgs.lib.getHostFqdn host);
# domainRecords = filter (record: record.domain == domain) serverList;
# in listToAttrs (map mkAlias domainRecords);
nameservers = let
domainNs = filter (record: record.domain == domain) dnsServerList;
mkNsRecord = { alias, host, ... }:
nameValuePair alias {
ipv4-address = pkgs.lib.getHostIpv4 host;
ipv6-address = pkgs.lib.getHostIpv6 host;
};
in listToAttrs (map mkNsRecord domainNs);
records = let
domainServers = filter (record: record.domain == domain) serverList;
mkHostRecords = { host, alias, ... }:
let
ipv4-address = pkgs.lib.getHostIpv4 host;
ipv6-address = pkgs.lib.getHostIpv6 host;
in (optional (ipv4-address != null) {
name = "${alias}.${domain}";
type = "A";
content = ipv4-address;
}) ++ (optional (ipv6-address != null) {
name = "${alias}.${domain}";
type = "AAAA";
content = ipv6-address;
});
in domainOpts.records ++ (concatMap mkHostRecords domainServers);
}) servedDomains;
client = {
enable = enableClient;
inherit hostname;
verbose = true;
domains = unique (domain.nexus.domains ++ site.nexus.domains);
hmac-key-file = hostSecrets.nexus-key.target-file;
servers = let localDomains = hostNexusDomainList hostname;
in map ({ domain, alias, ... }: "${alias}.${domain}")
(filter ({ domain, ... }: elem domain localDomains) serverList);
ssh-key-files = map (key: key.path) config.services.openssh.hostKeys;
};
server = {
enable = isServer;
verbose = true;
client-keys-file = hostSecrets.nexus-client-keys.target-file;
hostnames = let
hostServerRecords =
filter ({ host, ... }: host == hostname) serverList;
in map ({ domain, alias, ... }: "${alias}.${domain}") hostServerRecords;
database = {
user = serverUser;
password-file = hostSecrets.nexus-server-passwd.target-file;
};
};
dns-server = {
enable = isDnsServer;
enable-dnssec = true;
listen-addresses = mkIf (cfg.dns-server.listen-addresses != null)
cfg.dns-server.listen-addresses;
database = {
user = dnsServerUser;
password-file = hostSecrets.nexus-dns-server-passwd.target-file;
};
};
};
fudo = {
secrets.host-secrets."${hostname}" = {
nexus-client-keys = mkIf isServer {
source-file = let
clientKeyFiles =
filterAttrs (hostname: _: elem hostname clientHosts)
config.fudo.secrets.files.nexus-hmacs;
clientKeys =
mapAttrs (_: filename: readFile filename) clientKeyFiles;
in pkgs.writeText "nexus-client-keys.json"
(builtins.toJSON clientKeys);
target-file = "/run/nexus/client-keys.json";
};
nexus-key = mkIf enableClient {
source-file = config.fudo.secrets.files.nexus-hmacs."${hostname}";
target-file = "/run/nexus/client.key";
};
nexus-server-passwd = mkIf isServer {
source-file =
pkgs.lib.passwd.stablerandom-passwd-file "nexus-server-passwd"
"nexus-server-${config.instance.build-seed}";
target-file = "/run/nexus/server-db.passwd";
};
postgres-nexus-server-passwd = mkIf isDatabase {
source-file =
pkgs.lib.passwd.stablerandom-passwd-file "nexus-server-passwd"
"nexus-server-${config.instance.build-seed}";
target-file = "/run/nexus/server-db.passwd";
user = "postgres";
};
nexus-dns-server-passwd = mkIf isDnsServer {
source-file =
pkgs.lib.passwd.stablerandom-passwd-file "nexus-dns-server-passwd"
"nexus-dns-server-${config.instance.build-seed}";
target-file = "/run/nexus/dns-server-db.passwd";
};
postgres-nexus-dns-server-passwd = mkIf isDatabase {
source-file =
pkgs.lib.passwd.stablerandom-passwd-file "nexus-dns-server-passwd"
"nexus-dns-server-${config.instance.build-seed}";
target-file = "/run/nexus-db/nexus-dns.passwd";
user = "postgres";
};
};
postgresql = mkIf isDatabase {
required-services = [ "fudo-passwords.target" ];
databases."${databaseName}".users = config.instance.local-admins;
users = {
"${serverUser}" = {
password-file =
hostSecrets.postgres-nexus-server-passwd.target-file;
databases."${databaseName}" = {
access = "CONNECT";
entity-access = {
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
};
};
};
"${dnsServerUser}" = {
password-file =
hostSecrets.postgres-nexus-dns-server-passwd.target-file;
databases."${databaseName}" = {
access = "CONNECT";
entity-access = {
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
};
};
};
};
};
};
};
}

View File

@ -13,8 +13,7 @@ let
host-secrets = config.fudo.secrets.host-secrets.${hostname}; host-secrets = config.fudo.secrets.host-secrets.${hostname};
postgresEnabled = domain.postgresql-server == hostname; postgresEnabled = domain.postgresql-server == hostname;
publicNetwork = let publicNetwork = let site-name = config.fudo.hosts.${hostname}.site;
site-name = config.fudo.hosts.${hostname}.site;
in config.fudo.sites.${site-name}.local-gateway == null; in config.fudo.sites.${site-name}.local-gateway == null;
isPostgresHost = hostname == domain.postgresql-server; isPostgresHost = hostname == domain.postgresql-server;
@ -32,7 +31,7 @@ in {
}; };
keytab = mkOption { keytab = mkOption {
type = str; type = nullOr path;
description = "Keytab for PostgreSQL."; description = "Keytab for PostgreSQL.";
}; };
}; };
@ -49,7 +48,8 @@ in {
}; };
}; };
secrets.host-secrets.${hostname}.postgres-keytab = mkIf (cfg.keytab != null) { secrets.host-secrets.${hostname}.postgres-keytab =
mkIf (cfg.keytab != null) {
source-file = cfg.keytab; source-file = cfg.keytab;
target-file = "/run/postgresql/postgres.keytab"; target-file = "/run/postgresql/postgres.keytab";
user = postgresUser; user = postgresUser;
@ -60,7 +60,8 @@ in {
postgresql = mkIf isPostgresHost (let postgresql = mkIf isPostgresHost (let
ssl-config = optionalAttrs publicNetwork (let ssl-config = optionalAttrs publicNetwork (let
cert-copy = acme-copies.${postgresql-hostname}.local-copies.postgresql; cert-copy =
acme-copies.${postgresql-hostname}.local-copies.postgresql;
in { in {
ssl-certificate = mkIf publicNetwork cert-copy.full-certificate; ssl-certificate = mkIf publicNetwork cert-copy.full-certificate;
ssl-private-key = mkIf publicNetwork cert-copy.private-key; ssl-private-key = mkIf publicNetwork cert-copy.private-key;
@ -68,7 +69,8 @@ in {
}); });
in { in {
enable = true; enable = true;
keytab = mkIf (cfg.keytab != null) host-secrets.postgres-keytab.target-file; keytab = mkIf (cfg.keytab != null)
"${host-secrets.postgres-keytab.target-file}";
local-networks = config.instance.local-networks; local-networks = config.instance.local-networks;
state-directory = cfg.state-directory; state-directory = cfg.state-directory;
required-services = [ config.fudo.secrets.secret-target ]; required-services = [ config.fudo.secrets.secret-target ];

156
config/service/suanni.nix Normal file
View File

@ -0,0 +1,156 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.fudo.services.suanni;
hostname = config.instance.hostname;
isListener = hostname == cfg.event-listener.host;
isObjectifier = hostname == cfg.objectifier.host;
domain-name = config.fudo.hosts."${hostname}".domain;
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
suanni-mqtt-passwd = pkgs.lib.passwd.stablerandom-passwd-file "suanni-mqtt"
config.instance.build-seed;
in {
options.fudo.services.suanni = with types; {
enable = mkEnableOption "Enable Suan Ni Home Guardian.";
mqtt-topic = mkOption {
type = str;
description = "MQTT topic on which to publish events.";
default = "suanni/events/motion";
};
event-listener = {
host = mkOption {
type = str;
description = "Hostname of Event Listener server.";
};
port = mkOption {
type = port;
default = 5354;
};
};
objectifier = {
host = mkOption {
type = str;
description = "Hostname of objectifier server.";
};
port = mkOption {
type = port;
default = 5121;
};
};
synology = {
host = mkOption {
type = str;
description = "Hostname of the Synology server.";
};
port = mkOption {
type = port;
description = "Port on which to contact the Synology server.";
};
username = mkOption {
type = str;
description = "Username as which to connect to the Synology server.";
};
password-file = mkOption {
type = str;
description = "Path to file containing Synology user password.";
};
};
};
config = mkIf cfg.enable {
services = mkIf (isObjectifier || isListener) {
nginx = {
enable = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedGzipSettings = true;
virtualHosts = {
"event-listener.${domain-name}" = mkIf isListener {
locations."/".proxyPass =
"http://127.0.0.1:${toString cfg.event-listener.port}";
};
"objectifier.${domain-name}" = mkIf isObjectifier {
locations."/".proxyPass =
"http://127.0.0.1:${toString cfg.objectifier.port}";
};
};
};
objectifier = mkIf isObjectifier {
enable = true;
listen-addresses = [ "127.0.0.1" ];
port = cfg.objectifier.port;
};
suanni.server = mkIf isListener {
enable = true;
verbose = true;
event-listener.hostname = "127.0.0.1";
synology-client = {
inherit (cfg.synology) host port username;
password-file = host-secrets.suanni-synology-password.target-file;
};
objectifier-client = {
host = "objectifier.${domain-name}";
port = 80;
};
mqtt-client = {
inherit (config.fudo.services.mqtt.private) port;
host = config.fudo.services.mqtt.mqtt-hostname;
username = "suanni";
password-file = host-secrets.suanni-mqtt-password.target-file;
topic = cfg.mqtt-topic;
};
};
};
fudo = {
secrets.host-secrets."${hostname}" = {
suanni-synology-password = mkIf isListener {
source-file =
config.fudo.secrets.files.service-passwords."${hostname}".suanni-synology;
target-file = "/run/suanni/synology.passwd";
};
suanni-mqtt-password = mkIf isListener {
source-file = suanni-mqtt-passwd;
target-file = "/run/suanni/mqtt.passwd";
};
};
services.mqtt = {
enable = true;
private = {
enable = true;
users.suanni = {
password-file = suanni-mqtt-passwd;
acl = [ "readwrite #" ];
};
};
};
zones."${domain-name}" = {
aliases = {
objectifier = cfg.objectifier.host;
event-listener = "${cfg.event-listener.host}";
};
};
};
};
}

104
config/service/tattler.nix Normal file
View File

@ -0,0 +1,104 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.fudo.services.tattler;
hostname = config.instance.hostname;
isSnooper = config.instance.hostname == cfg.snooper-host;
domain-name = config.fudo.host."${hostname}".domain;
snooper-mqtt-passwd = pkgs.lib.passwd.stablerandom-passwd-file "snooper-mqtt"
config.instance.build-seed;
in {
options.fudo.services.tattler = with types; {
enable = mkEnableOption "Enable Snooper & Tattler notification system.";
verbose = mkEnableOption "Enable verbose output and logging.";
enable-notifications =
mkEnableOption "Enable tattler notifications on the local host.";
event-topics = mkOption {
type = listOf str;
description = "List of MQTT topics on which to listen for motion events.";
};
notification-topic = mkOption {
type = str;
description = "MQTT topic on which to publish notifications.";
default = "fudo/notifications/objects";
};
snooper-host = mkOption {
type = str;
description = "Host on which to run the snooper service.";
};
};
config = mkIf cfg.enable {
fudo = {
secrets.host-secrets."${hostname}" = {
snooper-passwd = mkIf isSnooper {
source-file = snooper-mqtt-passwd;
target-file = "/run/snooper/mqtt.passwd";
};
};
services.mqtt = mkIf isSnooper {
enable = true;
private = {
enable = true;
users.snooper = {
password-file = snooper-mqtt-passwd;
acl = map (topic: "read ${topic}") cfg.event-topics;
};
};
public = {
enable = true;
acl = [ "read ${cfg.notification-topic}" ];
users.snooper = {
password-file = snooper-mqtt-passwd;
acl = [ "readwrite ${cfg.notification-topic}" ];
};
};
};
};
services = {
snooper = mkIf isSnooper {
enable = true;
verbose = true;
event-topics = cfg.event-topics;
notification-topic = cfg.notification-topic;
mqtt = let
host-secrets =
(trace hostname config.fudo.secrets.host-secrets."${hostname}");
in {
incoming = {
port = config.fudo.services.mqtt.private.port;
host = config.fudo.services.mqtt.mqtt-hostname;
username = "snooper";
password-file = host-secrets.snooper-passwd.target-file;
};
outgoing = {
port = config.fudo.services.mqtt.public.port;
host = config.fudo.services.mqtt.mqtt-hostname;
username = "snooper";
password-file = host-secrets.snooper-passwd.target-file;
};
};
};
tattler = mkIf cfg.enable-notifications {
enable = true;
verbose = true;
notification-topic = cfg.notification-topic;
mqtt = {
inherit (config.fudo.services.mqtt.public) port;
host = config.fudo.services.mqtt.mqtt-hostname;
};
};
};
};
}

View File

@ -22,25 +22,6 @@ let
in { in {
options.fudo.services.wallfly-presence = with types; { options.fudo.services.wallfly-presence = with types; {
enable = mkEnableOption "Enable WallFly presence for the local site."; enable = mkEnableOption "Enable WallFly presence for the local site.";
mqtt = {
broker-host = mkOption {
type = str;
description = "Host to serve as local MQTT broker.";
};
port = mkOption {
type = port;
description = "Port on which to listen for MQTT connections.";
default = 1884;
};
listen-address = mkOption {
type = str;
description = "Address on which to listen for MQTT connections.";
default = "0.0.0.0";
};
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -50,42 +31,30 @@ in {
source-file = userOpts.password-file; source-file = userOpts.password-file;
target-file = "/run/wallfly-${username}/passwd"; target-file = "/run/wallfly-${username}/passwd";
user = username; user = username;
}) local-user-cfg) // (optionalAttrs is-mqtt-broker (mapAttrs' }) local-user-cfg);
(username: userOpts:
nameValuePair "wallfly-server-${username}-passwd" {
source-file = userOpts.password-file;
target-file = "/run/wallfly-mqtt/${username}.passwd";
user = config.systemd.services.mosquitto.serviceConfig.User;
}) user-cfg));
zones."${domain-name}" = {
aliases.mqtt = "${mqtt-broker}.${domain-name}.";
};
wallfly = { wallfly = {
enable = true; enable = true;
mqtt = { mqtt = let
broker-uri = mqtt-hostname = config.fudo.services.mqtt.mqtt-hostname;
"tcp://${mqtt-broker}.${domain-name}:${toString cfg.mqtt.port}"; mqtt-port = config.fudo.services.mqtt.private.port;
in {
broker-uri = "tcp://${mqtt-hostname}:${toString mqtt-port}";
username = "wallfly-$USER"; username = "wallfly-$USER";
password-file = "/run/wallfly-$USER/passwd"; password-file = "/run/wallfly-$USER/passwd";
}; };
}; };
};
services = { services.mqtt = {
mosquitto = mkIf (is-mqtt-broker) { enable = true;
private = {
enable = true; enable = true;
listeners = [{
settings.allow_anonymous = false;
port = cfg.mqtt.port;
address = cfg.mqtt.listen-address;
users = mapAttrs' (username: userOpts: users = mapAttrs' (username: userOpts:
nameValuePair "wallfly-${username}" { nameValuePair "wallfly-${username}" {
passwordFile = "/run/wallfly-mqtt/${username}.passwd"; password-file = userOpts.password-file;
acl = [ "readwrite homeassistant/binary_sensor/#" ]; acl = [ "readwrite homeassistant/binary_sensor/#" ];
}) user-cfg; }) user-cfg;
}]; };
}; };
}; };
}; };

View File

@ -2,7 +2,7 @@
{ {
imports = [ imports = [
./service/backplane.nix # ./service/backplane.nix
./service/chat.nix ./service/chat.nix
./service/chute.nix ./service/chute.nix
./service/dns.nix ./service/dns.nix
@ -12,8 +12,12 @@
./service/logging.nix ./service/logging.nix
./service/mail-server.nix ./service/mail-server.nix
./service/metrics.nix ./service/metrics.nix
./service/mqtt.nix
./service/nexus.nix
./service/postgresql.nix ./service/postgresql.nix
./service/selby-forum.nix ./service/selby-forum.nix
./service/suanni.nix
./service/tattler.nix
./service/wallfly-presence.nix ./service/wallfly-presence.nix
# ./service/wireguard-gateway.nix # ./service/wireguard-gateway.nix
]; ];

View File

@ -3,9 +3,37 @@
with lib; with lib;
let local-domain = "sea.fudo.org"; let local-domain = "sea.fudo.org";
in { in {
fudo.services.wallfly-presence = { fudo.services = {
mqtt = {
enable = true; enable = true;
mqtt.broker-host = "wormhole0"; host = "wormhole0";
};
wallfly-presence.enable = true;
tattler = let snooper-host = "wormhole0";
in {
enable = true;
verbose = true;
event-topics = [ "suanni/events/motion" ];
inherit snooper-host;
};
suanni = let
listener = "nostromo";
objectifier = "lambda";
in {
enable = true;
event-listener.host = listener;
objectifier.host = objectifier;
synology = {
host = "cargo.sea.fudo.org";
port = 5001;
username = "suanni";
password-file =
config.fudo.secrets.files.service-passwords."${listener}".suanni-synology;
};
};
}; };
fileSystems = { fileSystems = {
@ -165,7 +193,6 @@ in {
DefaultDependencies = false; DefaultDependencies = false;
ConditionPathExists = ConditionPathExists =
[ "|!/run/gssproxy.pid" "|!/proc/net/rpc/use-gss-proxy" ]; [ "|!/run/gssproxy.pid" "|!/proc/net/rpc/use-gss-proxy" ];
Restart = "always";
}; };
serviceConfig = { serviceConfig = {
Type = "forking"; Type = "forking";

View File

@ -207,7 +207,7 @@
uid = 10065; uid = 10065;
primary-group = "fudo"; primary-group = "fudo";
common-name = "Xiaoxuan Jin"; common-name = "Xiaoxuan Jin";
ldap-hashed-passwd = "{MD5}iecbyMpyVkmOaMBzSFy58Q=="; ldap-hashed-passwd = "{SSHA}04fLLUmqNUpOUJi3IBEja8bFNm0S6W60";
login-hashed-passwd = login-hashed-passwd =
"$6$C8lYHrK7KvdKm/RE$cHZ2hg5gEOEjTV8Zoayik8sz5h.Vh0.ClCgOlQn8l/2Qx/qdxqZ7xCsAZ1GZ.IEyESfhJeJbjLpykXDwPpfVF0"; "$6$C8lYHrK7KvdKm/RE$cHZ2hg5gEOEjTV8Zoayik8sz5h.Vh0.ClCgOlQn8l/2Qx/qdxqZ7xCsAZ1GZ.IEyESfhJeJbjLpykXDwPpfVF0";
email = "xiaoxuan@fudo.org"; email = "xiaoxuan@fudo.org";

3544
flake.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
fudo-home = { fudo-home = {
url = "git+https://git.fudo.org/fudo-nix/home.git"; url = "git+https://git.fudo.org/fudo-nix/home.git";
# url = "path:/state/fudo-home";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
@ -20,7 +21,10 @@
url = "path:/state/fudo-lib"; url = "path:/state/fudo-lib";
}; };
fudo-pkgs.url = "git+https://git.fudo.org/fudo-nix/pkgs.git"; fudo-pkgs = {
url = "git+https://git.fudo.org/fudo-nix/pkgs.git";
#url = "path:/state/fudo-pkgs";
};
fudo-secrets.url = "path:/state/secrets"; fudo-secrets.url = "path:/state/secrets";
@ -35,11 +39,21 @@
nixpkgs2111.url = "nixpkgs/nixos-21.11"; nixpkgs2111.url = "nixpkgs/nixos-21.11";
wallfly.url = "git+https://git.fudo.org/fudo-public/wallfly.git"; wallfly.url = "git+https://git.fudo.org/fudo-public/wallfly.git";
objectifier.url = "git+https://git.fudo.org/fudo-public/objectifier.git";
nexus.url = "git+https://git.fudo.org/fudo-public/nexus.git";
suanni.url = "git+https://git.fudo.org/fudo-public/suanni.git";
snooper.url = "git+https://git.fudo.org/fudo-public/snooper.git";
tattler.url = "git+https://git.fudo.org/fudo-public/tattler.git";
}; };
outputs = { self, nixpkgs, fudo-home, fudo-lib, fudo-entities, fudo-pkgs outputs = { self, nixpkgs, fudo-home, fudo-lib, fudo-entities, fudo-pkgs
, fudo-secrets, chute, chuteUnstable, nixpkgsUnstable, nixpkgs2111, pricebot , fudo-secrets, chute, chuteUnstable, nixpkgsUnstable, nixpkgs2111, pricebot
, wallfly, ... }@inputs: , wallfly, objectifier, nexus, suanni, snooper, tattler, ... }@inputs:
with nixpkgs.lib; with nixpkgs.lib;
let let
fudo-nixos-hosts = filterAttrs (hostname: hostOpts: hostOpts.nixos-system) fudo-nixos-hosts = filterAttrs (hostname: hostOpts: hostOpts.nixos-system)
@ -59,11 +73,14 @@
system = arch; system = arch;
config = { config = {
allowUnfree = true; allowUnfree = true;
permittedInsecurePackages = [ "openssh-with-gssapi-8.4p1" ]; permittedInsecurePackages =
[ "openssh-with-gssapi-8.4p1" "python3.10-certifi-2022.9.24" ];
}; };
overlays = [ overlays = [
fudo-lib.overlay fudo-lib.overlay
fudo-pkgs.overlay fudo-pkgs.overlays.default
fudo-secrets.overlays.default
fudo-entities.overlays.default
(final: prev: { (final: prev: {
chute = chute.packages.${arch}.chute; chute = chute.packages.${arch}.chute;
chuteUnstable = chuteUnstable.packages.${arch}.chute; chuteUnstable = chuteUnstable.packages.${arch}.chute;
@ -98,11 +115,19 @@
in { config, ... }: { in { config, ... }: {
imports = [ imports = [
fudo-home.nixosModules.default fudo-home.nixosModules.default
fudo-secrets.nixosModule fudo-secrets.nixosModules.default
fudo-lib.nixosModule fudo-lib.nixosModule
fudo-entities.nixosModule fudo-entities.nixosModule
pricebot.nixosModules.default pricebot.nixosModules.default
wallfly.nixosModule wallfly.nixosModule
objectifier.nixosModules.default
suanni.nixosModules.default
snooper.nixosModules.default
tattler.nixosModules.default
nexus.nixosModules.nexus-client
nexus.nixosModules.nexus-server
nexus.nixosModules.nexus-powerdns
./config ./config
(config-dir + "/hardware/${hostname}.nix") (config-dir + "/hardware/${hostname}.nix")