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,85 +1,98 @@
{ 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") ];
boot = { config = {
initrd = {
availableKernelModules = [
"uhci_hcd"
"ehci_pci"
"ata_piix"
"hpsa"
"usb_storage"
"usbhid"
"sd_mod"
"sr_mod"
];
kernelModules = [ ];
};
kernelModules = [ "kvm-intel" ]; system.stateVersion = "22.05";
supportedFilesystems = [ "zfs" ];
loader.grub = { boot = {
enable = true; initrd = {
version = 2; luks.devices.lambda-unlocked = {
device = "/dev/disk/by-id/wwn-0x600508b1001cecf6b880f591f9b18b29"; device = "/dev/disk/by-uuid/e90c9dda-4e4c-4ca1-8897-39fcebc03479";
}; allowDiscards = true;
}; };
fileSystems = { availableKernelModules = [
"/boot" = { "uhci_hcd"
device = "/dev/disk/by-label/lambda-boot"; "ehci_pci"
fsType = "ext4"; "ata_piix"
options = [ "noexec" "noatime" "nodiratime" ]; "hpsa"
}; "usb_storage"
"usbhid"
"sd_mod"
"sr_mod"
];
kernelModules = [ "dm-snapshot" ];
};
"/" = { kernelModules = [ "kvm-intel" ];
device = "none"; kernelPackages = pkgs.linuxPackages_latest;
fsType = "tmpfs";
options = [ "noexec" "mode=755" ];
};
"/nix" = { loader.grub = {
device = "lambda/transient/nix"; enable = true;
fsType = "zfs"; version = 2;
options = [ "noatime" "nodiratime" ]; device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121";
};
"/var/log" = {
device = "lambda/transient/logs";
fsType = "zfs";
neededForBoot = true;
options = [ "noexec" "noatime" "nodiratime" ];
};
"/state" = {
device = "lambda/persistent/state";
fsType = "zfs";
options = [ "noexec" "noatime" "nodiratime" ];
};
};
swapDevices = [{ device = "/dev/disk/by-label/lambda-swap"; }];
nix.maxJobs = lib.mkDefault 12;
networking = {
macvlans = {
intif0 = {
interface = "enp3s0f1";
mode = "bridge";
}; };
}; };
interfaces = { fileSystems = {
intif0 = { "/" = {
# output of: echo lambda-intif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' device = "lambda-root";
macAddress = "02:f5:fe:8c:22:fe"; fsType = "tmpfs";
options = [ "mode=755" "size=32G" "noexec" ];
};
"/boot" = {
device = "/dev/disk/by-label/lambda-boot";
fsType = "ext4";
options = [ "noatime" "noexec" ];
};
"/state" = {
device = "/dev/mapper/lambda-unlocked";
fsType = "btrfs";
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-id/scsi-3600508b1001c3be9174b4bdb31935121-part2";
randomEncryption.enable = true;
}];
nix.settings.max-jobs = lib.mkDefault 24;
networking = {
useDHCP = false;
macvlans = {
intif0 = {
interface = "enp4s0f1";
mode = "bridge";
};
};
interfaces = {
intif0 = {
macAddress = generateMac config.instance.hostname "intif0";
};
}; };
}; };
}; };

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,79 +1,72 @@
{ 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 = {
enp3s0f0.useDHCP = false; enp3s0f0.useDHCP = false;
enp3s0f1.useDHCP = false; enp3s0f1.useDHCP = false;
enp4s0f0.useDHCP = false; enp4s0f0.useDHCP = false;
enp4s0f1.useDHCP = false; enp4s0f1.useDHCP = false;
intif0.useDHCP = true; intif0 = {
useDHCP = false;
ipv4.addresses = [{
address = primaryIp;
prefixLength = 16;
}];
};
};
defaultGateway = {
address = "10.0.0.1";
interface = "intif0";
};
};
environment = {
etc = {
nixos.source = "/etc/nixos-live";
NIXOS.source = "/state/host/NIXOS";
};
systemPackages = with pkgs; [ nixopsUnstable openssl ];
};
security.sudo.extraConfig = ''
# Due to rollback, sudo will lecture after every reboot
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" ];
}; };
}; };
systemd.tmpfiles.rules = [
"L /root/.gnupg - - - - ${state-dir}/user/root/gnupg"
"L /root/.ssh/id_rsa - - - - ${state-dir}/user/root/ssh/id_rsa"
"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 = [
{
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";
adjtime.source = "/state/host/adjtime";
NIXOS.source = "/state/host/NIXOS";
};
security.sudo.extraConfig = ''
# Due to rollback, sudo will lecture after every reboot
Defaults lecture = never
'';
} }

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,12 +49,12 @@ in {
}; };
"selby.ca" = { "selby.ca" = {
enable = true; enable = true;
external-nameservers = map (n: let external-nameservers = map (n:
i = toString n; let i = toString n;
in { in {
authoritative-hostname = "ns${i}.fudo.org"; authoritative-hostname = "ns${i}.fudo.org";
description = "Nameserver ${i}, ns${i}.fudo.org."; description = "Nameserver ${i}, ns${i}.fudo.org.";
}) [2 3 4]; }) [ 2 3 4 ];
}; };
}; };
@ -82,9 +79,7 @@ in {
"rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org." "rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org."
]; ];
}; };
"selby.ca" = { "selby.ca" = { default-host = host-ipv4; };
default-host = host-ipv4;
};
}; };
}; };
@ -117,17 +112,15 @@ in {
interfaces = [ "eno2" ]; interfaces = [ "eno2" ];
config = { config, ... }: { config = { config, ... }: {
boot.kernelModules = [ "veth" ];
nixpkgs.pkgs = pkgs; nixpkgs.pkgs = pkgs;
environment = { environment = {
systemPackages = local-packages; systemPackages = local-packages;
etc = { etc = {
"generated-zones/fudo.org" = { "generated-zones/fudo.org" = { text = fudo-zone; };
text = fudo-zone; "generated-zones/selby.ca" = { text = selby-zone; };
};
"generated-zones/selby.ca" = {
text = selby-zone;
};
}; };
}; };
@ -144,17 +137,8 @@ in {
]; ];
}; };
groups = { groups = {
wheel.members = [ wheel.members = [ "niten" "reaper" ];
"niten" dns = { members = [ "niten" "reaper" "named" ]; };
"reaper"
];
dns = {
members = [
"niten"
"reaper"
"named"
];
};
}; };
}; };

