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, ... }:
|
||||
|
||||
let
|
||||
fudo = config.fudo.domains."fudo.org";
|
||||
let fudo = config.fudo.domains."fudo.org";
|
||||
in {
|
||||
config.fudo.domains."sea.fudo.org" = {
|
||||
local-networks = fudo.local-networks;
|
||||
|
||||
gssapi-realm = fudo.gssapi-realm;
|
||||
kerberos-master = fudo.kerberos-master;
|
||||
kerberos-slaves = fudo.kerberos-slaves;
|
||||
# gssapi-realm = fudo.gssapi-realm;
|
||||
# kerberos-master = fudo.kerberos-master;
|
||||
# kerberos-slaves = fudo.kerberos-slaves;
|
||||
|
||||
primary-mailserver = fudo.primary-mailserver;
|
||||
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
admin = {
|
||||
gid = 1000;
|
||||
description = "Admin User Group";
|
||||
members = [
|
||||
"niten"
|
||||
"reaper"
|
||||
"swaff"
|
||||
];
|
||||
members = [ "niten" "reaper" "swaff" ];
|
||||
};
|
||||
|
||||
fudo = {
|
||||
|
@ -79,10 +75,7 @@
|
|||
informis = {
|
||||
gid = 1003;
|
||||
description = "Informis User Group";
|
||||
members = [
|
||||
"niten"
|
||||
"viator"
|
||||
];
|
||||
members = [ "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,85 +1,98 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
with lib;
|
||||
let
|
||||
let generateMac = pkgs.lib.network.generate-mac-address;
|
||||
|
||||
in {
|
||||
system.stateVersion = "21.05";
|
||||
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
|
||||
|
||||
boot = {
|
||||
initrd = {
|
||||
availableKernelModules = [
|
||||
"uhci_hcd"
|
||||
"ehci_pci"
|
||||
"ata_piix"
|
||||
"hpsa"
|
||||
"usb_storage"
|
||||
"usbhid"
|
||||
"sd_mod"
|
||||
"sr_mod"
|
||||
];
|
||||
kernelModules = [ ];
|
||||
};
|
||||
config = {
|
||||
|
||||
kernelModules = [ "kvm-intel" ];
|
||||
supportedFilesystems = [ "zfs" ];
|
||||
system.stateVersion = "22.05";
|
||||
|
||||
loader.grub = {
|
||||
enable = true;
|
||||
version = 2;
|
||||
device = "/dev/disk/by-id/wwn-0x600508b1001cecf6b880f591f9b18b29";
|
||||
};
|
||||
};
|
||||
boot = {
|
||||
initrd = {
|
||||
luks.devices.lambda-unlocked = {
|
||||
device = "/dev/disk/by-uuid/e90c9dda-4e4c-4ca1-8897-39fcebc03479";
|
||||
allowDiscards = true;
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-label/lambda-boot";
|
||||
fsType = "ext4";
|
||||
options = [ "noexec" "noatime" "nodiratime" ];
|
||||
};
|
||||
availableKernelModules = [
|
||||
"uhci_hcd"
|
||||
"ehci_pci"
|
||||
"ata_piix"
|
||||
"hpsa"
|
||||
"usb_storage"
|
||||
"usbhid"
|
||||
"sd_mod"
|
||||
"sr_mod"
|
||||
];
|
||||
kernelModules = [ "dm-snapshot" ];
|
||||
};
|
||||
|
||||
"/" = {
|
||||
device = "none";
|
||||
fsType = "tmpfs";
|
||||
options = [ "noexec" "mode=755" ];
|
||||
};
|
||||
kernelModules = [ "kvm-intel" ];
|
||||
kernelPackages = pkgs.linuxPackages_latest;
|
||||
|
||||
"/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" = {
|
||||
device = "lambda/persistent/state";
|
||||
fsType = "zfs";
|
||||
options = [ "noexec" "noatime" "nodiratime" ];
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [{ device = "/dev/disk/by-label/lambda-swap"; }];
|
||||
|
||||
nix.maxJobs = lib.mkDefault 12;
|
||||
|
||||
networking = {
|
||||
macvlans = {
|
||||
intif0 = {
|
||||
interface = "enp3s0f1";
|
||||
mode = "bridge";
|
||||
loader.grub = {
|
||||
enable = true;
|
||||
version = 2;
|
||||
device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121";
|
||||
};
|
||||
};
|
||||
|
||||
interfaces = {
|
||||
intif0 = {
|
||||
# output of: echo lambda-intif0|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'
|
||||
macAddress = "02:f5:fe:8c:22:fe";
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "lambda-root";
|
||||
fsType = "tmpfs";
|
||||
options = [ "mode=755" "size=32G" "noexec" ];
|
||||
};
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-label/lambda-boot";
|
||||
fsType = "ext4";
|
||||
options = [ "noatime" "noexec" ];
|
||||
};
|
||||
"/state" = {
|
||||
device = "/dev/mapper/lambda-unlocked";
|
||||
fsType = "btrfs";
|
||||
options = [ "noatime" "compress=zstd" "noexec" "subvol=@state" ];
|
||||
};
|
||||
"/nix" = {
|
||||
device = "/dev/mapper/lambda-unlocked";
|
||||
fsType = "btrfs";
|
||||
options = [ "noatime" "compress=zstd" "subvol=@nix" ];
|
||||
};
|
||||
"/home" = {
|
||||
device = "/dev/mapper/lambda-unlocked";
|
||||
fsType = "btrfs";
|
||||
options = [ "noatime" "compress=zstd" "subvol=@home" ];
|
||||
};
|
||||
"/var/log" = {
|
||||
device = "/dev/mapper/lambda-unlocked";
|
||||
fsType = "btrfs";
|
||||
options = [ "noatime" "compress=zstd" "noexec" "subvol=@log" ];
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [{
|
||||
device = "/dev/disk/by-id/scsi-3600508b1001c3be9174b4bdb31935121-part2";
|
||||
randomEncryption.enable = true;
|
||||
}];
|
||||
|
||||
nix.settings.max-jobs = lib.mkDefault 24;
|
||||
|
||||
networking = {
|
||||
useDHCP = false;
|
||||
macvlans = {
|
||||
intif0 = {
|
||||
interface = "enp4s0f1";
|
||||
mode = "bridge";
|
||||
};
|
||||
};
|
||||
|
||||
interfaces = {
|
||||
intif0 = {
|
||||
macAddress = generateMac config.instance.hostname "intif0";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -49,11 +49,18 @@ with lib; {
|
|||
options = [ "subvol=@state" "noexec" "noatime" "nodiratime" ];
|
||||
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"; }];
|
||||
|
||||
nix.maxJobs = lib.mkDefault 4;
|
||||
nix.settings.max-jobs = lib.mkDefault 4;
|
||||
|
||||
hardware.bluetooth.enable = false;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
nix.maxJobs = lib.mkDefault 24;
|
||||
nix.settings.max-jobs = lib.mkDefault 24;
|
||||
|
||||
hardware.bluetooth.enable = false;
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
swapDevices = [{ device = "/dev/disk/by-label/swap"; }];
|
||||
|
||||
nix.maxJobs = lib.mkDefault 8;
|
||||
nix.settings.max-jobs = lib.mkDefault 8;
|
||||
|
||||
hardware.bluetooth.enable = false;
|
||||
|
||||
|
|
|
@ -59,6 +59,6 @@
|
|||
};
|
||||
|
||||
services.xserver.videoDrivers = [ "intel" ];
|
||||
nix.maxJobs = lib.mkDefault 4;
|
||||
nix.settings.max-jobs = lib.mkDefault 4;
|
||||
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" ];
|
||||
|
||||
nix.maxJobs = lib.mkDefault 8;
|
||||
nix.settings.max-jobs = lib.mkDefault 8;
|
||||
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||
|
||||
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,79 +1,72 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
state-dir = "/state"; # This must be a string!
|
||||
|
||||
generate-mac = pkgs.lib.network.generate-mac-address;
|
||||
let primaryIp = "10.0.0.11";
|
||||
|
||||
in {
|
||||
boot = {
|
||||
loader.grub.copyKernels = true;
|
||||
#kernelModules = [ "rpcsec_gss_krb5" ];
|
||||
};
|
||||
config = {
|
||||
boot = { loader.grub.copyKernels = true; };
|
||||
|
||||
networking = {
|
||||
interfaces = {
|
||||
enp3s0f0.useDHCP = false;
|
||||
enp3s0f1.useDHCP = false;
|
||||
enp4s0f0.useDHCP = false;
|
||||
enp4s0f1.useDHCP = false;
|
||||
networking = {
|
||||
interfaces = {
|
||||
enp3s0f0.useDHCP = false;
|
||||
enp3s0f1.useDHCP = false;
|
||||
enp4s0f0.useDHCP = false;
|
||||
enp4s0f1.useDHCP = false;
|
||||
|
||||
intif0.useDHCP = true;
|
||||
intif0 = {
|
||||
useDHCP = false;
|
||||
ipv4.addresses = [{
|
||||
address = primaryIp;
|
||||
prefixLength = 16;
|
||||
}];
|
||||
};
|
||||
};
|
||||
|
||||
defaultGateway = {
|
||||
address = "10.0.0.1";
|
||||
interface = "intif0";
|
||||
};
|
||||
};
|
||||
|
||||
environment = {
|
||||
etc = {
|
||||
nixos.source = "/etc/nixos-live";
|
||||
NIXOS.source = "/state/host/NIXOS";
|
||||
};
|
||||
systemPackages = with pkgs; [ nixopsUnstable openssl ];
|
||||
};
|
||||
|
||||
security.sudo.extraConfig = ''
|
||||
# Due to rollback, sudo will lecture after every reboot
|
||||
Defaults lecture = never
|
||||
'';
|
||||
|
||||
fudo = {
|
||||
secrets = {
|
||||
secret-group = "fudo-secrets";
|
||||
secret-users = [ "niten" ];
|
||||
secret-paths = [ "/secrets" ];
|
||||
};
|
||||
hosts.lambda.encrypted-filesystems.secrets = {
|
||||
encrypted-device =
|
||||
"/dev/disk/by-id/scsi-3600508b1001c2f439e343270a365a5bd-part1";
|
||||
key-path = "/state/secrets-key/key";
|
||||
filesystem-type = "btrfs";
|
||||
remove-key = false;
|
||||
type = "luks2";
|
||||
mountpoints = {
|
||||
"/secrets" = {
|
||||
options = [ "noatime" "compress=zstd" ];
|
||||
group = "fudo-secrets";
|
||||
users = [ "niten" ];
|
||||
world-readable = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
tmpfiles.rules = [ "L /etc/adjtime - - - - /state/etc/adjtime" ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"L /root/.gnupg - - - - ${state-dir}/user/root/gnupg"
|
||||
"L /root/.ssh/id_rsa - - - - ${state-dir}/user/root/ssh/id_rsa"
|
||||
"L /root/.ssh/id_rsa.pub - - - - ${state-dir}/user/root/ssh/id_rsa.pub"
|
||||
"L /root/.ssh/known_hosts - - - - ${state-dir}/user/root/ssh/known_hosts"
|
||||
];
|
||||
|
||||
services.openssh.hostKeys = [
|
||||
{
|
||||
path = "${state-dir}/ssh/ssh_host_rsa_key";
|
||||
type = "rsa";
|
||||
bits = 4096;
|
||||
}
|
||||
{
|
||||
path = "${state-dir}/ssh/ssh_host_ed25519_key";
|
||||
type = "ed25519";
|
||||
bits = 4096;
|
||||
}
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"ssh/ssh_host_rsa_key" = {
|
||||
source = "${state-dir}/ssh/ssh_host_rsa_key";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0400";
|
||||
};
|
||||
"ssh/ssh_host_rsa_key.pub" = {
|
||||
source = "${state-dir}/ssh/ssh_host_rsa_key.pub";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0444";
|
||||
};
|
||||
"ssh/ssh_host_ed25519_key" = {
|
||||
source = "${state-dir}/ssh/ssh_host_ed25519_key";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0400";
|
||||
};
|
||||
"ssh/ssh_host_ed25519_key.pub" = {
|
||||
source = "${state-dir}/ssh/ssh_host_ed25519_key.pub";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0444";
|
||||
};
|
||||
nixos.source = "/etc/nixos-live";
|
||||
adjtime.source = "/state/host/adjtime";
|
||||
NIXOS.source = "/state/host/NIXOS";
|
||||
};
|
||||
|
||||
security.sudo.extraConfig = ''
|
||||
# Due to rollback, sudo will lecture after every reboot
|
||||
Defaults lecture = never
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -45,14 +45,6 @@ in {
|
|||
# document-root = "/state/gemini/root";
|
||||
# # textfiles-archive = "${pkgs.textfiles}";
|
||||
# slynk-port = 4005;
|
||||
|
||||
# # feeds = {
|
||||
# # viator = {
|
||||
# # title = "viator's phlog";
|
||||
# # path = "/home/viator/gemini-public/feed/";
|
||||
# # url = "gemini://informis.land/user/viator/feed/";
|
||||
# # };
|
||||
# # };
|
||||
# };
|
||||
|
||||
fudo = {
|
||||
|
@ -63,8 +55,8 @@ in {
|
|||
ldap.state-directory = "/state/auth/ldap";
|
||||
kerberos = {
|
||||
state-directory = "/state/auth/kerberos";
|
||||
master-key-file = host-secrets.heimdal-master-key.target-file;
|
||||
ipropd-keytab = host-secrets.heimdal-ipropd-keytab.target-file;
|
||||
# master-key-file = host-secrets.heimdal-master-key.target-file;
|
||||
# ipropd-keytab = host-secrets.heimdal-ipropd-keytab.target-file;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -72,15 +64,17 @@ in {
|
|||
state-directory = "/state/services/chat";
|
||||
external-interface = "extif0";
|
||||
};
|
||||
|
||||
nexus.dns-server.listen-addresses = [ host-ipv4 ];
|
||||
};
|
||||
|
||||
secrets.host-secrets.legatus = let files = config.fudo.secrets.files;
|
||||
in {
|
||||
postgres-keytab = {
|
||||
source-file = files.service-keytabs.procul.postgres;
|
||||
target-file = "/srv/postgres/secure/postgres.keytab";
|
||||
user = "root";
|
||||
};
|
||||
# postgres-keytab = {
|
||||
# source-file = files.service-keytabs.procul.postgres;
|
||||
# target-file = "/srv/postgres/secure/postgres.keytab";
|
||||
# user = "root";
|
||||
# };
|
||||
|
||||
# gitea-database-password = {
|
||||
# source-file = files.service-passwords.procul.gitea-database;
|
||||
|
@ -88,17 +82,17 @@ in {
|
|||
# user = config.fudo.git.user;
|
||||
# };
|
||||
|
||||
heimdal-master-key = {
|
||||
source-file = files.realm-master-keys."FUDO.ORG";
|
||||
target-file = "/run/heimdal/master-key";
|
||||
user = config.fudo.auth.kdc.user;
|
||||
};
|
||||
# heimdal-master-key = {
|
||||
# source-file = files.realm-master-keys."FUDO.ORG";
|
||||
# target-file = "/run/heimdal/master-key";
|
||||
# user = config.fudo.auth.kdc.user;
|
||||
# };
|
||||
|
||||
heimdal-ipropd-keytab = {
|
||||
source-file = files.service-keytabs.legatus.ipropd;
|
||||
target-file = "/run/heimdal/ipropd.keytab";
|
||||
user = config.fudo.auth.kdc.user;
|
||||
};
|
||||
# heimdal-ipropd-keytab = {
|
||||
# source-file = files.service-keytabs.legatus.ipropd;
|
||||
# target-file = "/run/heimdal/ipropd.keytab";
|
||||
# user = config.fudo.auth.kdc.user;
|
||||
# };
|
||||
};
|
||||
|
||||
client.dns = {
|
||||
|
|
|
@ -55,18 +55,18 @@ in {
|
|||
{
|
||||
destination = "10.0.0.10:25565";
|
||||
proto = "tcp";
|
||||
sourcePort = "25565";
|
||||
sourcePort = 25565;
|
||||
}
|
||||
{
|
||||
destination = "10.0.0.10:25565";
|
||||
proto = "udp";
|
||||
sourcePort = "25565";
|
||||
sourcePort = 25565;
|
||||
}
|
||||
# Factorio
|
||||
{
|
||||
destination = "10.0.0.10:34197";
|
||||
proto = "udp";
|
||||
sourcePort = "34197";
|
||||
sourcePort = 34197;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
@ -93,6 +93,8 @@ in {
|
|||
prometheus.state-directory = "/state/services/prometheus";
|
||||
};
|
||||
|
||||
auth.kerberos.state-directory = "/state/services/heimdal-kdc";
|
||||
|
||||
# wireguard-gateway = {
|
||||
# enable = true;
|
||||
# network = "10.0.200.0/24";
|
||||
|
|
|
@ -21,12 +21,19 @@ in {
|
|||
firewall.enable = false;
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.kdcConvertDatabase ];
|
||||
|
||||
# Hopefully this'll help with NFS...
|
||||
boot.kernelModules = [ "rpcsec_gss_krb5" ];
|
||||
|
||||
services = {
|
||||
murmur.enable = true;
|
||||
|
||||
# objectifier = {
|
||||
# enable = true;
|
||||
# listen-addresses = [ "0.0.0.0" ];
|
||||
# };
|
||||
|
||||
nfs = {
|
||||
# See ../user-config.nix for the user@REALM -> user mapping
|
||||
server = {
|
||||
|
@ -99,7 +106,7 @@ in {
|
|||
mattermost-auth-token-file = host-secrets.pricebot-auth-token.target-file;
|
||||
monitors = {
|
||||
btc = {
|
||||
mattermost-channel-id = "3m4bsxcrwbrmpqd4yawwh98q8o";
|
||||
mattermost-channel-id = "f7iem9t3qbbczjyuq4waj1s3ua";
|
||||
notify-user = "niten";
|
||||
};
|
||||
};
|
||||
|
@ -117,6 +124,8 @@ in {
|
|||
};
|
||||
ldap.base-dn = "dc=fudo,dc=org";
|
||||
};
|
||||
|
||||
auth.kerberos.state-directory = "/state/services/heimdal-kdc";
|
||||
};
|
||||
|
||||
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
|
||||
hostname = "nutboy3";
|
||||
host-fqdn = config.instance.host-fqdn;
|
||||
|
@ -32,6 +32,8 @@ in {
|
|||
];
|
||||
|
||||
config = {
|
||||
boot.kernelModules = [ "veth" ];
|
||||
|
||||
networking = {
|
||||
nameservers = [ "1.1.1.1" ];
|
||||
defaultGateway = {
|
||||
|
@ -65,24 +67,22 @@ in {
|
|||
|
||||
secrets.host-secrets.${hostname} = let files = config.fudo.secrets.files;
|
||||
in {
|
||||
heimdal-master-key = {
|
||||
source-file = files.realm-master-keys."FUDO.ORG";
|
||||
target-file = "/run/heimdal/master-key";
|
||||
user = config.fudo.auth.kdc.user;
|
||||
};
|
||||
# heimdal-master-key = {
|
||||
# source-file = files.realm-master-keys."FUDO.ORG";
|
||||
# target-file = "/run/heimdal/master-key";
|
||||
# user = config.fudo.auth.kdc.user;
|
||||
# };
|
||||
|
||||
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";
|
||||
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 = {
|
||||
source-file = grafana-database-passwd-file;
|
||||
target-file = "/run/metrics/grafana/db.passwd";
|
||||
|
@ -129,15 +129,17 @@ in {
|
|||
auth = {
|
||||
ldap.state-directory = "/state/auth/ldap";
|
||||
kerberos = {
|
||||
state-directory = "/state/auth/kerberos";
|
||||
master-key-file = host-secrets.heimdal-master-key.target-file;
|
||||
state-directory = "/state/services/heimdal-kdc";
|
||||
# master-key-file = host-secrets.heimdal-master-key.target-file;
|
||||
};
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
state-directory = "/state/services/postgresql";
|
||||
keytab =
|
||||
config.fudo.secrets.files.service-keytabs.${hostname}.postgres;
|
||||
keytab = extractFudoKeytab {
|
||||
realm = domain.gssapi-realm;
|
||||
principals = [ "postgres/${host-fqdn}" ];
|
||||
};
|
||||
};
|
||||
|
||||
metrics = {
|
||||
|
@ -154,13 +156,13 @@ in {
|
|||
|
||||
logging.loki.state-directory = "/state/services/loki";
|
||||
|
||||
selby-forum = {
|
||||
enable = true;
|
||||
state-directory = "/state/services/selby-forum";
|
||||
legacy-forum-data = files.blobs."selby-forum-2021-12-14.clean";
|
||||
external-interface = "extif0";
|
||||
mail.host = "mail.fudo.org";
|
||||
};
|
||||
# selby-forum = {
|
||||
# enable = true;
|
||||
# state-directory = "/state/services/selby-forum";
|
||||
# legacy-forum-data = files.blobs."selby-forum-2021-12-14.clean";
|
||||
# external-interface = "extif0";
|
||||
# mail.host = "mail.fudo.org";
|
||||
# };
|
||||
};
|
||||
|
||||
# dns.state-directory = "/state/nsd";
|
||||
|
@ -258,5 +260,16 @@ in {
|
|||
# loadLatestSave = true;
|
||||
# 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";
|
||||
|
||||
local-packages = with pkgs; [
|
||||
bind
|
||||
emacs-nox
|
||||
mtr
|
||||
vim
|
||||
];
|
||||
local-packages = with pkgs; [ bind emacs-nox mtr vim ];
|
||||
|
||||
fudo-zone = pkgs.lib.dns.zoneToZonefile
|
||||
config.instance.build-timestamp "fudo.org"
|
||||
fudo-zone =
|
||||
pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp "fudo.org"
|
||||
config.fudo.zones."fudo.org";
|
||||
|
||||
selby-zone = pkgs.lib.dns.zoneToZonefile
|
||||
config.instance.build-timestamp "selby.ca"
|
||||
selby-zone =
|
||||
pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp "selby.ca"
|
||||
config.fudo.zones."selby.ca";
|
||||
|
||||
in {
|
||||
|
@ -36,12 +31,14 @@ in {
|
|||
{
|
||||
ipv4-address = "209.177.102.102";
|
||||
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";
|
||||
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";
|
||||
|
@ -52,12 +49,12 @@ in {
|
|||
};
|
||||
"selby.ca" = {
|
||||
enable = true;
|
||||
external-nameservers = map (n: let
|
||||
i = toString n;
|
||||
in {
|
||||
authoritative-hostname = "ns${i}.fudo.org";
|
||||
description = "Nameserver ${i}, ns${i}.fudo.org.";
|
||||
}) [2 3 4];
|
||||
external-nameservers = map (n:
|
||||
let i = toString n;
|
||||
in {
|
||||
authoritative-hostname = "ns${i}.fudo.org";
|
||||
description = "Nameserver ${i}, ns${i}.fudo.org.";
|
||||
}) [ 2 3 4 ];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -82,9 +79,7 @@ in {
|
|||
"rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org."
|
||||
];
|
||||
};
|
||||
"selby.ca" = {
|
||||
default-host = host-ipv4;
|
||||
};
|
||||
"selby.ca" = { default-host = host-ipv4; };
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -117,17 +112,15 @@ in {
|
|||
interfaces = [ "eno2" ];
|
||||
|
||||
config = { config, ... }: {
|
||||
boot.kernelModules = [ "veth" ];
|
||||
|
||||
nixpkgs.pkgs = pkgs;
|
||||
|
||||
environment = {
|
||||
systemPackages = local-packages;
|
||||
etc = {
|
||||
"generated-zones/fudo.org" = {
|
||||
text = fudo-zone;
|
||||
};
|
||||
"generated-zones/selby.ca" = {
|
||||
text = selby-zone;
|
||||
};
|
||||
"generated-zones/fudo.org" = { text = fudo-zone; };
|
||||
"generated-zones/selby.ca" = { text = selby-zone; };
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -144,17 +137,8 @@ in {
|
|||
];
|
||||
};
|
||||
groups = {
|
||||
wheel.members = [
|
||||
"niten"
|
||||
"reaper"
|
||||
];
|
||||
dns = {
|
||||
members = [
|
||||
"niten"
|
||||
"reaper"
|
||||
"named"
|
||||
];
|
||||
};
|
||||
wheel.members = [ "niten" "reaper" ];
|
||||
dns = { members = [ "niten" "reaper" "named" ]; };
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with pkgs.lib;
|
||||
let
|
||||
hostname = "procul";
|
||||
|
||||
|
@ -58,16 +58,14 @@ in {
|
|||
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
security.acme.email = "viator@informis.land";
|
||||
security.acme.defaults.email = "viator@informis.land";
|
||||
|
||||
users = {
|
||||
users = {
|
||||
gituser = {
|
||||
isSystemUser = true;
|
||||
group = "nogroup";
|
||||
};
|
||||
users.gituser = {
|
||||
isSystemUser = true;
|
||||
group = "nogroup";
|
||||
};
|
||||
groups = { acme = { members = [ "nginx" ]; }; };
|
||||
groups.acme.members = [ "nginx" ];
|
||||
};
|
||||
|
||||
informis = {
|
||||
|
@ -154,11 +152,11 @@ in {
|
|||
user = config.services.postgresql.superUser;
|
||||
};
|
||||
|
||||
heimdal-master-key = {
|
||||
source-file = files.realm-master-keys."INFORMIS.LAND";
|
||||
target-file = "/run/heimdal/master-key";
|
||||
user = config.fudo.auth.kdc.user;
|
||||
};
|
||||
# heimdal-master-key = {
|
||||
# source-file = files.realm-master-keys."INFORMIS.LAND";
|
||||
# target-file = "/run/heimdal/master-key";
|
||||
# user = config.fudo.auth.kdc.user;
|
||||
# };
|
||||
|
||||
chute-staging-credentials = {
|
||||
source-file = files.service-secrets.procul."chute-staging.env";
|
||||
|
@ -260,7 +258,11 @@ in {
|
|||
};
|
||||
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";
|
||||
metrics = {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
with lib;
|
||||
let state-dir = "/state";
|
||||
in {
|
||||
fudo = {
|
||||
slynk.enable = true;
|
||||
wallfly.location = "office";
|
||||
|
@ -16,6 +18,15 @@
|
|||
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 = {
|
||||
# enable = true;
|
||||
# http.listen-ip = "10.0.0.108";
|
||||
|
|
|
@ -8,8 +8,6 @@ in {
|
|||
wallfly.location = "office";
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [ opencv-java ];
|
||||
|
||||
networking = {
|
||||
interfaces.intif0.useDHCP = true;
|
||||
firewall.enable = false;
|
||||
|
@ -22,6 +20,7 @@ in {
|
|||
"L /root/.ssh/known_hosts - - - - ${state-dir}/user/root/ssh/known_hosts"
|
||||
"L /var/lib/flatpak - - - - ${state-dir}/lib/flatpak"
|
||||
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
|
||||
"d ${state-dir}/lib/cups 755 root root - -"
|
||||
];
|
||||
|
||||
services = {
|
||||
|
@ -40,6 +39,13 @@ in {
|
|||
];
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/var/lib/cups" = {
|
||||
device = "${state-dir}/lib/cups";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc = {
|
||||
nixos.source = "/etc/nixos-live";
|
||||
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";
|
||||
state-dir = "/state";
|
||||
zigbee2mqtt-statedir = "${state-dir}/services/zigbee2mqtt";
|
||||
mosquitto-statedir = "${state-dir}/services/mosquitto";
|
||||
home-assistant-port = 8123;
|
||||
|
||||
zigbee2mqtt-user = config.systemd.services.zigbee2mqtt.serviceConfig.User;
|
||||
|
||||
mosquitto-user = config.systemd.services.mosquitto.serviceConfig.User;
|
||||
|
||||
zigbee2mqtt-passwd-file =
|
||||
pkgs.lib.passwd.stablerandom-passwd-file "zigbee2mqtt-passwd"
|
||||
config.instance.build-seed;
|
||||
|
@ -54,31 +51,21 @@ in {
|
|||
dhcpcd.extraConfig = concatStringsSep "\n" [ "nogateway" ];
|
||||
};
|
||||
|
||||
fudo.secrets.host-secrets.${hostname} = {
|
||||
mosquitto-zigbee2mqtt-passwd = {
|
||||
source-file = zigbee2mqtt-passwd-file;
|
||||
target-file = "/run/mosquitto-secrets/zigbee2mqtt.passwd";
|
||||
user = mosquitto-user;
|
||||
};
|
||||
mosquitto-home-assistant-passwd = {
|
||||
source-file = host-passwds.mosquitto-home-assistant;
|
||||
target-file = "/run/mosquitto-secrets/home-assistant.passwd";
|
||||
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;
|
||||
fudo.services.mqtt = {
|
||||
enable = true;
|
||||
state-directory = "${state-dir}/services/mosquitto";
|
||||
private = {
|
||||
enable = true;
|
||||
users = {
|
||||
zigbee2mqtt = {
|
||||
password-file = zigbee2mqtt-passwd-file;
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
home-assistant = {
|
||||
password-file = host-passwds.mosquitto-home-assistant;
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -95,15 +82,6 @@ in {
|
|||
RemainAfterExit = true;
|
||||
};
|
||||
};
|
||||
|
||||
zigbee2mqtt = {
|
||||
after = [ config.fudo.secrets.secret-target "mosquitto.service" ];
|
||||
restartIfChanged = true;
|
||||
};
|
||||
mosquitto = {
|
||||
after = [ config.fudo.secrets.secret-target ];
|
||||
restartIfChanged = true;
|
||||
};
|
||||
};
|
||||
|
||||
tmpfiles.rules = [
|
||||
|
@ -114,7 +92,6 @@ in {
|
|||
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
|
||||
"d /state/services 0711 root root - -"
|
||||
"d ${zigbee2mqtt-statedir} 0700 ${zigbee2mqtt-user} - - -"
|
||||
"d ${mosquitto-statedir} 0700 ${mosquitto-user} - - -"
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -149,39 +126,39 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
mosquitto = {
|
||||
enable = true;
|
||||
dataDir = mosquitto-statedir;
|
||||
listeners = [{
|
||||
settings.allow_anonymous = false;
|
||||
port = 1883;
|
||||
address = "0.0.0.0";
|
||||
users = {
|
||||
zigbee2mqtt = {
|
||||
passwordFile =
|
||||
host-secrets.mosquitto-zigbee2mqtt-passwd.target-file;
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
home-assistant = {
|
||||
passwordFile =
|
||||
host-secrets.mosquitto-home-assistant-passwd.target-file;
|
||||
acl = [ "readwrite #" ];
|
||||
};
|
||||
# niten = {
|
||||
# passwordFile = host-secrets.mosquitto-niten-passwd.target-file;
|
||||
# acl = [ "readwrite #" ];
|
||||
# };
|
||||
# xiaoxuan = {
|
||||
# passwordFile = host-secrets.mosquitto-xiaoxuan-passwd.target-file;
|
||||
# acl = [ "readwrite #" ];
|
||||
# };
|
||||
# wallfly = {
|
||||
# passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
|
||||
# acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
||||
# };
|
||||
};
|
||||
}];
|
||||
};
|
||||
# mosquitto = {
|
||||
# enable = true;
|
||||
# dataDir = mosquitto-statedir;
|
||||
# listeners = [{
|
||||
# settings.allow_anonymous = false;
|
||||
# port = 1883;
|
||||
# address = "0.0.0.0";
|
||||
# users = {
|
||||
# zigbee2mqtt = {
|
||||
# passwordFile =
|
||||
# host-secrets.mosquitto-zigbee2mqtt-passwd.target-file;
|
||||
# acl = [ "readwrite #" ];
|
||||
# };
|
||||
# home-assistant = {
|
||||
# passwordFile =
|
||||
# host-secrets.mosquitto-home-assistant-passwd.target-file;
|
||||
# acl = [ "readwrite #" ];
|
||||
# };
|
||||
# niten = {
|
||||
# passwordFile = host-secrets.mosquitto-niten-passwd.target-file;
|
||||
# acl = [ "readwrite #" ];
|
||||
# };
|
||||
# # xiaoxuan = {
|
||||
# # passwordFile = host-secrets.mosquitto-xiaoxuan-passwd.target-file;
|
||||
# # acl = [ "readwrite #" ];
|
||||
# # };
|
||||
# # wallfly = {
|
||||
# # passwordFile = host-secrets.mosquitto-wallfly-passwd.target-file;
|
||||
# # acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
||||
# # };
|
||||
# };
|
||||
# }];
|
||||
# };
|
||||
|
||||
zigbee2mqtt = {
|
||||
enable = true;
|
||||
|
@ -191,8 +168,11 @@ in {
|
|||
homeassistant = true;
|
||||
permit_join = true;
|
||||
serial.port = "/dev/ttyUSB0";
|
||||
mqtt = {
|
||||
server = "mqtt://127.0.0.1:1883";
|
||||
mqtt = let
|
||||
mqttHost = config.fudo.services.mqtt.mqtt-hostname;
|
||||
mqttPort = config.fudo.services.mqtt.private.port;
|
||||
in {
|
||||
server = "mqtt://${mqttHost}:${toString mqttPort}";
|
||||
user = "zigbee2mqtt";
|
||||
password = readFile zigbee2mqtt-passwd-file;
|
||||
# TODO: could make a yaml file containing password
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
let state-dir = "/state";
|
||||
in {
|
||||
config = {
|
||||
|
@ -8,8 +9,6 @@ in {
|
|||
wallfly.location = "family_room";
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [ opencv-java ];
|
||||
|
||||
networking = {
|
||||
interfaces.intif0.useDHCP = true;
|
||||
firewall.enable = false;
|
||||
|
@ -21,12 +20,20 @@ in {
|
|||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${state-dir}/lib/cups 755 root root - -"
|
||||
"d ${state-dir}/lib/flatpak 0755 root root - -"
|
||||
"d ${state-dir}/etc 0755 root root - -"
|
||||
"L /var/lib/flatpak - - - - ${state-dir}/lib/flatpak"
|
||||
"L /etc/adjtime - - - - ${state-dir}/etc/adjtime"
|
||||
];
|
||||
|
||||
fileSystems = {
|
||||
"/var/lib/cups" = {
|
||||
device = "${state-dir}/lib/cups";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
};
|
||||
|
||||
hardware = {
|
||||
bluetooth = {
|
||||
enable = true;
|
||||
|
@ -34,5 +41,11 @@ in {
|
|||
};
|
||||
xpadneo.enable = true;
|
||||
};
|
||||
|
||||
services.xserver = {
|
||||
layout = "us";
|
||||
xkbVariant = mkForce "";
|
||||
xkbOptions = mkForce "";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
let
|
||||
has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||
let has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||
in {
|
||||
config.instance = mkIf has-secret-files {
|
||||
# TODO: This has a newline, I think...
|
||||
build-seed = builtins.readFile config.fudo.secrets.files.build-seed;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ in {
|
|||
autoSuspend = false;
|
||||
};
|
||||
|
||||
windowManager.stumpwm.enable = true;
|
||||
# windowManager.stumpwm.enable = true;
|
||||
|
||||
# windowManager.session = pkgs.lib.singleton {
|
||||
# name = "stumpwm";
|
||||
|
@ -88,4 +88,24 @@ in {
|
|||
services.flatpak.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;
|
||||
|
||||
config = {
|
||||
fudo.hosts.${hostname}.local-networks = [ "::1/128" ];
|
||||
fudo = { hosts.${hostname}.local-networks = [ "::1/128" ]; };
|
||||
|
||||
system.autoUpgrade.enable = false;
|
||||
|
||||
|
@ -49,28 +49,7 @@ in {
|
|||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
hardware.enableRedistributableFirmware = 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;
|
||||
};
|
||||
hardware.enableAllFirmware = true;
|
||||
|
||||
services = {
|
||||
openssh = {
|
||||
|
@ -78,12 +57,12 @@ in {
|
|||
startWhenNeeded = true;
|
||||
useDns = true;
|
||||
permitRootLogin = "prohibit-password";
|
||||
extraConfig = ''
|
||||
GSSAPIAuthentication yes
|
||||
GSSAPICleanupCredentials yes
|
||||
GSSAPIKeyExchange yes
|
||||
GSSAPIStoreCredentialsOnRekey yes
|
||||
'';
|
||||
# extraConfig = ''
|
||||
# GSSAPIAuthentication yes
|
||||
# GSSAPICleanupCredentials yes
|
||||
# GSSAPIKeyExchange yes
|
||||
# GSSAPIStoreCredentialsOnRekey yes
|
||||
# '';
|
||||
# FIXME: This is temporary! Getting error: Unsupported KEX algorithm "sntrup761x25519-sha512@openssh.com"
|
||||
kexAlgorithms = [
|
||||
"curve25519-sha256"
|
||||
|
@ -111,7 +90,10 @@ in {
|
|||
in length btrfsFilesystems > 0;
|
||||
|
||||
pcscd.enable = true;
|
||||
udev.packages = with pkgs; [ yubikey-personalization ];
|
||||
udev = {
|
||||
enable = true;
|
||||
packages = with pkgs; [ yubikey-personalization ];
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
|
@ -139,16 +121,7 @@ in {
|
|||
# pinentryFlavor = if cfg.enable-gui then "gnome3" else "curses";
|
||||
};
|
||||
|
||||
ssh = {
|
||||
startAgent = true;
|
||||
|
||||
package = pkgs.openssh_gssapi;
|
||||
|
||||
extraConfig = ''
|
||||
GSSAPIAuthentication yes
|
||||
GSSAPIDelegateCredentials yes
|
||||
'';
|
||||
};
|
||||
ssh = { startAgent = true; };
|
||||
};
|
||||
|
||||
security = {
|
||||
|
@ -178,7 +151,5 @@ in {
|
|||
# };
|
||||
};
|
||||
};
|
||||
|
||||
home-manager = { useGlobalPkgs = true; };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,66 +7,83 @@ let
|
|||
try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
|
||||
|
||||
in {
|
||||
config = mkIf has-secret-files
|
||||
(let keytab-file = try-attr hostname config.fudo.secrets.files.host-keytabs;
|
||||
in mkIf (keytab-file != null) {
|
||||
## This doesn't seem to work...timing?
|
||||
# environment.etc."krb5.keytab" = mkIf (keytab-file != null) {
|
||||
# source =
|
||||
# config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
|
||||
# user = "root";
|
||||
# group = "root";
|
||||
# mode = "0400";
|
||||
# };
|
||||
config = mkIf has-secret-files (let
|
||||
keytab-file =
|
||||
try-attr hostname config.fudo.secrets.files.kerberos.host-keytabs;
|
||||
in mkIf (keytab-file != null) {
|
||||
## This doesn't seem to work...timing?
|
||||
# environment.etc."krb5.keytab" = mkIf (keytab-file != null) {
|
||||
# source =
|
||||
# config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
|
||||
# user = "root";
|
||||
# group = "root";
|
||||
# mode = "0400";
|
||||
# };
|
||||
|
||||
systemd = let
|
||||
host-keytab =
|
||||
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
|
||||
in {
|
||||
paths."${hostname}-keytab-watcher" = {
|
||||
wantedBy = [ "default.target" ];
|
||||
description = "Watch host keytab for changes.";
|
||||
pathConfig = {
|
||||
PathChanged = host-keytab;
|
||||
Unit = "${hostname}-keytab-watcher.service";
|
||||
};
|
||||
};
|
||||
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;
|
||||
|
||||
services = {
|
||||
"${hostname}-keytab-watcher" = {
|
||||
description =
|
||||
"When host keytab is available or changed, activate copy job.";
|
||||
path = with pkgs; [ systemd ];
|
||||
serviceConfig = { Type = "oneshot"; };
|
||||
script = "systemctl restart ${hostname}-copy-keytab.service";
|
||||
};
|
||||
libdefaults.default_etypes =
|
||||
"aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96";
|
||||
};
|
||||
|
||||
"${hostname}-copy-keytab" = {
|
||||
description =
|
||||
"Copy the host krb5.keytab into place once it's available.";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = pkgs.writeShellScript "${hostname}-copy-keytab.sh" ''
|
||||
[ -f ${host-keytab} ] || exit 1
|
||||
[ -f /etc/krb5.keytab ] && rm /etc/krb5.keytab
|
||||
cp ${host-keytab} /etc/krb5.keytab
|
||||
chown root:root /etc/krb5.keytab
|
||||
chmod 0400 /etc/krb5.keytab
|
||||
'';
|
||||
ExecStop = pkgs.writeShellScript "${hostname}-remove-keytab.sh" ''
|
||||
rm -f /etc/krb5.keytab
|
||||
'';
|
||||
};
|
||||
};
|
||||
systemd = let
|
||||
host-keytab =
|
||||
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;
|
||||
in {
|
||||
paths."${hostname}-keytab-watcher" = {
|
||||
wantedBy = [ "default.target" ];
|
||||
description = "Watch host keytab for changes.";
|
||||
pathConfig = {
|
||||
PathChanged = host-keytab;
|
||||
Unit = "${hostname}-keytab-watcher.service";
|
||||
};
|
||||
};
|
||||
|
||||
fudo.secrets.host-secrets.${hostname}.host-keytab =
|
||||
mkIf (keytab-file != null) {
|
||||
source-file = keytab-file;
|
||||
target-file = "/run/kerberos/krb5.keytab";
|
||||
user = "root";
|
||||
services = {
|
||||
"${hostname}-keytab-watcher" = {
|
||||
description =
|
||||
"When host keytab is available or changed, activate copy job.";
|
||||
path = with pkgs; [ systemd ];
|
||||
serviceConfig = { Type = "oneshot"; };
|
||||
script = "systemctl restart ${hostname}-copy-keytab.service";
|
||||
};
|
||||
});
|
||||
|
||||
"${hostname}-copy-keytab" = {
|
||||
description =
|
||||
"Copy the host krb5.keytab into place once it's available.";
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = pkgs.writeShellScript "${hostname}-copy-keytab.sh" ''
|
||||
[ -f ${host-keytab} ] || exit 1
|
||||
[ -f /etc/krb5.keytab ] && rm /etc/krb5.keytab
|
||||
cp ${host-keytab} /etc/krb5.keytab
|
||||
chown root:root /etc/krb5.keytab
|
||||
chmod 0400 /etc/krb5.keytab
|
||||
'';
|
||||
ExecStop = pkgs.writeShellScript "${hostname}-remove-keytab.sh" ''
|
||||
rm -f /etc/krb5.keytab
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fudo.secrets.host-secrets.${hostname}.host-keytab =
|
||||
mkIf (keytab-file != null) {
|
||||
source-file = keytab-file;
|
||||
target-file = "/run/kerberos/krb5.keytab";
|
||||
user = "root";
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,56 +8,54 @@ let
|
|||
has-secret-files = hasAttr "files" config.fudo.secrets;
|
||||
|
||||
in {
|
||||
config = mkIf has-secret-files
|
||||
(let
|
||||
host-keypairs =
|
||||
if (hasAttr hostname config.fudo.secrets.files.host-ssh-keypairs) then
|
||||
config.fudo.secrets.files.host-ssh-keypairs.${hostname}
|
||||
else [];
|
||||
config = mkIf has-secret-files (let
|
||||
host-keypairs =
|
||||
if (hasAttr hostname config.fudo.secrets.files.ssh.host-keypairs) then
|
||||
config.fudo.secrets.files.ssh.host-keypairs.${hostname}
|
||||
else
|
||||
[ ];
|
||||
|
||||
in {
|
||||
fudo = let
|
||||
sshfp-filename = host: keypair:
|
||||
"ssh-${host}-${keypair.key-type}.sshfp-record";
|
||||
|
||||
dns-sshfp-records = host: keypair:
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "${host}-sshfp-records";
|
||||
|
||||
phases = [ "installPhase" ];
|
||||
|
||||
buildInputs = with pkgs; [ openssh ];
|
||||
|
||||
installPhase = ''
|
||||
ssh-keygen -r REMOVEME -f "${keypair.public-key}" | sed 's/^REMOVEME IN SSHFP //' > $out'';
|
||||
};
|
||||
|
||||
host-cfg = config.fudo.hosts.${hostname};
|
||||
in {
|
||||
fudo = let
|
||||
sshfp-filename = host: keypair: "ssh-${host}-${keypair.key-type}.sshfp-record";
|
||||
secrets.host-secrets.${hostname} = listToAttrs (map (keypair:
|
||||
nameValuePair "host-${keypair.key-type}-private-key" {
|
||||
source-file = keypair.private-key;
|
||||
target-file =
|
||||
"/run/openssh/private/host-${keypair.key-type}-private-key";
|
||||
user = "root";
|
||||
}) host-keypairs);
|
||||
|
||||
dns-sshfp-records = host: keypair:
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "${host}-sshfp-records";
|
||||
hosts = mkIf (hasAttr "files" config.fudo.secrets) (mapAttrs
|
||||
(hostname: keypairs: {
|
||||
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
|
||||
ssh-fingerprints = concatMap (keypair:
|
||||
let fingerprint-derivation = dns-sshfp-records hostname keypair;
|
||||
in read-lines "${fingerprint-derivation}") keypairs;
|
||||
}) config.fudo.secrets.files.ssh.host-keypairs);
|
||||
};
|
||||
|
||||
phases = [ "installPhase" ];
|
||||
|
||||
buildInputs = with pkgs; [ openssh ];
|
||||
|
||||
installPhase =
|
||||
"ssh-keygen -r REMOVEME -f \"${keypair.public-key}\" | sed 's/^REMOVEME IN SSHFP //' > $out";
|
||||
};
|
||||
|
||||
host-cfg = config.fudo.hosts.${hostname};
|
||||
in {
|
||||
secrets.host-secrets.${hostname} = listToAttrs
|
||||
(map
|
||||
(keypair: nameValuePair "host-${keypair.key-type}-private-key" {
|
||||
source-file = keypair.private-key;
|
||||
target-file = "/run/openssh/private/host-${keypair.key-type}-private-key";
|
||||
user = "root";
|
||||
})
|
||||
host-keypairs);
|
||||
|
||||
hosts = mkIf (hasAttr "files" config.fudo.secrets)
|
||||
(mapAttrs (hostname: keypairs: {
|
||||
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
|
||||
ssh-fingerprints = concatMap (keypair:
|
||||
let
|
||||
fingerprint-derivation = dns-sshfp-records hostname keypair;
|
||||
in read-lines "${fingerprint-derivation}") keypairs;
|
||||
}) config.fudo.secrets.files.host-ssh-keypairs);
|
||||
};
|
||||
|
||||
services.openssh.hostKeys = let
|
||||
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||
services.openssh.hostKeys =
|
||||
let host-secrets = config.fudo.secrets.host-secrets."${hostname}";
|
||||
in map (keypair: {
|
||||
path =
|
||||
host-secrets."host-${keypair.key-type}-private-key".target-file;
|
||||
path = host-secrets."host-${keypair.key-type}-private-key".target-file;
|
||||
type = keypair.key-type;
|
||||
}) host-keypairs;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
with lib;
|
||||
let
|
||||
hostname = config.instance.hostname;
|
||||
domain-name = config.fudo.hosts.${hostname}.domain;
|
||||
domain = config.fudo.domains.${domain-name};
|
||||
zone-name = config.fudo.domains.${domain-name}.zone;
|
||||
domain-name = config.fudo.hosts."${hostname}".domain;
|
||||
domain = config.fudo.domains."${domain-name}";
|
||||
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;
|
||||
|
||||
isDatabase = hostname == postgresql-server;
|
||||
isJabber = elem hostname domain.xmpp-servers;
|
||||
isDatabaseServer = hostname == postgresql-server;
|
||||
isJabberServer = elem hostname domain.xmpp-servers;
|
||||
isDNSBackplane = hostname == domain.backplane.dns-service;
|
||||
backplaneEnabled = domain.backplane != null;
|
||||
isNameserver = hostname == domain.backplane.nameserver;
|
||||
|
@ -73,18 +73,18 @@ in {
|
|||
user = config.fudo.backplane.dns.user;
|
||||
};
|
||||
|
||||
database-powerdns-passwd = mkIf isDatabase {
|
||||
database-powerdns-passwd = mkIf isDatabaseServer {
|
||||
source-file = powerdns-password;
|
||||
target-file = "/run/postgres/powerdns.passwd";
|
||||
user = config.services.postgresql.superUser;
|
||||
};
|
||||
database-backplane-passwd = mkIf isDatabase {
|
||||
database-backplane-passwd = mkIf isDatabaseServer {
|
||||
source-file = backplane-database-password;
|
||||
target-file = "/run/postgres/backplane-database.passwd";
|
||||
user = config.services.postgresql.superUser;
|
||||
};
|
||||
|
||||
ejabberd-backplane-passwd = mkIf isJabber {
|
||||
ejabberd-backplane-passwd = mkIf isJabberServer {
|
||||
source-file = xmpp-password;
|
||||
target-file = "/run/backplane-jabber/service-dns.passwd";
|
||||
user = config.services.ejabberd.user;
|
||||
|
@ -106,7 +106,7 @@ in {
|
|||
aliases = { backplane = "${backplane-host-fqdn}."; };
|
||||
};
|
||||
|
||||
postgresql = mkIf isDatabase {
|
||||
postgresql = mkIf isDatabaseServer {
|
||||
required-services = [ "fudo-passwords.target" ];
|
||||
|
||||
users = {
|
||||
|
@ -136,7 +136,7 @@ in {
|
|||
};
|
||||
|
||||
backplane = {
|
||||
enable = isJabber;
|
||||
enable = isJabberServer;
|
||||
|
||||
client-hosts = mapAttrs (hostname: hostOpts: {
|
||||
password-file = host-password-files.${hostname};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, ... } @ toplevel:
|
||||
{ config, lib, pkgs, ... }@toplevel:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
@ -6,6 +6,18 @@ let
|
|||
|
||||
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, ... }: {
|
||||
options = with types; {
|
||||
hostname = mkOption {
|
||||
|
@ -39,166 +51,192 @@ let
|
|||
};
|
||||
};
|
||||
|
||||
zoneOpts = { name, ... }: let
|
||||
zone-name = name;
|
||||
in {
|
||||
options = with types; {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
description = "Enable ${zone-name} zone on the local nameserver.";
|
||||
default = zone-name == toplevel.config.instance.local-zone;
|
||||
};
|
||||
zoneOpts = { name, ... }:
|
||||
let zone-name = name;
|
||||
in {
|
||||
options = with types; {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
description = "Enable ${zone-name} zone on the local nameserver.";
|
||||
default = zone-name == toplevel.config.instance.local-zone;
|
||||
};
|
||||
|
||||
default-host = mkOption {
|
||||
type = nullOr str;
|
||||
description = "IP which will respond to requests for the base domain.";
|
||||
default = null;
|
||||
};
|
||||
default-host = mkOption {
|
||||
type = nullOr str;
|
||||
description =
|
||||
"IP which will respond to requests for the base domain.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
external-nameservers = mkOption {
|
||||
type = listOf (submodule nameserverOpts);
|
||||
description = "Off-network secondary nameservers.";
|
||||
default = [];
|
||||
};
|
||||
external-nameservers = mkOption {
|
||||
type = listOf (submodule nameserverOpts);
|
||||
description = "Off-network secondary nameservers.";
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
description = "Domain which this zone serves.";
|
||||
default = zone-name;
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
description = "Domain which this zone serves.";
|
||||
default = zone-name;
|
||||
};
|
||||
|
||||
ksk = mkOption {
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
private-key = mkOption {
|
||||
type = path;
|
||||
description = "KSK private key.";
|
||||
};
|
||||
public-key = mkOption {
|
||||
type = path;
|
||||
description = "KSK public key.";
|
||||
};
|
||||
ds = mkOption {
|
||||
type = path;
|
||||
description = "KSK ds record.";
|
||||
};
|
||||
};
|
||||
});
|
||||
description =
|
||||
"Location of the zone-signing private & public keys and DS record.";
|
||||
default =
|
||||
toplevel.config.fudo.secrets.files.dns.key-signing-keys."${zone-name}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pthru = obj:
|
||||
builtins.trace "TRACE: ${ obj }" obj;
|
||||
|
||||
in {
|
||||
options.fudo.services.dns = with types; {
|
||||
zones = mkOption {
|
||||
type = attrsOf (submodule zoneOpts);
|
||||
description = "Map of served zone to extra zone details.";
|
||||
default = {};
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
||||
config.fudo = {
|
||||
zones = mapAttrs (zone-name: zone-cfg: let
|
||||
domain-name = zone-cfg.domain;
|
||||
domain = config.fudo.domains.${domain-name};
|
||||
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);
|
||||
|
||||
make-srv-record = port: host: {
|
||||
inherit port host;
|
||||
};
|
||||
zones = mapAttrs (zone-name: zone-cfg:
|
||||
let
|
||||
domain-name = zone-cfg.domain;
|
||||
domain = config.fudo.domains.${domain-name};
|
||||
|
||||
served-domain = domain.primary-nameserver != null;
|
||||
make-srv-record = port: host: { inherit port host; };
|
||||
|
||||
primary-nameserver = domain.primary-nameserver;
|
||||
served-domain = domain.primary-nameserver != null;
|
||||
|
||||
is-primary-nameserver = hostname == primary-nameserver;
|
||||
primary-nameserver = domain.primary-nameserver;
|
||||
|
||||
internal-nameserver-hostnames =
|
||||
[domain.primary-nameserver] ++ domain.secondary-nameservers;
|
||||
is-primary-nameserver = hostname == primary-nameserver;
|
||||
|
||||
get-host-deets = description: hostname: {
|
||||
ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
|
||||
ipv6-address = pkgs.lib.network.host-ipv6 config hostname;
|
||||
description = description;
|
||||
};
|
||||
internal-nameserver-hostnames = [ domain.primary-nameserver ]
|
||||
++ domain.secondary-nameservers;
|
||||
|
||||
get-ns-deets = hostname: let
|
||||
host-domain = config.fudo.hosts.${hostname}.domain;
|
||||
desc = "${domain-name} nameserver ${hostname}.${host-domain}.";
|
||||
in get-host-deets desc hostname;
|
||||
get-host-deets = description: hostname: {
|
||||
ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
|
||||
ipv6-address = pkgs.lib.network.host-ipv6 config hostname;
|
||||
description = description;
|
||||
};
|
||||
|
||||
nameserver-deets = let
|
||||
internal-nameservers = map get-ns-deets internal-nameserver-hostnames;
|
||||
in internal-nameservers ++ zone-cfg.external-nameservers;
|
||||
get-ns-deets = hostname:
|
||||
let
|
||||
host-domain = config.fudo.hosts.${hostname}.domain;
|
||||
desc = "${domain-name} nameserver ${hostname}.${host-domain}.";
|
||||
in get-host-deets desc hostname;
|
||||
|
||||
has-auth-hostname = ns-host: ns-opts:
|
||||
(hasAttr "authoritative-hostname" ns-opts) &&
|
||||
(ns-opts.authoritative-hostname != null);
|
||||
nameserver-deets = let
|
||||
internal-nameservers = map get-ns-deets internal-nameserver-hostnames;
|
||||
in internal-nameservers ++ zone-cfg.external-nameservers;
|
||||
|
||||
all-nameservers = listToAttrs
|
||||
(imap1
|
||||
(i: nsOpts:
|
||||
nameValuePair "ns${toString i}" nsOpts)
|
||||
nameserver-deets);
|
||||
has-auth-hostname = ns-host: ns-opts:
|
||||
(hasAttr "authoritative-hostname" ns-opts)
|
||||
&& (ns-opts.authoritative-hostname != null);
|
||||
|
||||
nameserver-aliases =
|
||||
mapAttrs (hostname: opts: "${opts.authoritative-hostname}.")
|
||||
all-nameservers = listToAttrs
|
||||
(imap1 (i: nsOpts: nameValuePair "ns${toString i}" nsOpts)
|
||||
nameserver-deets);
|
||||
|
||||
nameserver-aliases =
|
||||
mapAttrs (hostname: opts: "${opts.authoritative-hostname}.")
|
||||
(filterAttrs has-auth-hostname all-nameservers);
|
||||
|
||||
nameserver-hosts = mapAttrs (hostname: opts: {
|
||||
inherit (opts) ipv4-address ipv6-address description;
|
||||
}) (filterAttrs (hostname: opts: ! has-auth-hostname hostname opts)
|
||||
all-nameservers);
|
||||
nameserver-hosts = mapAttrs (hostname: opts: {
|
||||
inherit (opts) ipv4-address ipv6-address description;
|
||||
}) (filterAttrs (hostname: opts: !has-auth-hostname hostname opts)
|
||||
all-nameservers);
|
||||
|
||||
dns-srv-records = let
|
||||
nameserver-srv-records = mapAttrsToList
|
||||
(hostname: hostOpts: let
|
||||
target-host = if (has-auth-hostname hostname hostOpts) then
|
||||
"${hostOpts.authoritative-hostname}" else
|
||||
dns-srv-records = let
|
||||
nameserver-srv-records = mapAttrsToList (hostname: hostOpts:
|
||||
let
|
||||
target-host = if (has-auth-hostname hostname hostOpts) then
|
||||
"${hostOpts.authoritative-hostname}"
|
||||
else
|
||||
"${hostname}.${domain-name}";
|
||||
in make-srv-record 53 target-host)
|
||||
all-nameservers;
|
||||
in {
|
||||
tcp.domain = nameserver-srv-records;
|
||||
udp.domain = nameserver-srv-records;
|
||||
};
|
||||
|
||||
# TODO: move this to a mail service
|
||||
mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
|
||||
tcp = let
|
||||
mailserver-domain = config.fudo.hosts.${domain.primary-mailserver}.domain;
|
||||
fqdn = "mail.${mailserver-domain}";
|
||||
in make-srv-record 53 target-host) all-nameservers;
|
||||
in {
|
||||
smtp = [(make-srv-record 25 fqdn)];
|
||||
submission = [(make-srv-record 587 fqdn)];
|
||||
imap = [(make-srv-record 143 fqdn)];
|
||||
imaps = [(make-srv-record 993 fqdn)];
|
||||
pop3 = [(make-srv-record 110 fqdn)];
|
||||
pop3s = [(make-srv-record 995 fqdn)];
|
||||
tcp.domain = nameserver-srv-records;
|
||||
udp.domain = nameserver-srv-records;
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
gssapi-realm = domain.gssapi-realm;
|
||||
# # TODO: move this to a mail service
|
||||
# mail-srv-records = optionalAttrs (domain.primary-mailserver != null) {
|
||||
# tcp = let
|
||||
# mailserver-domain =
|
||||
# config.fudo.hosts.${domain.primary-mailserver}.domain;
|
||||
# fqdn = "mail.${mailserver-domain}";
|
||||
# in {
|
||||
# smtp = [ (make-srv-record 25 fqdn) ];
|
||||
# submission = [ (make-srv-record 587 fqdn) ];
|
||||
# imap = [ (make-srv-record 143 fqdn) ];
|
||||
# imaps = [ (make-srv-record 993 fqdn) ];
|
||||
# pop3 = [ (make-srv-record 110 fqdn) ];
|
||||
# pop3s = [ (make-srv-record 995 fqdn) ];
|
||||
# };
|
||||
# };
|
||||
|
||||
hosts = nameserver-hosts // {
|
||||
mail = mkIf (domain.primary-nameserver != null) (let
|
||||
mailserver-deets = host: let
|
||||
host-domain = config.fudo.hosts.${host}.domain;
|
||||
in get-host-deets "Primary ${domain-name} mailserver ${host}.${host-domain}." host;
|
||||
in mailserver-deets domain.primary-nameserver);
|
||||
};
|
||||
in {
|
||||
gssapi-realm = domain.gssapi-realm;
|
||||
|
||||
aliases = nameserver-aliases;
|
||||
hosts = nameserver-hosts // {
|
||||
mail = mkIf (domain.primary-nameserver != null) (let
|
||||
mailserver-deets = host:
|
||||
let host-domain = config.fudo.hosts.${host}.domain;
|
||||
in get-host-deets
|
||||
"Primary ${domain-name} mailserver ${host}.${host-domain}." host;
|
||||
in mailserver-deets domain.primary-nameserver);
|
||||
};
|
||||
|
||||
mx = optional (domain.primary-mailserver != null)
|
||||
(let
|
||||
mail-domain-name = config.fudo.hosts.${domain.primary-mailserver}.domain;
|
||||
in "mail.${mail-domain-name}");
|
||||
aliases = nameserver-aliases;
|
||||
|
||||
dmarc-report-address = "dmarc-report@${domain-name}";
|
||||
mx = optional (domain.primary-mailserver != null) (let
|
||||
mail-domain-name =
|
||||
config.fudo.hosts.${domain.primary-mailserver}.domain;
|
||||
in "mail.${mail-domain-name}");
|
||||
|
||||
nameservers = let
|
||||
direct-external = attrValues nameserver-aliases;
|
||||
internal = map (hostname: "${hostname}.${domain-name}.")
|
||||
(attrNames nameserver-hosts);
|
||||
in internal ++ direct-external;
|
||||
dmarc-report-address = "dmarc-report@${domain-name}";
|
||||
|
||||
srv-records = dns-srv-records // mail-srv-records;
|
||||
}) cfg.zones;
|
||||
nameservers = let
|
||||
direct-external = attrValues nameserver-aliases;
|
||||
internal = map (hostname: "${hostname}.${domain-name}.")
|
||||
(attrNames nameserver-hosts);
|
||||
in internal ++ direct-external;
|
||||
|
||||
dns = let
|
||||
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}";
|
||||
srv-records = dns-srv-records; # // mail-srv-records;
|
||||
|
||||
is-primary-nameserver = primary-nameserver == hostname;
|
||||
in {
|
||||
verbatim-dns-records = mkIf (zone-cfg.ksk != null) [
|
||||
(readFile zone-cfg.ksk.public-key)
|
||||
(readFile zone-cfg.ksk.ds)
|
||||
];
|
||||
}) cfg.zones;
|
||||
|
||||
dns = {
|
||||
enable = is-primary-nameserver;
|
||||
|
||||
identity = "${hostname}.${domain-name}";
|
||||
|
@ -207,11 +245,11 @@ in {
|
|||
(pkgs.lib.network.host-ips config hostname);
|
||||
|
||||
domains = mapAttrs' (zone-name: zone-cfg:
|
||||
nameValuePair zone-cfg.domain
|
||||
{
|
||||
dnssec = true;
|
||||
zone-definition = config.fudo.zones.${zone-name};
|
||||
}) cfg.zones;
|
||||
nameValuePair zone-cfg.domain {
|
||||
dnssec = zone-cfg.ksk != null;
|
||||
ksk.key-file = host-secrets."${zoneKeySecret zone-name}".target-file;
|
||||
zone-definition = config.fudo.zones.${zone-name};
|
||||
}) 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
|
||||
hostname = config.instance.hostname;
|
||||
domain-name = config.fudo.services.auth.domain;
|
||||
domain = config.fudo.domains.${domain-name};
|
||||
|
||||
realm = domain.gssapi-realm;
|
||||
|
||||
zone-name = domain.zone;
|
||||
|
||||
ldap-server = elem hostname domain.ldap-servers;
|
||||
|
@ -19,6 +21,11 @@ let
|
|||
|
||||
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 {
|
||||
options.fudo.services.auth = with types; {
|
||||
domain = mkOption {
|
||||
|
@ -30,20 +37,23 @@ in {
|
|||
ldap = {
|
||||
hostname = mkOption {
|
||||
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;
|
||||
};
|
||||
|
||||
state-directory = mkOption {
|
||||
type = str;
|
||||
description = "Directory at which to store peristent ldap-related data.";
|
||||
description =
|
||||
"Directory at which to store peristent ldap-related data.";
|
||||
};
|
||||
};
|
||||
|
||||
kerberos = {
|
||||
hostname = mkOption {
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -56,15 +66,64 @@ in {
|
|||
type = str;
|
||||
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 = {
|
||||
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 = {
|
||||
acme.host-domains.${hostname} = mkIf (ldap-server) {
|
||||
${cfg.ldap.hostname}.local-copies.openldap = {
|
||||
|
@ -73,52 +132,110 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
auth = {
|
||||
ldap-server = mkIf (ldap-server)
|
||||
(let
|
||||
ldap-cert-copy =
|
||||
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
|
||||
in {
|
||||
enable = ldap-server;
|
||||
base = "dc=fudo,dc=org";
|
||||
organization = "Fudo";
|
||||
listen-uris = [ "ldap:///" "ldaps:///" ];
|
||||
required-services = [ ldap-cert-copy.service ];
|
||||
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;
|
||||
};
|
||||
|
||||
# TODO: Maybe filter to Fudo-only?
|
||||
users = config.fudo.users;
|
||||
groups = config.fudo.groups;
|
||||
system-users = config.fudo.system-users;
|
||||
|
||||
state-directory = "${cfg.ldap.state-directory}";
|
||||
|
||||
ssl-chain = ldap-cert-copy.chain;
|
||||
ssl-certificate = ldap-cert-copy.certificate;
|
||||
ssl-private-key = ldap-cert-copy.private-key;
|
||||
ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
|
||||
});
|
||||
|
||||
kdc = mkIf (kerberos-master || kerberos-slave) {
|
||||
enable = true;
|
||||
realm = domain.gssapi-realm;
|
||||
bind-addresses =
|
||||
(pkgs.lib.network.host-ips config hostname) ++
|
||||
[ "127.0.0.1" ] ++ (optional config.networking.enableIPv6 "::1");
|
||||
state-directory = cfg.kerberos.state-directory;
|
||||
master-key-file = cfg.kerberos.master-key-file;
|
||||
master-config = mkIf (kerberos-master) {
|
||||
acl = let
|
||||
admin-entries = genAttrs config.instance.local-admins
|
||||
(admin: {
|
||||
perms = [ "add" "change-password" "list" ];
|
||||
});
|
||||
in admin-entries // {
|
||||
"*/root".perms = [ "all" ];
|
||||
};
|
||||
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" ];
|
||||
};
|
||||
slave-config = mkIf (kerberos-slave) {
|
||||
master-host = domain.kerberos-master;
|
||||
ipropd-keytab = cfg.kerberos.ipropd-keytab;
|
||||
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 = {
|
||||
ldap-server = mkIf ldap-server (let
|
||||
ldap-cert-copy =
|
||||
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
|
||||
in {
|
||||
enable = ldap-server;
|
||||
base = "dc=fudo,dc=org";
|
||||
organization = "Fudo";
|
||||
listen-uris = [ "ldap:///" "ldaps:///" ];
|
||||
required-services = [ ldap-cert-copy.service ];
|
||||
|
||||
# TODO: Maybe filter to Fudo-only?
|
||||
users = config.fudo.users;
|
||||
groups = config.fudo.groups;
|
||||
system-users = config.fudo.system-users;
|
||||
|
||||
state-directory = "${cfg.ldap.state-directory}";
|
||||
|
||||
ssl-chain = ldap-cert-copy.chain;
|
||||
ssl-certificate = ldap-cert-copy.certificate;
|
||||
ssl-private-key = ldap-cert-copy.private-key;
|
||||
ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
|
||||
});
|
||||
|
||||
kerberos = {
|
||||
inherit realm;
|
||||
kdc = mkIf (kerberos-master || kerberos-slave) {
|
||||
state-directory = cfg.kerberos.state-directory;
|
||||
master-key-file = host-secrets.realm-master-key.target-file;
|
||||
primary = mkIf kerberos-master {
|
||||
enable = true;
|
||||
acl = let
|
||||
adminEntries = genAttrs config.instance.local-admins
|
||||
(admin: { perms = [ "add" "change-password" "list" ]; });
|
||||
in adminEntries // { "*/root".perms = [ "all" ]; };
|
||||
secondary-servers = map getHostFqdn domain.kerberos-slaves;
|
||||
keytabs = {
|
||||
kadmind = host-secrets.kadmind-keytab.target-file;
|
||||
kpasswdd = host-secrets.kpasswdd-keytab.target-file;
|
||||
hprop = host-secrets.hprop-keytab.target-file;
|
||||
};
|
||||
};
|
||||
secondary = mkIf kerberos-slave {
|
||||
enable = true;
|
||||
keytabs.hpropd = host-secrets.hpropd-keytab.target-file;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -129,19 +246,20 @@ in {
|
|||
host = hostname;
|
||||
};
|
||||
|
||||
get-fqdn = host:
|
||||
"${host}.${config.fudo.hosts.${host}.domain}";
|
||||
get-fqdn = host: "${host}.${config.fudo.hosts.${host}.domain}";
|
||||
|
||||
kerberos-master-hosts = optional (kerberized-domain)
|
||||
domain.kerberos-master;
|
||||
kerberos-master-hosts =
|
||||
optional (kerberized-domain) domain.kerberos-master;
|
||||
|
||||
kerberos-servers = map get-fqdn
|
||||
(kerberos-master-hosts ++ domain.kerberos-slaves);
|
||||
kerberos-servers =
|
||||
map get-fqdn (kerberos-master-hosts ++ domain.kerberos-slaves);
|
||||
|
||||
kerberos-masters = map get-fqdn kerberos-master-hosts;
|
||||
|
||||
ldap-servers = map get-fqdn domain.ldap-servers;
|
||||
in {
|
||||
gssapi-realm = realm;
|
||||
|
||||
srv-records = {
|
||||
tcp = {
|
||||
kerberos = map (make-srv-record 88) kerberos-servers;
|
||||
|
|
|
@ -12,7 +12,7 @@ let
|
|||
mailserver-domain-name = config.fudo.hosts.${mailserver-host}.domain;
|
||||
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;
|
||||
|
||||
|
@ -94,15 +94,12 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
zones = mkIf isLocalMailserver {
|
||||
zones = {
|
||||
${mailserver-domain.zone} = let
|
||||
server-ipv4 = pkgs.lib.network.host-ipv4 config mailserver-host;
|
||||
server-ipv6 = pkgs.lib.network.host-ipv6 config mailserver-host;
|
||||
|
||||
srv-record = host: port: [{
|
||||
host = "${host}.${mailserver-domain-name}";
|
||||
port = port;
|
||||
}];
|
||||
srv-record = host: port: [{ inherit host port; }];
|
||||
|
||||
in {
|
||||
hosts = genAttrs [ "imap" "smtp" ] (alias: {
|
||||
|
@ -114,18 +111,17 @@ in {
|
|||
|
||||
mx = [ "smtp.${mailserver-domain-name}" ];
|
||||
|
||||
aliases =
|
||||
mkIf metricsEnabled { mail-stats = "${mailserver-host-fqdn}."; };
|
||||
aliases = mkIf metricsEnabled { mail-stats = "${mailserver-fqdn}."; };
|
||||
|
||||
srv-records.tcp = {
|
||||
pop3 = srv-record "imap" 110;
|
||||
pop3s = srv-record "imap" 995;
|
||||
pop3 = srv-record mailserver-fqdn 110;
|
||||
pop3s = srv-record mailserver-fqdn 995;
|
||||
|
||||
imap = srv-record "imap" 143;
|
||||
imaps = srv-record "imap" 993;
|
||||
imap = srv-record mailserver-fqdn 143;
|
||||
imaps = srv-record mailserver-fqdn 993;
|
||||
|
||||
smtp = srv-record "smtp" 25;
|
||||
submission = srv-record "smtp" 587;
|
||||
smtp = srv-record mailserver-fqdn 25;
|
||||
submission = srv-record mailserver-fqdn 587;
|
||||
};
|
||||
|
||||
metric-records = mkIf metricsEnabled
|
||||
|
@ -167,8 +163,7 @@ in {
|
|||
ssl-private-key = cert-copy.private-key;
|
||||
};
|
||||
|
||||
local-domains =
|
||||
[ mailserver-host-fqdn "smtp.${mailserver-domain-name}" ];
|
||||
local-domains = [ mailserver-fqdn "smtp.${mailserver-domain-name}" ];
|
||||
|
||||
mail-directory = "${cfg.state-directory}/mail";
|
||||
state-directory = "${cfg.state-directory}/state";
|
||||
|
|
|
@ -6,8 +6,6 @@ let
|
|||
domain-name = config.fudo.hosts.${hostname}.domain;
|
||||
domain = config.fudo.domains.${domain-name};
|
||||
|
||||
pthru = obj: builtins.trace "TRACE(${hostname}): ${toString obj}" obj;
|
||||
|
||||
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
||||
|
||||
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};
|
||||
|
||||
postgresEnabled = domain.postgresql-server == hostname;
|
||||
publicNetwork = let
|
||||
site-name = config.fudo.hosts.${hostname}.site;
|
||||
publicNetwork = let site-name = config.fudo.hosts.${hostname}.site;
|
||||
in config.fudo.sites.${site-name}.local-gateway == null;
|
||||
isPostgresHost = hostname == domain.postgresql-server;
|
||||
|
||||
|
@ -32,7 +31,7 @@ in {
|
|||
};
|
||||
|
||||
keytab = mkOption {
|
||||
type = str;
|
||||
type = nullOr path;
|
||||
description = "Keytab for PostgreSQL.";
|
||||
};
|
||||
};
|
||||
|
@ -49,18 +48,20 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
secrets.host-secrets.${hostname}.postgres-keytab = mkIf (cfg.keytab != null) {
|
||||
source-file = cfg.keytab;
|
||||
target-file = "/run/postgresql/postgres.keytab";
|
||||
user = postgresUser;
|
||||
};
|
||||
secrets.host-secrets.${hostname}.postgres-keytab =
|
||||
mkIf (cfg.keytab != null) {
|
||||
source-file = cfg.keytab;
|
||||
target-file = "/run/postgresql/postgres.keytab";
|
||||
user = postgresUser;
|
||||
};
|
||||
|
||||
zones.${zone-name}.aliases.postgresql =
|
||||
"${domain.postgresql-server}.${domain-name}.";
|
||||
|
||||
postgresql = mkIf isPostgresHost (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 {
|
||||
ssl-certificate = mkIf publicNetwork cert-copy.full-certificate;
|
||||
ssl-private-key = mkIf publicNetwork cert-copy.private-key;
|
||||
|
@ -68,7 +69,8 @@ in {
|
|||
});
|
||||
in {
|
||||
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;
|
||||
state-directory = cfg.state-directory;
|
||||
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 {
|
||||
options.fudo.services.wallfly-presence = with types; {
|
||||
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 {
|
||||
|
@ -50,42 +31,30 @@ in {
|
|||
source-file = userOpts.password-file;
|
||||
target-file = "/run/wallfly-${username}/passwd";
|
||||
user = username;
|
||||
}) local-user-cfg) // (optionalAttrs is-mqtt-broker (mapAttrs'
|
||||
(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}.";
|
||||
};
|
||||
}) local-user-cfg);
|
||||
|
||||
wallfly = {
|
||||
enable = true;
|
||||
mqtt = {
|
||||
broker-uri =
|
||||
"tcp://${mqtt-broker}.${domain-name}:${toString cfg.mqtt.port}";
|
||||
mqtt = let
|
||||
mqtt-hostname = config.fudo.services.mqtt.mqtt-hostname;
|
||||
mqtt-port = config.fudo.services.mqtt.private.port;
|
||||
in {
|
||||
broker-uri = "tcp://${mqtt-hostname}:${toString mqtt-port}";
|
||||
username = "wallfly-$USER";
|
||||
password-file = "/run/wallfly-$USER/passwd";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
mosquitto = mkIf (is-mqtt-broker) {
|
||||
services.mqtt = {
|
||||
enable = true;
|
||||
listeners = [{
|
||||
settings.allow_anonymous = false;
|
||||
port = cfg.mqtt.port;
|
||||
address = cfg.mqtt.listen-address;
|
||||
private = {
|
||||
enable = true;
|
||||
users = mapAttrs' (username: userOpts:
|
||||
nameValuePair "wallfly-${username}" {
|
||||
passwordFile = "/run/wallfly-mqtt/${username}.passwd";
|
||||
password-file = userOpts.password-file;
|
||||
acl = [ "readwrite homeassistant/binary_sensor/#" ];
|
||||
}) user-cfg;
|
||||
}];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{
|
||||
imports = [
|
||||
./service/backplane.nix
|
||||
# ./service/backplane.nix
|
||||
./service/chat.nix
|
||||
./service/chute.nix
|
||||
./service/dns.nix
|
||||
|
@ -12,8 +12,12 @@
|
|||
./service/logging.nix
|
||||
./service/mail-server.nix
|
||||
./service/metrics.nix
|
||||
./service/mqtt.nix
|
||||
./service/nexus.nix
|
||||
./service/postgresql.nix
|
||||
./service/selby-forum.nix
|
||||
./service/suanni.nix
|
||||
./service/tattler.nix
|
||||
./service/wallfly-presence.nix
|
||||
# ./service/wireguard-gateway.nix
|
||||
];
|
||||
|
|
|
@ -3,9 +3,37 @@
|
|||
with lib;
|
||||
let local-domain = "sea.fudo.org";
|
||||
in {
|
||||
fudo.services.wallfly-presence = {
|
||||
enable = true;
|
||||
mqtt.broker-host = "wormhole0";
|
||||
fudo.services = {
|
||||
mqtt = {
|
||||
enable = true;
|
||||
host = "wormhole0";
|
||||
};
|
||||
|
||||
wallfly-presence.enable = true;
|
||||
|
||||
tattler = let snooper-host = "wormhole0";
|
||||
in {
|
||||
enable = true;
|
||||
verbose = true;
|
||||
event-topics = [ "suanni/events/motion" ];
|
||||
inherit snooper-host;
|
||||
};
|
||||
|
||||
suanni = let
|
||||
listener = "nostromo";
|
||||
objectifier = "lambda";
|
||||
in {
|
||||
enable = true;
|
||||
event-listener.host = listener;
|
||||
objectifier.host = objectifier;
|
||||
synology = {
|
||||
host = "cargo.sea.fudo.org";
|
||||
port = 5001;
|
||||
username = "suanni";
|
||||
password-file =
|
||||
config.fudo.secrets.files.service-passwords."${listener}".suanni-synology;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
|
@ -165,7 +193,6 @@ in {
|
|||
DefaultDependencies = false;
|
||||
ConditionPathExists =
|
||||
[ "|!/run/gssproxy.pid" "|!/proc/net/rpc/use-gss-proxy" ];
|
||||
Restart = "always";
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "forking";
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
uid = 10065;
|
||||
primary-group = "fudo";
|
||||
common-name = "Xiaoxuan Jin";
|
||||
ldap-hashed-passwd = "{MD5}iecbyMpyVkmOaMBzSFy58Q==";
|
||||
ldap-hashed-passwd = "{SSHA}04fLLUmqNUpOUJi3IBEja8bFNm0S6W60";
|
||||
login-hashed-passwd =
|
||||
"$6$C8lYHrK7KvdKm/RE$cHZ2hg5gEOEjTV8Zoayik8sz5h.Vh0.ClCgOlQn8l/2Qx/qdxqZ7xCsAZ1GZ.IEyESfhJeJbjLpykXDwPpfVF0";
|
||||
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";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-22.05";
|
||||
nixpkgs.url = "nixpkgs/nixos-22.11";
|
||||
|
||||
fudo-home = {
|
||||
url = "git+https://git.fudo.org/fudo-nix/home.git";
|
||||
# url = "path:/state/fudo-home";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
|
@ -15,15 +16,11 @@
|
|||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
fudo-lib = {
|
||||
url = "git+https://git.fudo.org/fudo-nix/lib.git";
|
||||
#url = "path:/state/fudo-lib";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
fudo-lib = { url = "git+https://git.fudo.org/fudo-nix/lib.git"; };
|
||||
|
||||
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";
|
||||
|
||||
|
@ -36,11 +33,21 @@
|
|||
nixpkgs2111.url = "nixpkgs/nixos-21.11";
|
||||
|
||||
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
|
||||
, fudo-secrets, chute, chuteUnstable, nixpkgsUnstable, nixpkgs2111, pricebot
|
||||
, wallfly, ... }@inputs:
|
||||
, wallfly, objectifier, nexus, suanni, snooper, tattler, ... }@inputs:
|
||||
with nixpkgs.lib;
|
||||
let
|
||||
fudo-nixos-hosts = filterAttrs (hostname: hostOpts: hostOpts.nixos-system)
|
||||
|
@ -60,11 +67,14 @@
|
|||
system = arch;
|
||||
config = {
|
||||
allowUnfree = true;
|
||||
permittedInsecurePackages = [ "openssh-with-gssapi-8.4p1" ];
|
||||
permittedInsecurePackages =
|
||||
[ "openssh-with-gssapi-8.4p1" "python3.10-certifi-2022.9.24" ];
|
||||
};
|
||||
overlays = [
|
||||
fudo-lib.overlay
|
||||
fudo-pkgs.overlay
|
||||
fudo-pkgs.overlays.default
|
||||
fudo-secrets.overlays.default
|
||||
fudo-entities.overlays.default
|
||||
(final: prev: {
|
||||
chute = chute.packages.${arch}.chute;
|
||||
chuteUnstable = chuteUnstable.packages.${arch}.chute;
|
||||
|
@ -76,7 +86,12 @@
|
|||
};
|
||||
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;
|
||||
in { config, ... }: {
|
||||
imports = [
|
||||
fudo-home.nixosModule
|
||||
fudo-secrets.nixosModule
|
||||
fudo-home.nixosModules.default
|
||||
fudo-secrets.nixosModules.default
|
||||
fudo-lib.nixosModule
|
||||
fudo-entities.nixosModule
|
||||
pricebot.nixosModules.default
|
||||
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-dir + "/hardware/${hostname}.nix")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
with lib;
|
||||
let
|
||||
nixos-version = "21.05";
|
||||
nixos-version = "22.05";
|
||||
|
||||
pkgs = import <nixpkgs> {
|
||||
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