Merge branch 'master' of ssh://git.fudo.org:2222/fudo-nix/nixos-config

This commit is contained in:
niten 2023-05-24 14:14:28 -07:00
commit a192aaab95
75 changed files with 5808 additions and 979 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;

View File

@ -5,11 +5,7 @@
admin = { admin = {
gid = 1000; gid = 1000;
description = "Admin User Group"; description = "Admin User Group";
members = [ members = [ "niten" "reaper" "swaff" ];
"niten"
"reaper"
"swaff"
];
}; };
fudo = { fudo = {
@ -79,10 +75,7 @@
informis = { informis = {
gid = 1003; gid = 1003;
description = "Informis User Group"; description = "Informis User Group";
members = [ members = [ "niten" "viator" ];
"niten"
"viator"
];
}; };
}; };
} }

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" "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.maxJobs = 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

@ -49,11 +49,18 @@ with lib; {
options = [ "subvol=@state" "noexec" "noatime" "nodiratime" ]; options = [ "subvol=@state" "noexec" "noatime" "nodiratime" ];
neededForBoot = true; neededForBoot = true;
}; };
"/var/lib/private" = {
device = "/dev/disk/by-label/limina-data";
fsType = "btrfs";
options = [ "subvol=@var-private" "noexec" "noatime" "nodiratime" ];
neededForBoot = true;
};
}; };
swapDevices = [{ device = "/dev/disk/by-label/limina-swap"; }]; swapDevices = [{ device = "/dev/disk/by-label/limina-swap"; }];
nix.maxJobs = lib.mkDefault 4; nix.settings.max-jobs = lib.mkDefault 4;
hardware.bluetooth.enable = false; hardware.bluetooth.enable = false;

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

@ -59,6 +59,6 @@
}; };
services.xserver.videoDrivers = [ "intel" ]; services.xserver.videoDrivers = [ "intel" ];
nix.maxJobs = lib.mkDefault 4; nix.settings.max-jobs = lib.mkDefault 4;
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
} }

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

@ -103,7 +103,7 @@
services.xserver.videoDrivers = [ "nvidia" ]; services.xserver.videoDrivers = [ "nvidia" ];
nix.maxJobs = lib.mkDefault 8; nix.settings.max-jobs = lib.mkDefault 8;
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
systemd.targets = { systemd.targets = {

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,62 +13,60 @@ 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
Defaults lecture = never Defaults lecture = never
''; '';
fudo = {
secrets = {
secret-group = "fudo-secrets";
secret-users = [ "niten" ];
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;
};
};
};
};
systemd = {
tmpfiles.rules = [ "L /etc/adjtime - - - - /state/etc/adjtime" ];
};
};
} }

View File

@ -45,14 +45,6 @@ in {
# document-root = "/state/gemini/root"; # document-root = "/state/gemini/root";
# # textfiles-archive = "${pkgs.textfiles}"; # # textfiles-archive = "${pkgs.textfiles}";
# slynk-port = 4005; # slynk-port = 4005;
# # feeds = {
# # viator = {
# # title = "viator's phlog";
# # path = "/home/viator/gemini-public/feed/";
# # url = "gemini://informis.land/user/viator/feed/";
# # };
# # };
# }; # };
fudo = { fudo = {
@ -63,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;
}; };
}; };
@ -72,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;
@ -88,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