View File

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

View File

@ -1,6 +1,8 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
{ with lib;
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 = {
mosquitto-home-assistant-passwd = { zigbee2mqtt = {
source-file = host-passwds.mosquitto-home-assistant; password-file = zigbee2mqtt-passwd-file;
target-file = "/run/mosquitto-secrets/home-assistant.passwd"; acl = [ "readwrite #" ];
user = mosquitto-user; };
}; home-assistant = {
mosquitto-niten-passwd = { password-file = host-passwds.mosquitto-home-assistant;
source-file = host-passwds.mosquitto-niten; acl = [ "readwrite #" ];
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 = { # # wallfly = {
# passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file; # # passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
# acl = [ "readwrite homeassistant/binary_sensor/#" ]; # # 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,66 +7,83 @@ 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 =
in mkIf (keytab-file != null) { try-attr hostname config.fudo.secrets.files.kerberos.host-keytabs;
## This doesn't seem to work...timing? in mkIf (keytab-file != null) {
# environment.etc."krb5.keytab" = mkIf (keytab-file != null) { ## This doesn't seem to work...timing?
# source = # environment.etc."krb5.keytab" = mkIf (keytab-file != null) {
# config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file; # source =
# user = "root"; # config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
# group = "root"; # user = "root";
# mode = "0400"; # group = "root";
# }; # mode = "0400";
# };
systemd = let krb5 = {
host-keytab = domain_realm = let
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file; krbDoms = filterAttrs (_: domCfg: domCfg.gssapi-realm != null)
in { config.fudo.domains;
paths."${hostname}-keytab-watcher" = { domClauses = dom: domCfg: [
wantedBy = [ "default.target" ]; (nameValuePair dom domCfg.gssapi-realm)
description = "Watch host keytab for changes."; (nameValuePair ".${dom}" domCfg.gssapi-realm)
pathConfig = { ];
PathChanged = host-keytab; concatMapAttrs = f: lst:
Unit = "${hostname}-keytab-watcher.service"; listToAttrs (concatMap (i: i) (mapAttrsToList f lst));
}; in concatMapAttrs domClauses krbDoms;
};
services = { libdefaults.default_etypes =
"${hostname}-keytab-watcher" = { "aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96";
description = };
"When host keytab is available or changed, activate copy job.";
path = with pkgs; [ systemd ];
serviceConfig = { Type = "oneshot"; };
script = "systemctl restart ${hostname}-copy-keytab.service";
};
"${hostname}-copy-keytab" = { systemd = let
description = host-keytab =
"Copy the host krb5.keytab into place once it's available."; config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
serviceConfig = { in {
Type = "simple"; paths."${hostname}-keytab-watcher" = {
RemainAfterExit = true; wantedBy = [ "default.target" ];
ExecStart = pkgs.writeShellScript "${hostname}-copy-keytab.sh" '' description = "Watch host keytab for changes.";
[ -f ${host-keytab} ] || exit 1 pathConfig = {
[ -f /etc/krb5.keytab ] && rm /etc/krb5.keytab PathChanged = host-keytab;
cp ${host-keytab} /etc/krb5.keytab Unit = "${hostname}-keytab-watcher.service";
chown root:root /etc/krb5.keytab
chmod 0400 /etc/krb5.keytab
'';
ExecStop = pkgs.writeShellScript "${hostname}-remove-keytab.sh" ''
rm -f /etc/krb5.keytab
'';
};
};
}; };
}; };
fudo.secrets.host-secrets.${hostname}.host-keytab = services = {
mkIf (keytab-file != null) { "${hostname}-keytab-watcher" = {
source-file = keytab-file; description =
target-file = "/run/kerberos/krb5.keytab"; "When host keytab is available or changed, activate copy job.";
user = "root"; path = with pkgs; [ systemd ];
serviceConfig = { Type = "oneshot"; };
script = "systemctl restart ${hostname}-copy-keytab.service";
}; };
});
"${hostname}-copy-keytab" = {
description =
"Copy the host krb5.keytab into place once it's available.";
serviceConfig = {
Type = "simple";
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "${hostname}-copy-keytab.sh" ''
[ -f ${host-keytab} ] || exit 1
[ -f /etc/krb5.keytab ] && rm /etc/krb5.keytab
cp ${host-keytab} /etc/krb5.keytab
chown root:root /etc/krb5.keytab
chmod 0400 /etc/krb5.keytab
'';
ExecStop = pkgs.writeShellScript "${hostname}-remove-keytab.sh" ''
rm -f /etc/krb5.keytab
'';
};
};
};
};
fudo.secrets.host-secrets.${hostname}.host-keytab =
mkIf (keytab-file != null) {
source-file = keytab-file;
target-file = "/run/kerberos/krb5.keytab";
user = "root";
};
});
} }

