Merge branch 'master' of ssh://git.fudo.org:2222/fudo-nix/nixos-config
This commit is contained in:
commit
a192aaab95
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,13 +1,22 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let generateMac = pkgs.lib.network.generate-mac-address;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
system.stateVersion = "21.05";
|
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
|
||||||
|
system.stateVersion = "22.05";
|
||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
initrd = {
|
initrd = {
|
||||||
|
luks.devices.lambda-unlocked = {
|
||||||
|
device = "/dev/disk/by-uuid/e90c9dda-4e4c-4ca1-8897-39fcebc03479";
|
||||||
|
allowDiscards = true;
|
||||||
|
};
|
||||||
|
|
||||||
availableKernelModules = [
|
availableKernelModules = [
|
||||||
"uhci_hcd"
|
"uhci_hcd"
|
||||||
"ehci_pci"
|
"ehci_pci"
|
||||||
|
@ -18,68 +27,72 @@ in {
|
||||||
"sd_mod"
|
"sd_mod"
|
||||||
"sr_mod"
|
"sr_mod"
|
||||||
];
|
];
|
||||||
kernelModules = [ ];
|
kernelModules = [ "dm-snapshot" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
kernelModules = [ "kvm-intel" ];
|
kernelModules = [ "kvm-intel" ];
|
||||||
supportedFilesystems = [ "zfs" ];
|
kernelPackages = pkgs.linuxPackages_latest;
|
||||||
|
|
||||||
loader.grub = {
|
loader.grub = {
|
||||||
enable = true;
|
enable = true;
|
||||||
version = 2;
|
version = 2;
|
||||||
device = "/dev/disk/by-id/wwn-0x600508b1001cecf6b880f591f9b18b29";
|
device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems = {
|
fileSystems = {
|
||||||
|
"/" = {
|
||||||
|
device = "lambda-root";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [ "mode=755" "size=32G" "noexec" ];
|
||||||
|
};
|
||||||
"/boot" = {
|
"/boot" = {
|
||||||
device = "/dev/disk/by-label/lambda-boot";
|
device = "/dev/disk/by-label/lambda-boot";
|
||||||
fsType = "ext4";
|
fsType = "ext4";
|
||||||
options = [ "noexec" "noatime" "nodiratime" ];
|
options = [ "noatime" "noexec" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
"/" = {
|
|
||||||
device = "none";
|
|
||||||
fsType = "tmpfs";
|
|
||||||
options = [ "noexec" "mode=755" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
"/nix" = {
|
|
||||||
device = "lambda/transient/nix";
|
|
||||||
fsType = "zfs";
|
|
||||||
options = [ "noatime" "nodiratime" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
"/var/log" = {
|
|
||||||
device = "lambda/transient/logs";
|
|
||||||
fsType = "zfs";
|
|
||||||
neededForBoot = true;
|
|
||||||
options = [ "noexec" "noatime" "nodiratime" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
"/state" = {
|
"/state" = {
|
||||||
device = "lambda/persistent/state";
|
device = "/dev/mapper/lambda-unlocked";
|
||||||
fsType = "zfs";
|
fsType = "btrfs";
|
||||||
options = [ "noexec" "noatime" "nodiratime" ];
|
options = [ "noatime" "compress=zstd" "noexec" "subvol=@state" ];
|
||||||
|
};
|
||||||
|
"/nix" = {
|
||||||
|
device = "/dev/mapper/lambda-unlocked";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "compress=zstd" "subvol=@nix" ];
|
||||||
|
};
|
||||||
|
"/home" = {
|
||||||
|
device = "/dev/mapper/lambda-unlocked";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "compress=zstd" "subvol=@home" ];
|
||||||
|
};
|
||||||
|
"/var/log" = {
|
||||||
|
device = "/dev/mapper/lambda-unlocked";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "noatime" "compress=zstd" "noexec" "subvol=@log" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
swapDevices = [{ device = "/dev/disk/by-label/lambda-swap"; }];
|
swapDevices = [{
|
||||||
|
device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121-part2";
|
||||||
|
randomEncryption.enable = true;
|
||||||
|
}];
|
||||||
|
|
||||||
nix.maxJobs = lib.mkDefault 12;
|
nix.settings.max-jobs = lib.mkDefault 24;
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
|
useDHCP = false;
|
||||||
macvlans = {
|
macvlans = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
interface = "enp3s0f1";
|
interface = "enp4s0f1";
|
||||||
mode = "bridge";
|
mode = "bridge";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
interfaces = {
|
interfaces = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
# output of: echo lambda-intif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'
|
macAddress = generateMac config.instance.hostname "intif0";
|
||||||
macAddress = "02:f5:fe:8c:22:fe";
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
nix.maxJobs = lib.mkDefault 24;
|
nix.settings.max-jobs = lib.mkDefault 24;
|
||||||
|
|
||||||
hardware.bluetooth.enable = false;
|
hardware.bluetooth.enable = false;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
};
|
||||||
|
}
|
|
@ -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 = {
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let primaryIp = "10.0.0.11";
|
||||||
state-dir = "/state"; # This must be a string!
|
|
||||||
|
|
||||||
generate-mac = pkgs.lib.network.generate-mac-address;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
boot = {
|
config = {
|
||||||
loader.grub.copyKernels = true;
|
boot = { loader.grub.copyKernels = true; };
|
||||||
#kernelModules = [ "rpcsec_gss_krb5" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
|
@ -18,62 +13,60 @@ in {
|
||||||
enp4s0f0.useDHCP = false;
|
enp4s0f0.useDHCP = false;
|
||||||
enp4s0f1.useDHCP = false;
|
enp4s0f1.useDHCP = false;
|
||||||
|
|
||||||
intif0.useDHCP = true;
|
intif0 = {
|
||||||
|
useDHCP = false;
|
||||||
|
ipv4.addresses = [{
|
||||||
|
address = primaryIp;
|
||||||
|
prefixLength = 16;
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
defaultGateway = {
|
||||||
"L /root/.gnupg - - - - ${state-dir}/user/root/gnupg"
|
address = "10.0.0.1";
|
||||||
"L /root/.ssh/id_rsa - - - - ${state-dir}/user/root/ssh/id_rsa"
|
interface = "intif0";
|
||||||
"L /root/.ssh/id_rsa.pub - - - - ${state-dir}/user/root/ssh/id_rsa.pub"
|
};
|
||||||
"L /root/.ssh/known_hosts - - - - ${state-dir}/user/root/ssh/known_hosts"
|
};
|
||||||
];
|
|
||||||
|
|
||||||
services.openssh.hostKeys = [
|
environment = {
|
||||||
{
|
etc = {
|
||||||
path = "${state-dir}/ssh/ssh_host_rsa_key";
|
|
||||||
type = "rsa";
|
|
||||||
bits = 4096;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
path = "${state-dir}/ssh/ssh_host_ed25519_key";
|
|
||||||
type = "ed25519";
|
|
||||||
bits = 4096;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.etc = {
|
|
||||||
"ssh/ssh_host_rsa_key" = {
|
|
||||||
source = "${state-dir}/ssh/ssh_host_rsa_key";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
mode = "0400";
|
|
||||||
};
|
|
||||||
"ssh/ssh_host_rsa_key.pub" = {
|
|
||||||
source = "${state-dir}/ssh/ssh_host_rsa_key.pub";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
mode = "0444";
|
|
||||||
};
|
|
||||||
"ssh/ssh_host_ed25519_key" = {
|
|
||||||
source = "${state-dir}/ssh/ssh_host_ed25519_key";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
mode = "0400";
|
|
||||||
};
|
|
||||||
"ssh/ssh_host_ed25519_key.pub" = {
|
|
||||||
source = "${state-dir}/ssh/ssh_host_ed25519_key.pub";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
mode = "0444";
|
|
||||||
};
|
|
||||||
nixos.source = "/etc/nixos-live";
|
nixos.source = "/etc/nixos-live";
|
||||||
adjtime.source = "/state/host/adjtime";
|
|
||||||
NIXOS.source = "/state/host/NIXOS";
|
NIXOS.source = "/state/host/NIXOS";
|
||||||
};
|
};
|
||||||
|
systemPackages = with pkgs; [ nixopsUnstable openssl ];
|
||||||
|
};
|
||||||
|
|
||||||
security.sudo.extraConfig = ''
|
security.sudo.extraConfig = ''
|
||||||
# Due to rollback, sudo will lecture after every reboot
|
# Due to rollback, sudo will lecture after every reboot
|
||||||
Defaults lecture = never
|
Defaults lecture = never
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
fudo = {
|
||||||
|
secrets = {
|
||||||
|
secret-group = "fudo-secrets";
|
||||||
|
secret-users = [ "niten" ];
|
||||||
|
secret-paths = [ "/secrets" ];
|
||||||
|
};
|
||||||
|
hosts.lambda.encrypted-filesystems.secrets = {
|
||||||
|
encrypted-device =
|
||||||
|
"/dev/disk/by-id/scsi-3600508b1001c2f439e343270a365a5bd-part1";
|
||||||
|
key-path = "/state/secrets-key/key";
|
||||||
|
filesystem-type = "btrfs";
|
||||||
|
remove-key = false;
|
||||||
|
type = "luks2";
|
||||||
|
mountpoints = {
|
||||||
|
"/secrets" = {
|
||||||
|
options = [ "noatime" "compress=zstd" ];
|
||||||
|
group = "fudo-secrets";
|
||||||
|
users = [ "niten" ];
|
||||||
|
world-readable = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
tmpfiles.rules = [ "L /etc/adjtime - - - - /state/etc/adjtime" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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)
|
||||||
|
}"
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -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";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,14 @@ let
|
||||||
|
|
||||||
host-ipv4 = "199.87.154.175";
|
host-ipv4 = "199.87.154.175";
|
||||||
|
|
||||||
local-packages = with pkgs; [
|
local-packages = with pkgs; [ bind emacs-nox mtr vim ];
|
||||||
bind
|
|
||||||
emacs-nox
|
|
||||||
mtr
|
|
||||||
vim
|
|
||||||
];
|
|
||||||
|
|
||||||
fudo-zone = pkgs.lib.dns.zoneToZonefile
|
fudo-zone =
|
||||||
config.instance.build-timestamp "fudo.org"
|
pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp "fudo.org"
|
||||||
config.fudo.zones."fudo.org";
|
config.fudo.zones."fudo.org";
|
||||||
|
|
||||||
selby-zone = pkgs.lib.dns.zoneToZonefile
|
selby-zone =
|
||||||
config.instance.build-timestamp "selby.ca"
|
pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp "selby.ca"
|
||||||
config.fudo.zones."selby.ca";
|
config.fudo.zones."selby.ca";
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
@ -36,12 +31,14 @@ in {
|
||||||
{
|
{
|
||||||
ipv4-address = "209.177.102.102";
|
ipv4-address = "209.177.102.102";
|
||||||
ipv6-address = "2001:470:1f16:40::2";
|
ipv6-address = "2001:470:1f16:40::2";
|
||||||
description = "Nameserver 2, Musashi.100percenthost.net, in Winnipeg, MB, CA";
|
description =
|
||||||
|
"Nameserver 2, Musashi.100percenthost.net, in Winnipeg, MB, CA";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
ipv4-address = "104.131.53.95";
|
ipv4-address = "104.131.53.95";
|
||||||
ipv6-address = "2604:a880:800:10::8:7001";
|
ipv6-address = "2604:a880:800:10::8:7001";
|
||||||
description = "Nameserver 3, ns2.henchmman21.net, in New York City, NY, US";
|
description =
|
||||||
|
"Nameserver 3, ns2.henchmman21.net, in New York City, NY, US";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
ipv4-address = "204.42.254.5";
|
ipv4-address = "204.42.254.5";
|
||||||
|
@ -52,8 +49,8 @@ in {
|
||||||
};
|
};
|
||||||
"selby.ca" = {
|
"selby.ca" = {
|
||||||
enable = true;
|
enable = true;
|
||||||
external-nameservers = map (n: let
|
external-nameservers = map (n:
|
||||||
i = toString n;
|
let i = toString n;
|
||||||
in {
|
in {
|
||||||
authoritative-hostname = "ns${i}.fudo.org";
|
authoritative-hostname = "ns${i}.fudo.org";
|
||||||
description = "Nameserver ${i}, ns${i}.fudo.org.";
|
description = "Nameserver ${i}, ns${i}.fudo.org.";
|
||||||
|
@ -82,9 +79,7 @@ in {
|
||||||
"rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org."
|
"rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org."
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
"selby.ca" = {
|
"selby.ca" = { default-host = host-ipv4; };
|
||||||
default-host = host-ipv4;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,17 +112,15 @@ in {
|
||||||
interfaces = [ "eno2" ];
|
interfaces = [ "eno2" ];
|
||||||
|
|
||||||
config = { config, ... }: {
|
config = { config, ... }: {
|
||||||
|
boot.kernelModules = [ "veth" ];
|
||||||
|
|
||||||
nixpkgs.pkgs = pkgs;
|
nixpkgs.pkgs = pkgs;
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
systemPackages = local-packages;
|
systemPackages = local-packages;
|
||||||
etc = {
|
etc = {
|
||||||
"generated-zones/fudo.org" = {
|
"generated-zones/fudo.org" = { text = fudo-zone; };
|
||||||
text = fudo-zone;
|
"generated-zones/selby.ca" = { text = selby-zone; };
|
||||||
};
|
|
||||||
"generated-zones/selby.ca" = {
|
|
||||||
text = selby-zone;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,17 +137,8 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
groups = {
|
groups = {
|
||||||
wheel.members = [
|
wheel.members = [ "niten" "reaper" ];
|
||||||
"niten"
|
dns = { members = [ "niten" "reaper" "named" ]; };
|
||||||
"reaper"
|
|
||||||
];
|
|
||||||
dns = {
|
|
||||||
members = [
|
|
||||||
"niten"
|
|
||||||
"reaper"
|
|
||||||
"named"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}"
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -6,13 +6,10 @@ let
|
||||||
primary-ip = "10.0.0.3";
|
primary-ip = "10.0.0.3";
|
||||||
state-dir = "/state";
|
state-dir = "/state";
|
||||||
zigbee2mqtt-statedir = "${state-dir}/services/zigbee2mqtt";
|
zigbee2mqtt-statedir = "${state-dir}/services/zigbee2mqtt";
|
||||||
mosquitto-statedir = "${state-dir}/services/mosquitto";
|
|
||||||
home-assistant-port = 8123;
|
home-assistant-port = 8123;
|
||||||
|
|
||||||
zigbee2mqtt-user = config.systemd.services.zigbee2mqtt.serviceConfig.User;
|
zigbee2mqtt-user = config.systemd.services.zigbee2mqtt.serviceConfig.User;
|
||||||
|
|
||||||
mosquitto-user = config.systemd.services.mosquitto.serviceConfig.User;
|
|
||||||
|
|
||||||
zigbee2mqtt-passwd-file =
|
zigbee2mqtt-passwd-file =
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "zigbee2mqtt-passwd"
|
pkgs.lib.passwd.stablerandom-passwd-file "zigbee2mqtt-passwd"
|
||||||
config.instance.build-seed;
|
config.instance.build-seed;
|
||||||
|
@ -54,31 +51,21 @@ in {
|
||||||
dhcpcd.extraConfig = concatStringsSep "\n" [ "nogateway" ];
|
dhcpcd.extraConfig = concatStringsSep "\n" [ "nogateway" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo.secrets.host-secrets.${hostname} = {
|
fudo.services.mqtt = {
|
||||||
mosquitto-zigbee2mqtt-passwd = {
|
enable = true;
|
||||||
source-file = zigbee2mqtt-passwd-file;
|
state-directory = "${state-dir}/services/mosquitto";
|
||||||
target-file = "/run/mosquitto-secrets/zigbee2mqtt.passwd";
|
private = {
|
||||||
user = mosquitto-user;
|
enable = true;
|
||||||
|
users = {
|
||||||
|
zigbee2mqtt = {
|
||||||
|
password-file = zigbee2mqtt-passwd-file;
|
||||||
|
acl = [ "readwrite #" ];
|
||||||
};
|
};
|
||||||
mosquitto-home-assistant-passwd = {
|
home-assistant = {
|
||||||
source-file = host-passwds.mosquitto-home-assistant;
|
password-file = host-passwds.mosquitto-home-assistant;
|
||||||
target-file = "/run/mosquitto-secrets/home-assistant.passwd";
|
acl = [ "readwrite #" ];
|
||||||
user = mosquitto-user;
|
|
||||||
};
|
};
|
||||||
mosquitto-niten-passwd = {
|
|
||||||
source-file = host-passwds.mosquitto-niten;
|
|
||||||
target-file = "/run/mosquitto-secrets/niten.passwd";
|
|
||||||
user = mosquitto-user;
|
|
||||||
};
|
};
|
||||||
mosquitto-xiaoxuan-passwd = {
|
|
||||||
source-file = host-passwds.mosquitto-xiaoxuan;
|
|
||||||
target-file = "/run/mosquitto-secrets/xiaoxuan.passwd";
|
|
||||||
user = mosquitto-user;
|
|
||||||
};
|
|
||||||
mosquitto-wallfly-passwd = {
|
|
||||||
source-file = host-passwds.mosquitto-wallfly;
|
|
||||||
target-file = "/run/mosquitto-secrets/wallfly.passwd";
|
|
||||||
user = mosquitto-user;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,15 +82,6 @@ in {
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
zigbee2mqtt = {
|
|
||||||
after = [ config.fudo.secrets.secret-target "mosquitto.service" ];
|
|
||||||
restartIfChanged = true;
|
|
||||||
};
|
|
||||||
mosquitto = {
|
|
||||||
after = [ config.fudo.secrets.secret-target ];
|
|
||||||
restartIfChanged = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tmpfiles.rules = [
|
tmpfiles.rules = [
|
||||||
|
@ -114,7 +92,6 @@ in {
|
||||||
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
|
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
|
||||||
"d /state/services 0711 root root - -"
|
"d /state/services 0711 root root - -"
|
||||||
"d ${zigbee2mqtt-statedir} 0700 ${zigbee2mqtt-user} - - -"
|
"d ${zigbee2mqtt-statedir} 0700 ${zigbee2mqtt-user} - - -"
|
||||||
"d ${mosquitto-statedir} 0700 ${mosquitto-user} - - -"
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -149,39 +126,39 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
mosquitto = {
|
# mosquitto = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
dataDir = mosquitto-statedir;
|
# dataDir = mosquitto-statedir;
|
||||||
listeners = [{
|
# listeners = [{
|
||||||
settings.allow_anonymous = false;
|
# settings.allow_anonymous = false;
|
||||||
port = 1883;
|
# port = 1883;
|
||||||
address = "0.0.0.0";
|
# address = "0.0.0.0";
|
||||||
users = {
|
# users = {
|
||||||
zigbee2mqtt = {
|
# zigbee2mqtt = {
|
||||||
passwordFile =
|
# passwordFile =
|
||||||
host-secrets.mosquitto-zigbee2mqtt-passwd.target-file;
|
# host-secrets.mosquitto-zigbee2mqtt-passwd.target-file;
|
||||||
acl = [ "readwrite #" ];
|
# acl = [ "readwrite #" ];
|
||||||
};
|
# };
|
||||||
home-assistant = {
|
# home-assistant = {
|
||||||
passwordFile =
|
# passwordFile =
|
||||||
host-secrets.mosquitto-home-assistant-passwd.target-file;
|
# host-secrets.mosquitto-home-assistant-passwd.target-file;
|
||||||
acl = [ "readwrite #" ];
|
# acl = [ "readwrite #" ];
|
||||||
};
|
# };
|
||||||
# niten = {
|
# niten = {
|
||||||
# passwordFile = host-secrets.mosquitto-niten-passwd.target-file;
|
# passwordFile = host-secrets.mosquitto-niten-passwd.target-file;
|
||||||
# acl = [ "readwrite #" ];
|
# acl = [ "readwrite #" ];
|
||||||
# };
|
# };
|
||||||
# xiaoxuan = {
|
# # xiaoxuan = {
|
||||||
# passwordFile = host-secrets.mosquitto-xiaoxuan-passwd.target-file;
|
# # passwordFile = host-secrets.mosquitto-xiaoxuan-passwd.target-file;
|
||||||
# acl = [ "readwrite #" ];
|
# # acl = [ "readwrite #" ];
|
||||||
|
# # };
|
||||||
|
# # wallfly = {
|
||||||
|
# # passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
|
||||||
|
# # acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
||||||
|
# # };
|
||||||
# };
|
# };
|
||||||
# wallfly = {
|
# }];
|
||||||
# passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
|
|
||||||
# acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
|
||||||
# };
|
# };
|
||||||
};
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
|
|
||||||
zigbee2mqtt = {
|
zigbee2mqtt = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -191,8 +168,11 @@ in {
|
||||||
homeassistant = true;
|
homeassistant = true;
|
||||||
permit_join = true;
|
permit_join = true;
|
||||||
serial.port = "/dev/ttyUSB0";
|
serial.port = "/dev/ttyUSB0";
|
||||||
mqtt = {
|
mqtt = let
|
||||||
server = "mqtt://127.0.0.1:1883";
|
mqttHost = config.fudo.services.mqtt.mqtt-hostname;
|
||||||
|
mqttPort = config.fudo.services.mqtt.private.port;
|
||||||
|
in {
|
||||||
|
server = "mqtt://${mqttHost}:${toString mqttPort}";
|
||||||
user = "zigbee2mqtt";
|
user = "zigbee2mqtt";
|
||||||
password = readFile zigbee2mqtt-passwd-file;
|
password = readFile zigbee2mqtt-passwd-file;
|
||||||
# TODO: could make a yaml file containing password
|
# TODO: could make a yaml file containing password
|
||||||
|
|
|
@ -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 "";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ let
|
||||||
try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
|
try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
config = mkIf has-secret-files
|
config = mkIf has-secret-files (let
|
||||||
(let keytab-file = try-attr hostname config.fudo.secrets.files.host-keytabs;
|
keytab-file =
|
||||||
|
try-attr hostname config.fudo.secrets.files.kerberos.host-keytabs;
|
||||||
in mkIf (keytab-file != null) {
|
in mkIf (keytab-file != null) {
|
||||||
## This doesn't seem to work...timing?
|
## This doesn't seem to work...timing?
|
||||||
# environment.etc."krb5.keytab" = mkIf (keytab-file != null) {
|
# environment.etc."krb5.keytab" = mkIf (keytab-file != null) {
|
||||||
|
@ -19,6 +20,22 @@ in {
|
||||||
# mode = "0400";
|
# mode = "0400";
|
||||||
# };
|
# };
|
||||||
|
|
||||||
|
krb5 = {
|
||||||
|
domain_realm = let
|
||||||
|
krbDoms = filterAttrs (_: domCfg: domCfg.gssapi-realm != null)
|
||||||
|
config.fudo.domains;
|
||||||
|
domClauses = dom: domCfg: [
|
||||||
|
(nameValuePair dom domCfg.gssapi-realm)
|
||||||
|
(nameValuePair ".${dom}" domCfg.gssapi-realm)
|
||||||
|
];
|
||||||
|
concatMapAttrs = f: lst:
|
||||||
|
listToAttrs (concatMap (i: i) (mapAttrsToList f lst));
|
||||||
|
in concatMapAttrs domClauses krbDoms;
|
||||||
|
|
||||||
|
libdefaults.default_etypes =
|
||||||
|
"aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96";
|
||||||
|
};
|
||||||
|
|
||||||
systemd = let
|
systemd = let
|
||||||
host-keytab =
|
host-keytab =
|
||||||
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
|
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
|
||||||
|
|
|
@ -8,16 +8,17 @@ let
|
||||||
has-secret-files = hasAttr "files" config.fudo.secrets;
|
has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
config = mkIf has-secret-files
|
config = mkIf has-secret-files (let
|
||||||
(let
|
|
||||||
host-keypairs =
|
host-keypairs =
|
||||||
if (hasAttr hostname config.fudo.secrets.files.host-ssh-keypairs) then
|
if (hasAttr hostname config.fudo.secrets.files.ssh.host-keypairs) then
|
||||||
config.fudo.secrets.files.host-ssh-keypairs.${hostname}
|
config.fudo.secrets.files.ssh.host-keypairs.${hostname}
|
||||||
else [];
|
else
|
||||||
|
[ ];
|
||||||
|
|
||||||
in {
|
in {
|
||||||
fudo = let
|
fudo = let
|
||||||
sshfp-filename = host: keypair: "ssh-${host}-${keypair.key-type}.sshfp-record";
|
sshfp-filename = host: keypair:
|
||||||
|
"ssh-${host}-${keypair.key-type}.sshfp-record";
|
||||||
|
|
||||||
dns-sshfp-records = host: keypair:
|
dns-sshfp-records = host: keypair:
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
|
@ -27,36 +28,33 @@ in {
|
||||||
|
|
||||||
buildInputs = with pkgs; [ openssh ];
|
buildInputs = with pkgs; [ openssh ];
|
||||||
|
|
||||||
installPhase =
|
installPhase = ''
|
||||||
"ssh-keygen -r REMOVEME -f \"${keypair.public-key}\" | sed 's/^REMOVEME IN SSHFP //' > $out";
|
ssh-keygen -r REMOVEME -f "${keypair.public-key}" | sed 's/^REMOVEME IN SSHFP //' > $out'';
|
||||||
};
|
};
|
||||||
|
|
||||||
host-cfg = config.fudo.hosts.${hostname};
|
host-cfg = config.fudo.hosts.${hostname};
|
||||||
in {
|
in {
|
||||||
secrets.host-secrets.${hostname} = listToAttrs
|
secrets.host-secrets.${hostname} = listToAttrs (map (keypair:
|
||||||
(map
|
nameValuePair "host-${keypair.key-type}-private-key" {
|
||||||
(keypair: nameValuePair "host-${keypair.key-type}-private-key" {
|
|
||||||
source-file = keypair.private-key;
|
source-file = keypair.private-key;
|
||||||
target-file = "/run/openssh/private/host-${keypair.key-type}-private-key";
|
target-file =
|
||||||
|
"/run/openssh/private/host-${keypair.key-type}-private-key";
|
||||||
user = "root";
|
user = "root";
|
||||||
})
|
}) host-keypairs);
|
||||||
host-keypairs);
|
|
||||||
|
|
||||||
hosts = mkIf (hasAttr "files" config.fudo.secrets)
|
hosts = mkIf (hasAttr "files" config.fudo.secrets) (mapAttrs
|
||||||
(mapAttrs (hostname: keypairs: {
|
(hostname: keypairs: {
|
||||||
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
|
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
|
||||||
ssh-fingerprints = concatMap (keypair:
|
ssh-fingerprints = concatMap (keypair:
|
||||||
let
|
let fingerprint-derivation = dns-sshfp-records hostname keypair;
|
||||||
fingerprint-derivation = dns-sshfp-records hostname keypair;
|
|
||||||
in read-lines "${fingerprint-derivation}") keypairs;
|
in read-lines "${fingerprint-derivation}") keypairs;
|
||||||
}) config.fudo.secrets.files.host-ssh-keypairs);
|
}) config.fudo.secrets.files.ssh.host-keypairs);
|
||||||
};
|
};
|
||||||
|
|
||||||
services.openssh.hostKeys = let
|
services.openssh.hostKeys =
|
||||||
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
let host-secrets = config.fudo.secrets.host-secrets."${hostname}";
|
||||||
in map (keypair: {
|
in map (keypair: {
|
||||||
path =
|
path = host-secrets."host-${keypair.key-type}-private-key".target-file;
|
||||||
host-secrets."host-${keypair.key-type}-private-key".target-file;
|
|
||||||
type = keypair.key-type;
|
type = keypair.key-type;
|
||||||
}) host-keypairs;
|
}) host-keypairs;
|
||||||
});
|
});
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -6,6 +6,18 @@ let
|
||||||
|
|
||||||
cfg = config.fudo.services.dns;
|
cfg = config.fudo.services.dns;
|
||||||
|
|
||||||
|
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
|
||||||
|
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
domain = config.fudo.domains.${domain-name};
|
||||||
|
primary-nameserver = domain.primary-nameserver;
|
||||||
|
primary-nameserver-ip = pkgs.lib.network.host-ipv4 config primary-nameserver;
|
||||||
|
primary-nameserver-fqdn = "${primary-nameserver}.${domain-name}";
|
||||||
|
|
||||||
|
is-primary-nameserver = primary-nameserver == hostname;
|
||||||
|
|
||||||
|
zoneKeySecret = zone: "${zone}-ksk";
|
||||||
|
|
||||||
nameserverOpts = { name, ... }: {
|
nameserverOpts = { name, ... }: {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
|
@ -39,8 +51,8 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
zoneOpts = { name, ... }: let
|
zoneOpts = { name, ... }:
|
||||||
zone-name = name;
|
let zone-name = name;
|
||||||
in {
|
in {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
|
@ -51,7 +63,8 @@ let
|
||||||
|
|
||||||
default-host = mkOption {
|
default-host = mkOption {
|
||||||
type = nullOr str;
|
type = nullOr str;
|
||||||
description = "IP which will respond to requests for the base domain.";
|
description =
|
||||||
|
"IP which will respond to requests for the base domain.";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,11 +79,31 @@ let
|
||||||
description = "Domain which this zone serves.";
|
description = "Domain which this zone serves.";
|
||||||
default = zone-name;
|
default = zone-name;
|
||||||
};
|
};
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pthru = obj:
|
ksk = mkOption {
|
||||||
builtins.trace "TRACE: ${ obj }" obj;
|
type = nullOr (submodule {
|
||||||
|
options = {
|
||||||
|
private-key = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "KSK private key.";
|
||||||
|
};
|
||||||
|
public-key = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "KSK public key.";
|
||||||
|
};
|
||||||
|
ds = mkOption {
|
||||||
|
type = path;
|
||||||
|
description = "KSK ds record.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
description =
|
||||||
|
"Location of the zone-signing private & public keys and DS record.";
|
||||||
|
default =
|
||||||
|
toplevel.config.fudo.secrets.files.dns.key-signing-keys."${zone-name}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.services.dns = with types; {
|
options.fudo.services.dns = with types; {
|
||||||
|
@ -82,13 +115,20 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config.fudo = {
|
config.fudo = {
|
||||||
zones = mapAttrs (zone-name: zone-cfg: let
|
secrets.host-secrets."${hostname}" = mkIf is-primary-nameserver (mapAttrs'
|
||||||
|
(zone: zone-cfg:
|
||||||
|
nameValuePair (zoneKeySecret zone) {
|
||||||
|
source-file = zone-cfg.ksk.private-key;
|
||||||
|
target-file = "/run/nsd/${baseNameOf zone-cfg.ksk.private-key}";
|
||||||
|
user = config.fudo.nsd.user;
|
||||||
|
}) cfg.zones);
|
||||||
|
|
||||||
|
zones = mapAttrs (zone-name: zone-cfg:
|
||||||
|
let
|
||||||
domain-name = zone-cfg.domain;
|
domain-name = zone-cfg.domain;
|
||||||
domain = config.fudo.domains.${domain-name};
|
domain = config.fudo.domains.${domain-name};
|
||||||
|
|
||||||
make-srv-record = port: host: {
|
make-srv-record = port: host: { inherit port host; };
|
||||||
inherit port host;
|
|
||||||
};
|
|
||||||
|
|
||||||
served-domain = domain.primary-nameserver != null;
|
served-domain = domain.primary-nameserver != null;
|
||||||
|
|
||||||
|
@ -96,8 +136,8 @@ in {
|
||||||
|
|
||||||
is-primary-nameserver = hostname == primary-nameserver;
|
is-primary-nameserver = hostname == primary-nameserver;
|
||||||
|
|
||||||
internal-nameserver-hostnames =
|
internal-nameserver-hostnames = [ domain.primary-nameserver ]
|
||||||
[domain.primary-nameserver] ++ domain.secondary-nameservers;
|
++ domain.secondary-nameservers;
|
||||||
|
|
||||||
get-host-deets = description: hostname: {
|
get-host-deets = description: hostname: {
|
||||||
ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
|
ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
|
||||||
|
@ -105,7 +145,8 @@ in {
|
||||||
description = description;
|
description = description;
|
||||||
};
|
};
|
||||||
|
|
||||||
get-ns-deets = hostname: let
|
get-ns-deets = hostname:
|
||||||
|
let
|
||||||
host-domain = config.fudo.hosts.${hostname}.domain;
|
host-domain = config.fudo.hosts.${hostname}.domain;
|
||||||
desc = "${domain-name} nameserver ${hostname}.${host-domain}.";
|
desc = "${domain-name} nameserver ${hostname}.${host-domain}.";
|
||||||
in get-host-deets desc hostname;
|
in get-host-deets desc hostname;
|
||||||
|
@ -115,13 +156,11 @@ in {
|
||||||
in internal-nameservers ++ zone-cfg.external-nameservers;
|
in internal-nameservers ++ zone-cfg.external-nameservers;
|
||||||
|
|
||||||
has-auth-hostname = ns-host: ns-opts:
|
has-auth-hostname = ns-host: ns-opts:
|
||||||
(hasAttr "authoritative-hostname" ns-opts) &&
|
(hasAttr "authoritative-hostname" ns-opts)
|
||||||
(ns-opts.authoritative-hostname != null);
|
&& (ns-opts.authoritative-hostname != null);
|
||||||
|
|
||||||
all-nameservers = listToAttrs
|
all-nameservers = listToAttrs
|
||||||
(imap1
|
(imap1 (i: nsOpts: nameValuePair "ns${toString i}" nsOpts)
|
||||||
(i: nsOpts:
|
|
||||||
nameValuePair "ns${toString i}" nsOpts)
|
|
||||||
nameserver-deets);
|
nameserver-deets);
|
||||||
|
|
||||||
nameserver-aliases =
|
nameserver-aliases =
|
||||||
|
@ -134,49 +173,51 @@ in {
|
||||||
all-nameservers);
|
all-nameservers);
|
||||||
|
|
||||||
dns-srv-records = let
|
dns-srv-records = let
|
||||||
nameserver-srv-records = mapAttrsToList
|
nameserver-srv-records = mapAttrsToList (hostname: hostOpts:
|
||||||
(hostname: hostOpts: let
|
let
|
||||||
target-host = if (has-auth-hostname hostname hostOpts) then
|
target-host = if (has-auth-hostname hostname hostOpts) then
|
||||||
"${hostOpts.authoritative-hostname}" else
|
"${hostOpts.authoritative-hostname}"
|
||||||
|
else
|
||||||
"${hostname}.${domain-name}";
|
"${hostname}.${domain-name}";
|
||||||
in make-srv-record 53 target-host)
|
in make-srv-record 53 target-host) all-nameservers;
|
||||||
all-nameservers;
|
|
||||||
in {
|
in {
|
||||||
tcp.domain = nameserver-srv-records;
|
tcp.domain = nameserver-srv-records;
|
||||||
udp.domain = nameserver-srv-records;
|
udp.domain = nameserver-srv-records;
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO: move this to a mail service
|
# # TODO: move this to a mail service
|
||||||
mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
|
# mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
|
||||||
tcp = let
|
# tcp = let
|
||||||
mailserver-domain = config.fudo.hosts.${domain.primary-mailserver}.domain;
|
# mailserver-domain =
|
||||||
fqdn = "mail.${mailserver-domain}";
|
# config.fudo.hosts.${domain.primary-mailserver}.domain;
|
||||||
in {
|
# fqdn = "mail.${mailserver-domain}";
|
||||||
smtp = [(make-srv-record 25 fqdn)];
|
# in {
|
||||||
submission = [(make-srv-record 587 fqdn)];
|
# smtp = [ (make-srv-record 25 fqdn) ];
|
||||||
imap = [(make-srv-record 143 fqdn)];
|
# submission = [ (make-srv-record 587 fqdn) ];
|
||||||
imaps = [(make-srv-record 993 fqdn)];
|
# imap = [ (make-srv-record 143 fqdn) ];
|
||||||
pop3 = [(make-srv-record 110 fqdn)];
|
# imaps = [ (make-srv-record 993 fqdn) ];
|
||||||
pop3s = [(make-srv-record 995 fqdn)];
|
# pop3 = [ (make-srv-record 110 fqdn) ];
|
||||||
};
|
# pop3s = [ (make-srv-record 995 fqdn) ];
|
||||||
};
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
in {
|
in {
|
||||||
gssapi-realm = domain.gssapi-realm;
|
gssapi-realm = domain.gssapi-realm;
|
||||||
|
|
||||||
hosts = nameserver-hosts // {
|
hosts = nameserver-hosts // {
|
||||||
mail = mkIf (domain.primary-nameserver != null) (let
|
mail = mkIf (domain.primary-nameserver != null) (let
|
||||||
mailserver-deets = host: let
|
mailserver-deets = host:
|
||||||
host-domain = config.fudo.hosts.${host}.domain;
|
let host-domain = config.fudo.hosts.${host}.domain;
|
||||||
in get-host-deets "Primary ${domain-name} mailserver ${host}.${host-domain}." host;
|
in get-host-deets
|
||||||
|
"Primary ${domain-name} mailserver ${host}.${host-domain}." host;
|
||||||
in mailserver-deets domain.primary-nameserver);
|
in mailserver-deets domain.primary-nameserver);
|
||||||
};
|
};
|
||||||
|
|
||||||
aliases = nameserver-aliases;
|
aliases = nameserver-aliases;
|
||||||
|
|
||||||
mx = optional (domain.primary-mailserver != null)
|
mx = optional (domain.primary-mailserver != null) (let
|
||||||
(let
|
mail-domain-name =
|
||||||
mail-domain-name = config.fudo.hosts.${domain.primary-mailserver}.domain;
|
config.fudo.hosts.${domain.primary-mailserver}.domain;
|
||||||
in "mail.${mail-domain-name}");
|
in "mail.${mail-domain-name}");
|
||||||
|
|
||||||
dmarc-report-address = "dmarc-report@${domain-name}";
|
dmarc-report-address = "dmarc-report@${domain-name}";
|
||||||
|
@ -187,18 +228,15 @@ in {
|
||||||
(attrNames nameserver-hosts);
|
(attrNames nameserver-hosts);
|
||||||
in internal ++ direct-external;
|
in internal ++ direct-external;
|
||||||
|
|
||||||
srv-records = dns-srv-records // mail-srv-records;
|
srv-records = dns-srv-records; # // mail-srv-records;
|
||||||
|
|
||||||
|
verbatim-dns-records = mkIf (zone-cfg.ksk != null) [
|
||||||
|
(readFile zone-cfg.ksk.public-key)
|
||||||
|
(readFile zone-cfg.ksk.ds)
|
||||||
|
];
|
||||||
}) cfg.zones;
|
}) cfg.zones;
|
||||||
|
|
||||||
dns = let
|
dns = {
|
||||||
domain-name = config.instance.local-domain;
|
|
||||||
domain = config.fudo.domains.${domain-name};
|
|
||||||
primary-nameserver = domain.primary-nameserver;
|
|
||||||
primary-nameserver-ip = pkgs.lib.network.host-ipv4 config primary-nameserver;
|
|
||||||
primary-nameserver-fqdn = "${primary-nameserver}.${domain-name}";
|
|
||||||
|
|
||||||
is-primary-nameserver = primary-nameserver == hostname;
|
|
||||||
in {
|
|
||||||
enable = is-primary-nameserver;
|
enable = is-primary-nameserver;
|
||||||
|
|
||||||
identity = "${hostname}.${domain-name}";
|
identity = "${hostname}.${domain-name}";
|
||||||
|
@ -207,9 +245,9 @@ in {
|
||||||
(pkgs.lib.network.host-ips config hostname);
|
(pkgs.lib.network.host-ips config hostname);
|
||||||
|
|
||||||
domains = mapAttrs' (zone-name: zone-cfg:
|
domains = mapAttrs' (zone-name: zone-cfg:
|
||||||
nameValuePair zone-cfg.domain
|
nameValuePair zone-cfg.domain {
|
||||||
{
|
dnssec = zone-cfg.ksk != null;
|
||||||
dnssec = true;
|
ksk.key-file = host-secrets."${zoneKeySecret zone-name}".target-file;
|
||||||
zone-definition = config.fudo.zones.${zone-name};
|
zone-definition = config.fudo.zones.${zone-name};
|
||||||
}) cfg.zones;
|
}) cfg.zones;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with pkgs.lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
domain-name = config.fudo.services.auth.domain;
|
domain-name = config.fudo.services.auth.domain;
|
||||||
domain = config.fudo.domains.${domain-name};
|
domain = config.fudo.domains.${domain-name};
|
||||||
|
|
||||||
|
realm = domain.gssapi-realm;
|
||||||
|
|
||||||
zone-name = domain.zone;
|
zone-name = domain.zone;
|
||||||
|
|
||||||
ldap-server = elem hostname domain.ldap-servers;
|
ldap-server = elem hostname domain.ldap-servers;
|
||||||
|
@ -19,6 +21,11 @@ let
|
||||||
|
|
||||||
cfg = config.fudo.services.auth;
|
cfg = config.fudo.services.auth;
|
||||||
|
|
||||||
|
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
|
||||||
|
|
||||||
|
krb-user = config.fudo.auth.kerberos.user;
|
||||||
|
krb-group = config.fudo.auth.kerberos.group;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.services.auth = with types; {
|
options.fudo.services.auth = with types; {
|
||||||
domain = mkOption {
|
domain = mkOption {
|
||||||
|
@ -30,20 +37,23 @@ in {
|
||||||
ldap = {
|
ldap = {
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Fully-qualified (and public-addressable) domain name of this host.";
|
description =
|
||||||
|
"Fully-qualified (and public-addressable) domain name of this host.";
|
||||||
default = config.instance.host-fqdn;
|
default = config.instance.host-fqdn;
|
||||||
};
|
};
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Directory at which to store peristent ldap-related data.";
|
description =
|
||||||
|
"Directory at which to store peristent ldap-related data.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
kerberos = {
|
kerberos = {
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Fully-qualified (and public-addressable) domain name of this host.";
|
description =
|
||||||
|
"Fully-qualified (and public-addressable) domain name of this host.";
|
||||||
default = config.instance.host-fqdn;
|
default = config.instance.host-fqdn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,15 +66,64 @@ in {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path (on the build server) to the KDC master key file.";
|
description = "Path (on the build server) to the KDC master key file.";
|
||||||
};
|
};
|
||||||
|
|
||||||
ipropd-keytab = mkOption {
|
|
||||||
type = nullOr str;
|
|
||||||
description = "ipropd keytab for kerberos database propagation.";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
systemd = {
|
||||||
|
tmpfiles.rules = mkIf (kerberos-master || kerberos-slave) [
|
||||||
|
"d ${cfg.kerberos.state-directory} 0700 ${krb-user} ${krb-group} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
paths.heimdal-kdc-initialize = mkIf kerberos-master {
|
||||||
|
wantedBy = [ "heimdal-kdc.service" ];
|
||||||
|
pathConfig = {
|
||||||
|
PathModified = host-secrets.kdc-principals.target-file;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
heimdal-kdc-initialize = mkIf (kerberos-master || kerberos-slave) {
|
||||||
|
requires = [
|
||||||
|
host-secrets.kdc-principals.service
|
||||||
|
host-secrets.realm-master-key.service
|
||||||
|
];
|
||||||
|
description = "Initialize and update the Heimdal KDC database.";
|
||||||
|
path = with pkgs; [ kdcMergePrincipals coreutils ];
|
||||||
|
serviceConfig = {
|
||||||
|
User = krb-user;
|
||||||
|
Group = krb-group;
|
||||||
|
ExecStart = let
|
||||||
|
db = config.fudo.auth.kerberos.kdc.database;
|
||||||
|
principals = host-secrets.kdc-principals.target-file;
|
||||||
|
master-key = host-secrets.realm-master-key.target-file;
|
||||||
|
init-db-cmd = concatStringsSep " " [
|
||||||
|
"${pkgs.kdcMergePrincipals}/bin/kdc-merge-principals"
|
||||||
|
"--create"
|
||||||
|
"--database=${db}"
|
||||||
|
"--principals=${principals}"
|
||||||
|
"--key=${master-key}"
|
||||||
|
"--realm=${realm}"
|
||||||
|
"--verbose"
|
||||||
|
];
|
||||||
|
in pkgs.writeShellScript "heimdal-kdc-initialize.sh" ''
|
||||||
|
${init-db-cmd}
|
||||||
|
chown ${krb-user}:${krb-group} ${db}
|
||||||
|
chmod 0700 ${db}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
heimdal-kdc = mkIf kerberos-master {
|
||||||
|
requires = [ "heimdal-kdc-initialize.service" ];
|
||||||
|
after = [ "heimdal-kdc-initialize.service" ];
|
||||||
|
};
|
||||||
|
heimdal-kdc-secondary = mkIf kerberos-slave {
|
||||||
|
requires = [ "heimdal-kdc-initialize.service" ];
|
||||||
|
after = [ "heimdal-kdc-initialize.service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fudo = {
|
fudo = {
|
||||||
acme.host-domains.${hostname} = mkIf (ldap-server) {
|
acme.host-domains.${hostname} = mkIf (ldap-server) {
|
||||||
${cfg.ldap.hostname}.local-copies.openldap = {
|
${cfg.ldap.hostname}.local-copies.openldap = {
|
||||||
|
@ -73,9 +132,66 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
secrets.host-secrets."${hostname}" = let
|
||||||
|
realm-key =
|
||||||
|
config.fudo.secrets.files.kerberos.realm-master-keys."${realm}";
|
||||||
|
in {
|
||||||
|
realm-master-key = mkIf (kerberos-master || kerberos-slave) {
|
||||||
|
source-file = realm-key;
|
||||||
|
target-file = "/run/kdc/realm.key";
|
||||||
|
user = krb-user;
|
||||||
|
group = krb-group;
|
||||||
|
};
|
||||||
|
|
||||||
|
kdc-principals = mkIf (kerberos-master || kerberos-slave) {
|
||||||
|
source-file =
|
||||||
|
config.fudo.secrets.files.kerberos.realm-principals."${realm}";
|
||||||
|
target-file = "/run/kdc/realm.principals";
|
||||||
|
user = krb-user;
|
||||||
|
group = krb-group;
|
||||||
|
};
|
||||||
|
kadmind-keytab = mkIf kerberos-master {
|
||||||
|
source-file = extractFudoKeytab {
|
||||||
|
inherit realm;
|
||||||
|
principals = [ "kadmin/admin" ];
|
||||||
|
};
|
||||||
|
target-file = "/run/kdc/kadmind.keytab";
|
||||||
|
user = krb-user;
|
||||||
|
group = krb-group;
|
||||||
|
};
|
||||||
|
kpasswdd-keytab = mkIf kerberos-master {
|
||||||
|
source-file = extractFudoKeytab {
|
||||||
|
inherit realm;
|
||||||
|
principals = [ "kadmin/changepw" ];
|
||||||
|
};
|
||||||
|
target-file = "/run/kdc/kpasswdd.keytab";
|
||||||
|
user = krb-user;
|
||||||
|
group = krb-group;
|
||||||
|
};
|
||||||
|
hprop-keytab =
|
||||||
|
mkIf (kerberos-master && (domain.kerberos-slaves != [ ])) {
|
||||||
|
source-file = extractFudoKeytab {
|
||||||
|
inherit realm;
|
||||||
|
principals = [ "kadmin/hprop" ];
|
||||||
|
};
|
||||||
|
target-file = "/run/kdc/hprop.keytab";
|
||||||
|
user = krb-user;
|
||||||
|
group = krb-group;
|
||||||
|
};
|
||||||
|
|
||||||
|
hpropd-keytab = mkIf kerberos-slave {
|
||||||
|
source-file = extractFudoHostKeytab {
|
||||||
|
inherit hostname realm;
|
||||||
|
services = [ "hprop" ];
|
||||||
|
};
|
||||||
|
target-file = "/run/kdc/hpropd.keytab";
|
||||||
|
user = krb-user;
|
||||||
|
group = krb-group;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
auth = {
|
auth = {
|
||||||
ldap-server = mkIf (ldap-server)
|
ldap-server = mkIf ldap-server (let
|
||||||
(let
|
|
||||||
ldap-cert-copy =
|
ldap-cert-copy =
|
||||||
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
|
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
|
||||||
in {
|
in {
|
||||||
|
@ -98,27 +214,28 @@ in {
|
||||||
ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
|
ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
kerberos = {
|
||||||
|
inherit realm;
|
||||||
kdc = mkIf (kerberos-master || kerberos-slave) {
|
kdc = mkIf (kerberos-master || kerberos-slave) {
|
||||||
enable = true;
|
|
||||||
realm = domain.gssapi-realm;
|
|
||||||
bind-addresses =
|
|
||||||
(pkgs.lib.network.host-ips config hostname) ++
|
|
||||||
[ "127.0.0.1" ] ++ (optional config.networking.enableIPv6 "::1");
|
|
||||||
state-directory = cfg.kerberos.state-directory;
|
state-directory = cfg.kerberos.state-directory;
|
||||||
master-key-file = cfg.kerberos.master-key-file;
|
master-key-file = host-secrets.realm-master-key.target-file;
|
||||||
master-config = mkIf (kerberos-master) {
|
primary = mkIf kerberos-master {
|
||||||
|
enable = true;
|
||||||
acl = let
|
acl = let
|
||||||
admin-entries = genAttrs config.instance.local-admins
|
adminEntries = genAttrs config.instance.local-admins
|
||||||
(admin: {
|
(admin: { perms = [ "add" "change-password" "list" ]; });
|
||||||
perms = [ "add" "change-password" "list" ];
|
in adminEntries // { "*/root".perms = [ "all" ]; };
|
||||||
});
|
secondary-servers = map getHostFqdn domain.kerberos-slaves;
|
||||||
in admin-entries // {
|
keytabs = {
|
||||||
"*/root".perms = [ "all" ];
|
kadmind = host-secrets.kadmind-keytab.target-file;
|
||||||
|
kpasswdd = host-secrets.kpasswdd-keytab.target-file;
|
||||||
|
hprop = host-secrets.hprop-keytab.target-file;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
slave-config = mkIf (kerberos-slave) {
|
secondary = mkIf kerberos-slave {
|
||||||
master-host = domain.kerberos-master;
|
enable = true;
|
||||||
ipropd-keytab = cfg.kerberos.ipropd-keytab;
|
keytabs.hpropd = host-secrets.hpropd-keytab.target-file;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -129,19 +246,20 @@ in {
|
||||||
host = hostname;
|
host = hostname;
|
||||||
};
|
};
|
||||||
|
|
||||||
get-fqdn = host:
|
get-fqdn = host: "${host}.${config.fudo.hosts.${host}.domain}";
|
||||||
"${host}.${config.fudo.hosts.${host}.domain}";
|
|
||||||
|
|
||||||
kerberos-master-hosts = optional (kerberized-domain)
|
kerberos-master-hosts =
|
||||||
domain.kerberos-master;
|
optional (kerberized-domain) domain.kerberos-master;
|
||||||
|
|
||||||
kerberos-servers = map get-fqdn
|
kerberos-servers =
|
||||||
(kerberos-master-hosts ++ domain.kerberos-slaves);
|
map get-fqdn (kerberos-master-hosts ++ domain.kerberos-slaves);
|
||||||
|
|
||||||
kerberos-masters = map get-fqdn kerberos-master-hosts;
|
kerberos-masters = map get-fqdn kerberos-master-hosts;
|
||||||
|
|
||||||
ldap-servers = map get-fqdn domain.ldap-servers;
|
ldap-servers = map get-fqdn domain.ldap-servers;
|
||||||
in {
|
in {
|
||||||
|
gssapi-realm = realm;
|
||||||
|
|
||||||
srv-records = {
|
srv-records = {
|
||||||
tcp = {
|
tcp = {
|
||||||
kerberos = map (make-srv-record 88) kerberos-servers;
|
kerberos = map (make-srv-record 88) kerberos-servers;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -13,8 +13,7 @@ let
|
||||||
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||||
|
|
||||||
postgresEnabled = domain.postgresql-server == hostname;
|
postgresEnabled = domain.postgresql-server == hostname;
|
||||||
publicNetwork = let
|
publicNetwork = let site-name = config.fudo.hosts.${hostname}.site;
|
||||||
site-name = config.fudo.hosts.${hostname}.site;
|
|
||||||
in config.fudo.sites.${site-name}.local-gateway == null;
|
in config.fudo.sites.${site-name}.local-gateway == null;
|
||||||
isPostgresHost = hostname == domain.postgresql-server;
|
isPostgresHost = hostname == domain.postgresql-server;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
keytab = mkOption {
|
keytab = mkOption {
|
||||||
type = str;
|
type = nullOr path;
|
||||||
description = "Keytab for PostgreSQL.";
|
description = "Keytab for PostgreSQL.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -49,7 +48,8 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
secrets.host-secrets.${hostname}.postgres-keytab = mkIf (cfg.keytab != null) {
|
secrets.host-secrets.${hostname}.postgres-keytab =
|
||||||
|
mkIf (cfg.keytab != null) {
|
||||||
source-file = cfg.keytab;
|
source-file = cfg.keytab;
|
||||||
target-file = "/run/postgresql/postgres.keytab";
|
target-file = "/run/postgresql/postgres.keytab";
|
||||||
user = postgresUser;
|
user = postgresUser;
|
||||||
|
@ -60,7 +60,8 @@ in {
|
||||||
|
|
||||||
postgresql = mkIf isPostgresHost (let
|
postgresql = mkIf isPostgresHost (let
|
||||||
ssl-config = optionalAttrs publicNetwork (let
|
ssl-config = optionalAttrs publicNetwork (let
|
||||||
cert-copy = acme-copies.${postgresql-hostname}.local-copies.postgresql;
|
cert-copy =
|
||||||
|
acme-copies.${postgresql-hostname}.local-copies.postgresql;
|
||||||
in {
|
in {
|
||||||
ssl-certificate = mkIf publicNetwork cert-copy.full-certificate;
|
ssl-certificate = mkIf publicNetwork cert-copy.full-certificate;
|
||||||
ssl-private-key = mkIf publicNetwork cert-copy.private-key;
|
ssl-private-key = mkIf publicNetwork cert-copy.private-key;
|
||||||
|
@ -68,7 +69,8 @@ in {
|
||||||
});
|
});
|
||||||
in {
|
in {
|
||||||
enable = true;
|
enable = true;
|
||||||
keytab = mkIf (cfg.keytab != null) host-secrets.postgres-keytab.target-file;
|
keytab = mkIf (cfg.keytab != null)
|
||||||
|
"${host-secrets.postgres-keytab.target-file}";
|
||||||
local-networks = config.instance.local-networks;
|
local-networks = config.instance.local-networks;
|
||||||
state-directory = cfg.state-directory;
|
state-directory = cfg.state-directory;
|
||||||
required-services = [ config.fudo.secrets.secret-target ];
|
required-services = [ config.fudo.secrets.secret-target ];
|
||||||
|
|
|
@ -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}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -22,25 +22,6 @@ let
|
||||||
in {
|
in {
|
||||||
options.fudo.services.wallfly-presence = with types; {
|
options.fudo.services.wallfly-presence = with types; {
|
||||||
enable = mkEnableOption "Enable WallFly presence for the local site.";
|
enable = mkEnableOption "Enable WallFly presence for the local site.";
|
||||||
|
|
||||||
mqtt = {
|
|
||||||
broker-host = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Host to serve as local MQTT broker.";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = port;
|
|
||||||
description = "Port on which to listen for MQTT connections.";
|
|
||||||
default = 1884;
|
|
||||||
};
|
|
||||||
|
|
||||||
listen-address = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Address on which to listen for MQTT connections.";
|
|
||||||
default = "0.0.0.0";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
@ -50,42 +31,30 @@ in {
|
||||||
source-file = userOpts.password-file;
|
source-file = userOpts.password-file;
|
||||||
target-file = "/run/wallfly-${username}/passwd";
|
target-file = "/run/wallfly-${username}/passwd";
|
||||||
user = username;
|
user = username;
|
||||||
}) local-user-cfg) // (optionalAttrs is-mqtt-broker (mapAttrs'
|
}) local-user-cfg);
|
||||||
(username: userOpts:
|
|
||||||
nameValuePair "wallfly-server-${username}-passwd" {
|
|
||||||
source-file = userOpts.password-file;
|
|
||||||
target-file = "/run/wallfly-mqtt/${username}.passwd";
|
|
||||||
user = config.systemd.services.mosquitto.serviceConfig.User;
|
|
||||||
}) user-cfg));
|
|
||||||
|
|
||||||
zones."${domain-name}" = {
|
|
||||||
aliases.mqtt = "${mqtt-broker}.${domain-name}.";
|
|
||||||
};
|
|
||||||
|
|
||||||
wallfly = {
|
wallfly = {
|
||||||
enable = true;
|
enable = true;
|
||||||
mqtt = {
|
mqtt = let
|
||||||
broker-uri =
|
mqtt-hostname = config.fudo.services.mqtt.mqtt-hostname;
|
||||||
"tcp://${mqtt-broker}.${domain-name}:${toString cfg.mqtt.port}";
|
mqtt-port = config.fudo.services.mqtt.private.port;
|
||||||
|
in {
|
||||||
|
broker-uri = "tcp://${mqtt-hostname}:${toString mqtt-port}";
|
||||||
username = "wallfly-$USER";
|
username = "wallfly-$USER";
|
||||||
password-file = "/run/wallfly-$USER/passwd";
|
password-file = "/run/wallfly-$USER/passwd";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
services.mqtt = {
|
||||||
mosquitto = mkIf (is-mqtt-broker) {
|
enable = true;
|
||||||
|
private = {
|
||||||
enable = true;
|
enable = true;
|
||||||
listeners = [{
|
|
||||||
settings.allow_anonymous = false;
|
|
||||||
port = cfg.mqtt.port;
|
|
||||||
address = cfg.mqtt.listen-address;
|
|
||||||
users = mapAttrs' (username: userOpts:
|
users = mapAttrs' (username: userOpts:
|
||||||
nameValuePair "wallfly-${username}" {
|
nameValuePair "wallfly-${username}" {
|
||||||
passwordFile = "/run/wallfly-mqtt/${username}.passwd";
|
password-file = userOpts.password-file;
|
||||||
acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
||||||
}) user-cfg;
|
}) user-cfg;
|
||||||
}];
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
];
|
];
|
||||||
|
|
|
@ -3,9 +3,37 @@
|
||||||
with lib;
|
with lib;
|
||||||
let local-domain = "sea.fudo.org";
|
let local-domain = "sea.fudo.org";
|
||||||
in {
|
in {
|
||||||
fudo.services.wallfly-presence = {
|
fudo.services = {
|
||||||
|
mqtt = {
|
||||||
enable = true;
|
enable = true;
|
||||||
mqtt.broker-host = "wormhole0";
|
host = "wormhole0";
|
||||||
|
};
|
||||||
|
|
||||||
|
wallfly-presence.enable = true;
|
||||||
|
|
||||||
|
tattler = let snooper-host = "wormhole0";
|
||||||
|
in {
|
||||||
|
enable = true;
|
||||||
|
verbose = true;
|
||||||
|
event-topics = [ "suanni/events/motion" ];
|
||||||
|
inherit snooper-host;
|
||||||
|
};
|
||||||
|
|
||||||
|
suanni = let
|
||||||
|
listener = "nostromo";
|
||||||
|
objectifier = "lambda";
|
||||||
|
in {
|
||||||
|
enable = true;
|
||||||
|
event-listener.host = listener;
|
||||||
|
objectifier.host = objectifier;
|
||||||
|
synology = {
|
||||||
|
host = "cargo.sea.fudo.org";
|
||||||
|
port = 5001;
|
||||||
|
username = "suanni";
|
||||||
|
password-file =
|
||||||
|
config.fudo.secrets.files.service-passwords."${listener}".suanni-synology;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems = {
|
fileSystems = {
|
||||||
|
@ -165,7 +193,6 @@ in {
|
||||||
DefaultDependencies = false;
|
DefaultDependencies = false;
|
||||||
ConditionPathExists =
|
ConditionPathExists =
|
||||||
[ "|!/run/gssproxy.pid" "|!/proc/net/rpc/use-gss-proxy" ];
|
[ "|!/run/gssproxy.pid" "|!/proc/net/rpc/use-gss-proxy" ];
|
||||||
Restart = "always";
|
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "forking";
|
Type = "forking";
|
||||||
|
|
|
@ -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
3680
flake.lock
File diff suppressed because it is too large
Load Diff
51
flake.nix
51
flake.nix
|
@ -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")
|
||||||
|
|
|
@ -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.
Loading…
Reference in New Issue