@ -55,18 +55,18 @@ in {
{ {
destination = "10.0.0.10:25565"; destination = "10.0.0.10:25565";
proto = "tcp"; proto = "tcp";
sourcePort = "25565"; sourcePort = 25565;
} }
{ {
destination = "10.0.0.10:25565"; destination = "10.0.0.10:25565";
proto = "udp"; proto = "udp";
sourcePort = "25565"; sourcePort = 25565;
} }
# Factorio # Factorio
{ {
destination = "10.0.0.10:34197"; destination = "10.0.0.10:34197";
proto = "udp"; proto = "udp";
sourcePort = "34197"; sourcePort = 34197;
} }
]; ];
}; };
@ -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 = {
@ -99,7 +106,7 @@ in {
mattermost-auth-token-file = host-secrets.pricebot-auth-token.target-file; mattermost-auth-token-file = host-secrets.pricebot-auth-token.target-file;
monitors = { monitors = {
btc = { btc = {
mattermost-channel-id = "3m4bsxcrwbrmpqd4yawwh98q8o"; mattermost-channel-id = "f7iem9t3qbbczjyuq4waj1s3ua";
notify-user = "niten"; notify-user = "niten";
}; };
}; };
@ -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

@ -0,0 +1,183 @@
{ config, lib, pkgs, ... }:
with lib;
let
mods = let
modFromFile = { file, deps, ... }:
let basename = baseNameOf file;
in pkgs.stdenv.mkDerivation {
name = basename;
src = file;
phases = [ "installPhase" ];
installPhase = ''
mkdir $out
cp $src $out/${basename}
'';
inherit deps;
};
modzip = { filename, deps ? [ ], ... }:
modFromFile {
file = (../../../static/factorio + "/${filename}");
inherit deps;
};
in rec {
advanced-autonomous-industries =
modzip { filename = "aai-industry_0.5.19.zip"; };
alien-biomes = modzip { filename = "alien-biomes_0.6.7.zip"; };
aircraft = modzip { filename = "Aircraft_1.8.4.zip"; };
armored-biters = modzip { filename = "ArmouredBiters_1.1.6.zip"; };
big-data-string = modzip { filename = "big-data-string_1.0.1.zip"; };
bobs-enemies = modzip { filename = "bobenemies_1.1.5.zip"; };
bottleneck = modzip { filename = "Bottleneck_0.11.7.zip"; };
bullet-trails = modzip { filename = "bullet-trails_0.6.2.zip"; };
even-distribution = modzip { filename = "even-distribution_1.0.10.zip"; };
flib = modzip { filename = "flib_0.11.2.zip"; };
flow-control = modzip { filename = "Flow Control_3.1.3.zip"; };
fluid-must-flow = modzip { filename = "FluidMustFlow_1.3.1.zip"; };
gdiw = modzip { filename = "GDIW_1.1.0.zip"; };
hovercrafts = modzip { filename = "Hovercrafts_1.2.2.zip"; };
industrial-revolution-2 =
modzip { filename = "IndustrialRevolution_2.3.2.zip"; };
krastorio2 = modzip {
filename = "Krastorio2_1.3.6.zip";
deps = [ krastorio2-assets flib ];
};
krastorio2-assets = modzip { filename = "Krastorio2Assets_1.2.0.zip"; };
larger-lamps = modzip { filename = "DeadlockLargerLamp_1.5.0.zip"; };
miniloader = modzip { filename = "miniloader_1.15.6.zip"; };
planet-imaging-satellite =
modzip { filename = "planetImagingSatellite_1.0.3.zip"; };
rampant = modzip { filename = "Rampant_3.1.2.zip"; };
recipe-book = modzip { filename = "RecipeBook_3.4.5.zip"; };
space-exploration = modzip { filename = "space-exploration_0.6.89.zip"; };
stackers = modzip { filename = "deadlock-beltboxes-loaders_2.4.2.zip"; };
trees = modzip {
filename = "Trees_4.5.1.zip";
deps = [ big-data-string ];
};
vehicle-snap = modzip { filename = "VehicleSnap_1.18.4.zip"; };
};
worldGenSeed = 5298;
mapGenSettings = {
autoplace_controls = {
coal = {
size = 4;
richness = "high";
};
copper-ore = {
size = 10;
richness = "high";
};
crude-oil = {
size = 10;
richness = "high";
};
iron-ore = {
size = 10;
richness = "high";
};
stone = {
size = 4;
richness = "high";
};
uranium-ore = {
size = 4;
richness = "high";
};
};
seed = (toString worldGenSeed);
};
in {
config = {
services.factorio = {
enable = true;
# 'factorio' points to an old game
stateDirName = "krastorio2";
package = pkgs.factorio-headless-experimental.override {
username = "fudoniten";
token = lib.removeSuffix "\n" (readFile
config.fudo.secrets.files.blobs."factorio-token-fudoniten.txt");
};
public = false;
port = 34197;
lan = true;
game-name = "Fudo Factorio";
description = "Fudo Factorio Server";
admins = [ "fudoniten" "Arkayuu" ];
openFirewall = true;
autosave-interval = 30;
loadLatestSave = true;
mods = with mods; [
alien-biomes
aircraft
armored-biters
bottleneck
bullet-trails
fluid-must-flow
krastorio2
# industrial-revolution-2
larger-lamps
stackers
trees
];
};
systemd.services.factorio = let
cfg = config.services.factorio;
serverSettings = {
name = cfg.game-name;
description = cfg.description;
visibility = {
public = cfg.public;
lan = cfg.lan;
};
username = cfg.username;
password = cfg.password;
token = cfg.token;
game_password = cfg.game-password;
require_user_verification = cfg.requireUserVerification;
max_upload_in_kilobytes_per_second = 0;
minimum_latency_in_ticks = 0;
ignore_player_limit_for_returning_players = false;
allow_commands = "admins-only";
autosave_interval = cfg.autosave-interval;
autosave_slots = 5;
afk_autokick_interval = 0;
auto_pause = true;
only_admins_can_pause_the_game = false;
autosave_only_on_server = true;
non_blocking_saving = cfg.nonBlockingSaving;
} // cfg.extraSettings;
in {
serviceConfig.ExecStart = mkForce (toString [
"${cfg.package}/bin/factorio"
"--config=${cfg.configFile}"
"--port=${toString cfg.port}"
"--bind=${toString cfg.bind}"
(optionalString (!cfg.loadLatestSave)
"--start-server=/var/lib/${cfg.stateDirName}/saves/${cfg.saveName}.zip")
"--server-settings=${
pkgs.writeText "factorio-server-settings.json" (builtins.toJSON
(filterAttrsRecursive (n: v: v != null) serverSettings))
}"
(optionalString cfg.loadLatestSave "--start-server-load-latest")
(optionalString (cfg.mods != [ ])
"--mod-directory=${pkgs.factorio-utils.mkModDirDrv cfg.mods}")
(optionalString (cfg.admins != [ ]) "--server-adminlist=${
pkgs.writeText "factorio-server-adminlist.json"
(builtins.toJSON cfg.admins)
}")
"--map-gen-settings=${
pkgs.writeText "factorio-map-gen-settings.json"
(builtins.toJSON mapGenSettings)
}"
]);
};
};
}