View File

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

View File

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

View File

@ -1,4 +1,4 @@
{ config, lib, pkgs, ... } @ toplevel: { config, lib, pkgs, ... }@toplevel:
with lib; with lib;
let let
@ -6,6 +6,18 @@ let
cfg = config.fudo.services.dns; cfg = config.fudo.services.dns;
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
domain-name = config.instance.local-domain;
domain = config.fudo.domains.${domain-name};
primary-nameserver = domain.primary-nameserver;
primary-nameserver-ip = pkgs.lib.network.host-ipv4 config primary-nameserver;
primary-nameserver-fqdn = "${primary-nameserver}.${domain-name}";
is-primary-nameserver = primary-nameserver == hostname;
zoneKeySecret = zone: "${zone}-ksk";
nameserverOpts = { name, ... }: { nameserverOpts = { name, ... }: {
options = with types; { options = with types; {
hostname = mkOption { hostname = mkOption {
@ -39,166 +51,192 @@ 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 {
type = bool; type = bool;
description = "Enable ${zone-name} zone on the local nameserver."; description = "Enable ${zone-name} zone on the local nameserver.";
default = zone-name == toplevel.config.instance.local-zone; default = zone-name == toplevel.config.instance.local-zone;
}; };
default-host = mkOption { default-host = mkOption {
type = nullOr str; type = nullOr str;
description = "IP which will respond to requests for the base domain."; description =
default = null; "IP which will respond to requests for the base domain.";
}; default = null;
};
external-nameservers = mkOption { external-nameservers = mkOption {
type = listOf (submodule nameserverOpts); type = listOf (submodule nameserverOpts);
description = "Off-network secondary nameservers."; description = "Off-network secondary nameservers.";
default = []; default = [ ];
}; };
domain = mkOption { domain = mkOption {
type = str; type = str;
description = "Domain which this zone serves."; description = "Domain which this zone serves.";
default = zone-name; default = zone-name;
};
ksk = mkOption {
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}";
};
}; };
}; };
};
pthru = obj:
builtins.trace "TRACE: ${ obj }" obj;
in { in {
options.fudo.services.dns = with types; { options.fudo.services.dns = with types; {
zones = mkOption { zones = mkOption {
type = attrsOf (submodule zoneOpts); type = attrsOf (submodule zoneOpts);
description = "Map of served zone to extra zone details."; description = "Map of served zone to extra zone details.";
default = {}; default = { };
}; };
}; };
config.fudo = { config.fudo = {
zones = mapAttrs (zone-name: zone-cfg: let secrets.host-secrets."${hostname}" = mkIf is-primary-nameserver (mapAttrs'
domain-name = zone-cfg.domain; (zone: zone-cfg:
domain = config.fudo.domains.${domain-name}; 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);
make-srv-record = port: host: { zones = mapAttrs (zone-name: zone-cfg:
inherit port host; let
}; domain-name = zone-cfg.domain;
domain = config.fudo.domains.${domain-name};
served-domain = domain.primary-nameserver != null; make-srv-record = port: host: { inherit port host; };
primary-nameserver = domain.primary-nameserver; served-domain = domain.primary-nameserver != null;
is-primary-nameserver = hostname == primary-nameserver; primary-nameserver = domain.primary-nameserver;
internal-nameserver-hostnames = is-primary-nameserver = hostname == primary-nameserver;
[domain.primary-nameserver] ++ domain.secondary-nameservers;
get-host-deets = description: hostname: { internal-nameserver-hostnames = [ domain.primary-nameserver ]
ipv4-address = pkgs.lib.network.host-ipv4 config hostname; ++ domain.secondary-nameservers;
ipv6-address = pkgs.lib.network.host-ipv6 config hostname;
description = description;
};
get-ns-deets = hostname: let get-host-deets = description: hostname: {
host-domain = config.fudo.hosts.${hostname}.domain; ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
desc = "${domain-name} nameserver ${hostname}.${host-domain}."; ipv6-address = pkgs.lib.network.host-ipv6 config hostname;
in get-host-deets desc hostname; description = description;
};
nameserver-deets = let get-ns-deets = hostname:
internal-nameservers = map get-ns-deets internal-nameserver-hostnames; let
in internal-nameservers ++ zone-cfg.external-nameservers; host-domain = config.fudo.hosts.${hostname}.domain;
desc = "${domain-name} nameserver ${hostname}.${host-domain}.";
in get-host-deets desc hostname;
has-auth-hostname = ns-host: ns-opts: nameserver-deets = let
(hasAttr "authoritative-hostname" ns-opts) && internal-nameservers = map get-ns-deets internal-nameserver-hostnames;
(ns-opts.authoritative-hostname != null); in internal-nameservers ++ zone-cfg.external-nameservers;
all-nameservers = listToAttrs has-auth-hostname = ns-host: ns-opts:
(imap1 (hasAttr "authoritative-hostname" ns-opts)
(i: nsOpts: && (ns-opts.authoritative-hostname != null);
nameValuePair "ns${toString i}" nsOpts)
nameserver-deets);
nameserver-aliases = all-nameservers = listToAttrs
mapAttrs (hostname: opts: "${opts.authoritative-hostname}.") (imap1 (i: nsOpts: nameValuePair "ns${toString i}" nsOpts)
nameserver-deets);
nameserver-aliases =
mapAttrs (hostname: opts: "${opts.authoritative-hostname}.")
(filterAttrs has-auth-hostname all-nameservers); (filterAttrs has-auth-hostname all-nameservers);
nameserver-hosts = mapAttrs (hostname: opts: { nameserver-hosts = mapAttrs (hostname: opts: {
inherit (opts) ipv4-address ipv6-address description; inherit (opts) ipv4-address ipv6-address description;
}) (filterAttrs (hostname: opts: ! has-auth-hostname hostname opts) }) (filterAttrs (hostname: opts: !has-auth-hostname hostname opts)
all-nameservers); all-nameservers);
dns-srv-records = let dns-srv-records = let
nameserver-srv-records = mapAttrsToList nameserver-srv-records = mapAttrsToList (hostname: hostOpts:
(hostname: hostOpts: let let
target-host = if (has-auth-hostname hostname hostOpts) then target-host = if (has-auth-hostname hostname hostOpts) then
"${hostOpts.authoritative-hostname}" else "${hostOpts.authoritative-hostname}"
else
"${hostname}.${domain-name}"; "${hostname}.${domain-name}";
in make-srv-record 53 target-host) in make-srv-record 53 target-host) all-nameservers;
all-nameservers;
in {
tcp.domain = nameserver-srv-records;
udp.domain = nameserver-srv-records;
};
# TODO: move this to a mail service
mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
tcp = let
mailserver-domain = config.fudo.hosts.${domain.primary-mailserver}.domain;
fqdn = "mail.${mailserver-domain}";
in { in {
smtp = [(make-srv-record 25 fqdn)]; tcp.domain = nameserver-srv-records;
submission = [(make-srv-record 587 fqdn)]; udp.domain = nameserver-srv-records;
imap = [(make-srv-record 143 fqdn)];
imaps = [(make-srv-record 993 fqdn)];
pop3 = [(make-srv-record 110 fqdn)];
pop3s = [(make-srv-record 995 fqdn)];
}; };
};
in { # # TODO: move this to a mail service
gssapi-realm = domain.gssapi-realm; # mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
# tcp = let
# mailserver-domain =
# config.fudo.hosts.${domain.primary-mailserver}.domain;
# fqdn = "mail.${mailserver-domain}";
# in {
# smtp = [ (make-srv-record 25 fqdn) ];
# submission = [ (make-srv-record 587 fqdn) ];
# imap = [ (make-srv-record 143 fqdn) ];
# imaps = [ (make-srv-record 993 fqdn) ];
# pop3 = [ (make-srv-record 110 fqdn) ];
# pop3s = [ (make-srv-record 995 fqdn) ];
# };
# };
hosts = nameserver-hosts // { in {
mail = mkIf (domain.primary-nameserver != null) (let gssapi-realm = domain.gssapi-realm;
mailserver-deets = host: let
host-domain = config.fudo.hosts.${host}.domain;
in get-host-deets "Primary ${domain-name} mailserver ${host}.${host-domain}." host;
in mailserver-deets domain.primary-nameserver);
};
aliases = nameserver-aliases; hosts = nameserver-hosts // {
mail = mkIf (domain.primary-nameserver != null) (let
mailserver-deets = host:
let host-domain = config.fudo.hosts.${host}.domain;
in get-host-deets
"Primary ${domain-name} mailserver ${host}.${host-domain}." host;
in mailserver-deets domain.primary-nameserver);
};
mx = optional (domain.primary-mailserver != null) aliases = nameserver-aliases;
(let
mail-domain-name = config.fudo.hosts.${domain.primary-mailserver}.domain;
in "mail.${mail-domain-name}");
dmarc-report-address = "dmarc-report@${domain-name}"; mx = optional (domain.primary-mailserver != null) (let
mail-domain-name =
config.fudo.hosts.${domain.primary-mailserver}.domain;
in "mail.${mail-domain-name}");
nameservers = let dmarc-report-address = "dmarc-report@${domain-name}";
direct-external = attrValues nameserver-aliases;
internal = map (hostname: "${hostname}.${domain-name}.")
(attrNames nameserver-hosts);
in internal ++ direct-external;
srv-records = dns-srv-records // mail-srv-records; nameservers = let
}) cfg.zones; direct-external = attrValues nameserver-aliases;
internal = map (hostname: "${hostname}.${domain-name}.")
(attrNames nameserver-hosts);
in internal ++ direct-external;
dns = let srv-records = dns-srv-records; # // mail-srv-records;
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; verbatim-dns-records = mkIf (zone-cfg.ksk != null) [
in { (readFile zone-cfg.ksk.public-key)
(readFile zone-cfg.ksk.ds)
];
}) cfg.zones;
dns = {
enable = is-primary-nameserver; enable = is-primary-nameserver;
identity = "${hostname}.${domain-name}"; identity = "${hostname}.${domain-name}";
@ -207,11 +245,11 @@ 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,52 +132,110 @@ in {
}; };
}; };
auth = { secrets.host-secrets."${hostname}" = let
ldap-server = mkIf (ldap-server) realm-key =
(let config.fudo.secrets.files.kerberos.realm-master-keys."${realm}";
ldap-cert-copy = in {
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap; realm-master-key = mkIf (kerberos-master || kerberos-slave) {
in { source-file = realm-key;
enable = ldap-server; target-file = "/run/kdc/realm.key";
base = "dc=fudo,dc=org"; user = krb-user;
organization = "Fudo"; group = krb-group;
listen-uris = [ "ldap:///" "ldaps:///" ]; };
required-services = [ ldap-cert-copy.service ];
# TODO: Maybe filter to Fudo-only? kdc-principals = mkIf (kerberos-master || kerberos-slave) {
users = config.fudo.users; source-file =
groups = config.fudo.groups; config.fudo.secrets.files.kerberos.realm-principals."${realm}";
system-users = config.fudo.system-users; target-file = "/run/kdc/realm.principals";
user = krb-user;
state-directory = "${cfg.ldap.state-directory}"; group = krb-group;
};
ssl-chain = ldap-cert-copy.chain; kadmind-keytab = mkIf kerberos-master {
ssl-certificate = ldap-cert-copy.certificate; source-file = extractFudoKeytab {
ssl-private-key = ldap-cert-copy.private-key; inherit realm;
ssl-ca-certificate = "${pkgs.letsencrypt-ca}"; principals = [ "kadmin/admin" ];
});
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;
master-key-file = cfg.kerberos.master-key-file;
master-config = mkIf (kerberos-master) {
acl = let
admin-entries = genAttrs config.instance.local-admins
(admin: {
perms = [ "add" "change-password" "list" ];
});
in admin-entries // {
"*/root".perms = [ "all" ];
};
}; };
slave-config = mkIf (kerberos-slave) { target-file = "/run/kdc/kadmind.keytab";
master-host = domain.kerberos-master; user = krb-user;
ipropd-keytab = cfg.kerberos.ipropd-keytab; 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 = {
ldap-server = mkIf ldap-server (let
ldap-cert-copy =
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
in {
enable = ldap-server;
base = "dc=fudo,dc=org";
organization = "Fudo";
listen-uris = [ "ldap:///" "ldaps:///" ];
required-services = [ ldap-cert-copy.service ];
# TODO: Maybe filter to Fudo-only?
users = config.fudo.users;
groups = config.fudo.groups;
system-users = config.fudo.system-users;
state-directory = "${cfg.ldap.state-directory}";
ssl-chain = ldap-cert-copy.chain;
ssl-certificate = ldap-cert-copy.certificate;
ssl-private-key = ldap-cert-copy.private-key;
ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
});
kerberos = {
inherit realm;
kdc = mkIf (kerberos-master || kerberos-slave) {
state-directory = cfg.kerberos.state-directory;
master-key-file = host-secrets.realm-master-key.target-file;
primary = mkIf kerberos-master {
enable = true;
acl = let
adminEntries = genAttrs config.instance.local-admins
(admin: { perms = [ "add" "change-password" "list" ]; });
in adminEntries // { "*/root".perms = [ "all" ]; };
secondary-servers = map getHostFqdn domain.kerberos-slaves;
keytabs = {
kadmind = host-secrets.kadmind-keytab.target-file;
kpasswdd = host-secrets.kpasswdd-keytab.target-file;
hprop = host-secrets.hprop-keytab.target-file;
};
};
secondary = mkIf kerberos-slave {
enable = true;
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,18 +48,20 @@ in {
}; };
}; };
secrets.host-secrets.${hostname}.postgres-keytab = mkIf (cfg.keytab != null) { secrets.host-secrets.${hostname}.postgres-keytab =
source-file = cfg.keytab; mkIf (cfg.keytab != null) {
target-file = "/run/postgresql/postgres.keytab"; source-file = cfg.keytab;
user = postgresUser; target-file = "/run/postgresql/postgres.keytab";
}; user = postgresUser;
};
zones.${zone-name}.aliases.postgresql = zones.${zone-name}.aliases.postgresql =
"${domain.postgresql-server}.${domain-name}."; "${domain.postgresql-server}.${domain-name}.";
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; enable = true;
listeners = [{ private = {
settings.allow_anonymous = false; enable = true;
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 = {
enable = true; mqtt = {
mqtt.broker-host = "wormhole0"; enable = true;
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.