View File

@ -0,0 +1,14 @@
{ config, lib, pkgs, ... }:
{
config.fudo.minecraft-server = {
enable = true;
package = pkgs.minecraft-current;
data-dir = "/state/minecraft/data";
world-name = "selbyland";
game-mode = "creative";
difficulty = 2;
allow-cheats = true;
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 = {
@ -154,13 +156,13 @@ in {
logging.loki.state-directory = "/state/services/loki"; logging.loki.state-directory = "/state/services/loki";
selby-forum = { # selby-forum = {
enable = true; # enable = true;
state-directory = "/state/services/selby-forum"; # state-directory = "/state/services/selby-forum";
legacy-forum-data = files.blobs."selby-forum-2021-12-14.clean"; # legacy-forum-data = files.blobs."selby-forum-2021-12-14.clean";
external-interface = "extif0"; # external-interface = "extif0";
mail.host = "mail.fudo.org"; # mail.host = "mail.fudo.org";
}; # };
}; };
# dns.state-directory = "/state/nsd"; # dns.state-directory = "/state/nsd";
@ -258,5 +260,16 @@ in {
# loadLatestSave = true; # loadLatestSave = true;
# package = pkgs.factorio-headless-experimental; # package = pkgs.factorio-headless-experimental;
# }; # };
services.nginx.virtualHosts = {
"selby.ca" = {
enableACME = true;
locations."/".return = "301 https://selbyhomecentre.com$request_uri";
};
"www.selby.ca" = {
enableACME = true;
locations."/".return = "301 https://selbyhomecentre.com$request_uri";
};
};
}; };
} }

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,8 +49,8 @@ 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.";
@ -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;
let state-dir = "/state";
in {
fudo = { fudo = {
slynk.enable = true; slynk.enable = true;
wallfly.location = "office"; wallfly.location = "office";
@ -16,6 +18,15 @@
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

@ -8,8 +8,6 @@ in {
wallfly.location = "office"; wallfly.location = "office";
}; };
environment.systemPackages = with pkgs; [ opencv-java ];
networking = { networking = {
interfaces.intif0.useDHCP = true; interfaces.intif0.useDHCP = true;
firewall.enable = false; firewall.enable = false;
@ -22,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 = {
@ -40,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,59 @@
{ config, lib, pkgs, ... }:
let
stateDir = "/state";
primaryIp = "10.0.0.12";
generateMac = pkgs.lib.network.generate-mac-address;
in {
imports = [ ./toothless/factorio.nix ];
config = {
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

@ -0,0 +1,192 @@
{ config, lib, pkgs, ... }:
with lib;
let
mods = let
modFromFile = { file, deps, ... }:
let basename = baseNameOf file;
in pkgs.stdenv.mkDerivation {
name = basename;
src = file;
phases = [ "installPhase" ];
installPhase = ''
mkdir $out
cp $src $out/${basename}
'';
inherit deps;
};
modzip = { filename, deps ? [ ], ... }:
modFromFile {
file = (../../../static/factorio + "/${filename}");
inherit deps;
};
in rec {
advanced-autonomous-industries =
modzip { filename = "aai-industry_0.5.19.zip"; };
alien-biomes = modzip { filename = "alien-biomes_0.6.7.zip"; };
aircraft = modzip { filename = "Aircraft_1.8.4.zip"; };
armored-biters = modzip { filename = "ArmouredBiters_1.1.6.zip"; };
big-data-string = modzip { filename = "big-data-string_1.0.1.zip"; };
bobs-enemies = modzip { filename = "bobenemies_1.1.5.zip"; };
bottleneck = modzip { filename = "Bottleneck_0.11.7.zip"; };
bullet-trails = modzip { filename = "bullet-trails_0.6.2.zip"; };
even-distribution = modzip { filename = "even-distribution_1.0.10.zip"; };
flib = modzip { filename = "flib_0.11.2.zip"; };
flow-control = modzip { filename = "Flow Control_3.1.3.zip"; };
fluid-must-flow = modzip { filename = "FluidMustFlow_1.3.1.zip"; };
gdiw = modzip { filename = "GDIW_1.1.0.zip"; };
hovercrafts = modzip { filename = "Hovercrafts_1.2.2.zip"; };
industrial-revolution-2 =
modzip { filename = "IndustrialRevolution_2.3.2.zip"; };
krastorio2 = modzip {
filename = "Krastorio2_1.3.6.zip";
deps = [ krastorio2-assets flib ];
};
krastorio2-assets = modzip { filename = "Krastorio2Assets_1.2.0.zip"; };
larger-lamps = modzip { filename = "DeadlockLargerLamp_1.5.0.zip"; };
miniloader = modzip { filename = "miniloader_1.15.6.zip"; };
planet-imaging-satellite =
modzip { filename = "planetImagingSatellite_1.0.3.zip"; };
rampant = modzip { filename = "Rampant_3.1.2.zip"; };
recipe-book = modzip { filename = "RecipeBook_3.4.5.zip"; };
space-exploration = modzip { filename = "space-exploration_0.6.89.zip"; };
stackers = modzip { filename = "deadlock-beltboxes-loaders_2.4.2.zip"; };
trees = modzip {
filename = "Trees_4.5.1.zip";
deps = [ big-data-string ];
};
vehicle-snap = modzip { filename = "VehicleSnap_1.18.4.zip"; };
};
worldGenSeed = 5298;
mapGenSettings = {
autoplace_controls = {
coal = {
size = 4;
richness = "high";
};
copper-ore = {
size = 10;
richness = "high";
};
crude-oil = {
size = 10;
richness = "high";
};
iron-ore = {
size = 10;
richness = "high";
};
stone = {
size = 4;
richness = "high";
};
uranium-ore = {
size = 4;
richness = "high";
};
};
seed = (toString worldGenSeed);
};
stateDirName = "citadel";
in {
config = {
services.factorio = {
enable = true;
# 'factorio' points to an old game
inherit stateDirName;
package = pkgs.factorio-headless-experimental.override {
username = "fudoniten";
token = lib.removeSuffix "\n" (readFile
config.fudo.secrets.files.blobs."factorio-token-fudoniten.txt");
};
public = false;
port = 34197;
lan = true;
game-name = "Fudo Factorio";
description = "Fudo Factorio Server";
admins = [ "fudoniten" "Arkayuu" ];
openFirewall = true;
autosave-interval = 30;
loadLatestSave = true;
mods = with mods; [
alien-biomes
# aircraft
#armored-biters
bottleneck
bullet-trails
fluid-must-flow
#krastorio2
# industrial-revolution-2
larger-lamps
stackers
trees
];
};
fileSystems = {
"/var/lib/private/${stateDirName}" = {
device = "/state/services/factorio/${stateDirName}";
options = [ "bind" ];
};
};
systemd.services.factorio = let
cfg = config.services.factorio;
serverSettings = {
name = cfg.game-name;
description = cfg.description;
visibility = {
public = cfg.public;
lan = cfg.lan;
};
username = cfg.username;
password = cfg.password;
token = cfg.token;
game_password = cfg.game-password;
require_user_verification = cfg.requireUserVerification;
max_upload_in_kilobytes_per_second = 0;
minimum_latency_in_ticks = 0;
ignore_player_limit_for_returning_players = false;
allow_commands = "admins-only";
autosave_interval = cfg.autosave-interval;
autosave_slots = 5;
afk_autokick_interval = 0;
auto_pause = true;
only_admins_can_pause_the_game = false;
autosave_only_on_server = true;
non_blocking_saving = cfg.nonBlockingSaving;
} // cfg.extraSettings;
in {
serviceConfig.ExecStart = mkForce (toString [
"${cfg.package}/bin/factorio"
"--config=${cfg.configFile}"
"--port=${toString cfg.port}"
"--bind=${toString cfg.bind}"
(optionalString (!cfg.loadLatestSave)
"--start-server=/var/lib/${cfg.stateDirName}/saves/${cfg.saveName}.zip")
"--server-settings=${
pkgs.writeText "factorio-server-settings.json" (builtins.toJSON
(filterAttrsRecursive (n: v: v != null) serverSettings))
}"
(optionalString cfg.loadLatestSave "--start-server-load-latest")
(optionalString (cfg.mods != [ ])
"--mod-directory=${pkgs.factorio-utils.mkModDirDrv cfg.mods}")
(optionalString (cfg.admins != [ ]) "--server-adminlist=${
pkgs.writeText "factorio-server-adminlist.json"
(builtins.toJSON cfg.admins)
}")
"--map-gen-settings=${
pkgs.writeText "factorio-map-gen-settings.json"
(builtins.toJSON mapGenSettings)
}"
]);
};
};
}

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 = {
@ -8,8 +9,6 @@ in {
wallfly.location = "family_room"; wallfly.location = "family_room";
}; };
environment.systemPackages = with pkgs; [ opencv-java ];
networking = { networking = {
interfaces.intif0.useDHCP = true; interfaces.intif0.useDHCP = true;
firewall.enable = false; firewall.enable = false;
@ -21,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;
@ -34,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

@ -27,7 +27,7 @@ in {
autoSuspend = false; autoSuspend = false;
}; };
windowManager.stumpwm.enable = true; # windowManager.stumpwm.enable = true;
# windowManager.session = pkgs.lib.singleton { # windowManager.session = pkgs.lib.singleton {
# name = "stumpwm"; # name = "stumpwm";
@ -88,4 +88,24 @@ in {
services.flatpak.enable = enable-gui; services.flatpak.enable = enable-gui;
fonts.fontDir.enable = enable-gui; fonts.fontDir.enable = enable-gui;
# Stupid hack
home-manager.users = {
jasper.home.packages = let
factorio = pkgs.factorio-experimental.override {
username = "Exceeding9987";
token = lib.removeSuffix "\n" (readFile
config.fudo.secrets.files.blobs."factorio-token-exceeding9987.txt");
};
in [ factorio ];
niten.home.packages = let
factorio = pkgs.factorio-experimental.override {
username = "fudoniten";
token = lib.removeSuffix "\n" (readFile
config.fudo.secrets.files.blobs."factorio-token-fudoniten.txt");
};
in [ factorio ];
};
fudo.services.tattler.enable-notifications = 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"
@ -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 = {
@ -178,7 +151,5 @@ in {
# }; # };
}; };
}; };
home-manager = { useGlobalPkgs = true; };
}; };
} }

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

@ -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,7 +63,8 @@ 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;
}; };
@ -66,11 +79,31 @@ 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; {
@ -82,13 +115,20 @@ in {
}; };
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 =
@ -134,49 +173,51 @@ in {
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

@ -0,0 +1,38 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.fudo.services.forum_selby_ca;
in {
options.fudo.services.forum_selby_ca = with types; {
enable = mkEnableOption "Enable the Selby forum on this host.";
state-directory = mkOption {
type = str;
description = "Path at which to store forum data.";
};
};
config = mkIf cfg.enable {
containers.forum_selby_ca = {
autoStart = true;
bindMounts = {
};
config = { config, pkgs, ... }: {
services.mysql = {
enable = true;
dataDir = "${cfg.state-directory}/mysql";
ensureUsers = [{
name = "forum_selby_ca";
ensurePermissions = { "forum_selby_ca.*" = "ALL PRIVILEGES"; };
}];
ensureDatabases = [ "forum_selby_ca" ];
};
};
};
};
}

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";

View File

@ -6,8 +6,6 @@ let
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};
pthru = obj: builtins.trace "TRACE(${hostname}): ${toString obj}" obj;
host-secrets = config.fudo.secrets.host-secrets.${hostname}; host-secrets = config.fudo.secrets.host-secrets.${hostname};
notEmpty = lst: (length lst) > 0; notEmpty = lst: (length lst) > 0;

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}";
};
};
};
};
}

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

@ -0,0 +1,103 @@
{ 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 = 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";

3680
flake.lock

File diff suppressed because it is too large Load Diff

View File

@ -2,10 +2,11 @@
description = "Fudo Host Configuration"; description = "Fudo Host Configuration";
inputs = { inputs = {
nixpkgs.url = "nixpkgs/nixos-22.05"; nixpkgs.url = "nixpkgs/nixos-22.11";
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";
}; };
@ -15,15 +16,11 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
fudo-lib = { fudo-lib = { url = "git+https://git.fudo.org/fudo-nix/lib.git"; };
url = "git+https://git.fudo.org/fudo-nix/lib.git";
#url = "path:/state/fudo-lib";
inputs.nixpkgs.follows = "nixpkgs";
};
fudo-pkgs.url = "git+https://git.fudo.org/fudo-nix/pkgs.git"; fudo-pkgs = { url = "git+https://git.fudo.org/fudo-nix/pkgs.git"; };
fudo-secrets.url = "path:/state/secrets"; fudo-secrets.url = "path:/secrets";
chute.url = "git+https://git.fudo.org/chute/chute.git?ref=stable"; chute.url = "git+https://git.fudo.org/chute/chute.git?ref=stable";
@ -36,11 +33,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)
@ -60,11 +67,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;
@ -76,7 +86,12 @@
}; };
pkgsUnstable = unstable; pkgsUnstable = unstable;
}) })
(final: prev: { nyxt = unstable.nyxt; }) (final: prev: {
signal-desktop = unstable.signal-desktop;
factorio-experimental = unstable.factorio-experimental;
factorio-headless-experimental =
unstable.factorio-headless-experimental;
})
]; ];
}; };
@ -93,12 +108,20 @@
build-timestamp = concat-timestamp latest-modified-timestamp; build-timestamp = concat-timestamp latest-modified-timestamp;
in { config, ... }: { in { config, ... }: {
imports = [ imports = [
fudo-home.nixosModule 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")

View File

@ -2,7 +2,7 @@
with lib; with lib;
let let
nixos-version = "21.05"; nixos-version = "22.05";
pkgs = import <nixpkgs> { pkgs = import <nixpkgs> {
config = { config = {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.