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

This commit is contained in:
niten 2023-05-24 14:14:28 -07:00
commit a192aaab95
75 changed files with 5808 additions and 979 deletions

View File

@ -1,14 +1,13 @@
{ config, lib, pkgs, ... }:
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;

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,10 @@
{ config, lib, pkgs, ... }:
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 = {
@ -18,62 +13,60 @@ in {
enp4s0f0.useDHCP = false;
enp4s0f1.useDHCP = false;
intif0.useDHCP = true;
intif0 = {
useDHCP = false;
ipv4.addresses = [{
address = primaryIp;
prefixLength = 16;
}];
};
};
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"
];
defaultGateway = {
address = "10.0.0.1";
interface = "intif0";
};
};
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";
};
environment = {
etc = {
nixos.source = "/etc/nixos-live";
adjtime.source = "/state/host/adjtime";
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" ];
};
};
}

View File

@ -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 = {

View File

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

View File

@ -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 = {

View File

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

View File

@ -0,0 +1,14 @@
{ config, lib, pkgs, ... }:
{
config.fudo.minecraft-server = {
enable = true;
package = pkgs.minecraft-current;
data-dir = "/state/minecraft/data";
world-name = "selbyland";
game-mode = "creative";
difficulty = 2;
allow-cheats = true;
allocated-memory = 14;
};
}

View File

@ -1,6 +1,6 @@
{ config, lib, pkgs, ... }:
{ config, pkgs, ... }:
with lib;
with pkgs.lib;
let
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";
};
};
};
}

View File

@ -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,8 +49,8 @@ in {
};
"selby.ca" = {
enable = true;
external-nameservers = map (n: let
i = toString n;
external-nameservers = map (n:
let i = toString n;
in {
authoritative-hostname = "ns${i}.fudo.org";
description = "Nameserver ${i}, ns${i}.fudo.org.";
@ -82,9 +79,7 @@ in {
"rspamd._metrics._tcp IN SRV 0 0 443 mail.fudo.org."
];
};
"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" ]; };
};
};

View File

@ -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 = {
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 = {

View File

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

View File

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

View File

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

View File

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

View File

@ -6,13 +6,10 @@ let
primary-ip = "10.0.0.3";
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;
fudo.services.mqtt = {
enable = true;
state-directory = "${state-dir}/services/mosquitto";
private = {
enable = true;
users = {
zigbee2mqtt = {
password-file = zigbee2mqtt-passwd-file;
acl = [ "readwrite #" ];
};
mosquitto-home-assistant-passwd = {
source-file = host-passwds.mosquitto-home-assistant;
target-file = "/run/mosquitto-secrets/home-assistant.passwd";
user = mosquitto-user;
home-assistant = {
password-file = host-passwds.mosquitto-home-assistant;
acl = [ "readwrite #" ];
};
mosquitto-niten-passwd = {
source-file = host-passwds.mosquitto-niten;
target-file = "/run/mosquitto-secrets/niten.passwd";
user = mosquitto-user;
};
mosquitto-xiaoxuan-passwd = {
source-file = host-passwds.mosquitto-xiaoxuan;
target-file = "/run/mosquitto-secrets/xiaoxuan.passwd";
user = mosquitto-user;
};
mosquitto-wallfly-passwd = {
source-file = host-passwds.mosquitto-wallfly;
target-file = "/run/mosquitto-secrets/wallfly.passwd";
user = mosquitto-user;
};
};
@ -95,15 +82,6 @@ in {
RemainAfterExit = true;
};
};
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 #" ];
};
# 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 #" ];
# # 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/#" ];
# # };
# };
# 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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,8 +7,9 @@ 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;
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) {
@ -19,6 +20,22 @@ in {
# mode = "0400";
# };
krb5 = {
domain_realm = let
krbDoms = filterAttrs (_: domCfg: domCfg.gssapi-realm != null)
config.fudo.domains;
domClauses = dom: domCfg: [
(nameValuePair dom domCfg.gssapi-realm)
(nameValuePair ".${dom}" domCfg.gssapi-realm)
];
concatMapAttrs = f: lst:
listToAttrs (concatMap (i: i) (mapAttrsToList f lst));
in concatMapAttrs domClauses krbDoms;
libdefaults.default_etypes =
"aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96";
};
systemd = let
host-keytab =
config.fudo.secrets.host-secrets.${hostname}.host-keytab.target-file;

View File

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

View File

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

View File

@ -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,8 +51,8 @@ let
};
};
zoneOpts = { name, ... }: let
zone-name = name;
zoneOpts = { name, ... }:
let zone-name = name;
in {
options = with types; {
enable = mkOption {
@ -51,7 +63,8 @@ let
default-host = mkOption {
type = nullOr str;
description = "IP which will respond to requests for the base domain.";
description =
"IP which will respond to requests for the base domain.";
default = null;
};
@ -66,11 +79,31 @@ let
description = "Domain which this zone serves.";
default = zone-name;
};
};
};
pthru = obj:
builtins.trace "TRACE: ${ obj }" obj;
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}";
};
};
};
in {
options.fudo.services.dns = with types; {
@ -82,13 +115,20 @@ in {
};
config.fudo = {
zones = mapAttrs (zone-name: zone-cfg: let
secrets.host-secrets."${hostname}" = mkIf is-primary-nameserver (mapAttrs'
(zone: zone-cfg:
nameValuePair (zoneKeySecret zone) {
source-file = zone-cfg.ksk.private-key;
target-file = "/run/nsd/${baseNameOf zone-cfg.ksk.private-key}";
user = config.fudo.nsd.user;
}) cfg.zones);
zones = mapAttrs (zone-name: zone-cfg:
let
domain-name = zone-cfg.domain;
domain = config.fudo.domains.${domain-name};
make-srv-record = port: host: {
inherit port host;
};
make-srv-record = port: host: { inherit port host; };
served-domain = domain.primary-nameserver != null;
@ -96,8 +136,8 @@ in {
is-primary-nameserver = hostname == primary-nameserver;
internal-nameserver-hostnames =
[domain.primary-nameserver] ++ domain.secondary-nameservers;
internal-nameserver-hostnames = [ domain.primary-nameserver ]
++ domain.secondary-nameservers;
get-host-deets = description: hostname: {
ipv4-address = pkgs.lib.network.host-ipv4 config hostname;
@ -105,7 +145,8 @@ in {
description = description;
};
get-ns-deets = hostname: let
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;
@ -115,13 +156,11 @@ in {
in internal-nameservers ++ zone-cfg.external-nameservers;
has-auth-hostname = ns-host: ns-opts:
(hasAttr "authoritative-hostname" ns-opts) &&
(ns-opts.authoritative-hostname != null);
(hasAttr "authoritative-hostname" ns-opts)
&& (ns-opts.authoritative-hostname != null);
all-nameservers = listToAttrs
(imap1
(i: nsOpts:
nameValuePair "ns${toString i}" nsOpts)
(imap1 (i: nsOpts: nameValuePair "ns${toString i}" nsOpts)
nameserver-deets);
nameserver-aliases =
@ -134,49 +173,51 @@ in {
all-nameservers);
dns-srv-records = let
nameserver-srv-records = mapAttrsToList
(hostname: hostOpts: let
nameserver-srv-records = mapAttrsToList (hostname: hostOpts:
let
target-host = if (has-auth-hostname hostname hostOpts) then
"${hostOpts.authoritative-hostname}" else
"${hostOpts.authoritative-hostname}"
else
"${hostname}.${domain-name}";
in make-srv-record 53 target-host)
all-nameservers;
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 {
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)];
};
};
# # 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) ];
# };
# };
in {
gssapi-realm = domain.gssapi-realm;
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;
mailserver-deets = host:
let host-domain = config.fudo.hosts.${host}.domain;
in get-host-deets
"Primary ${domain-name} mailserver ${host}.${host-domain}." host;
in mailserver-deets domain.primary-nameserver);
};
aliases = nameserver-aliases;
mx = optional (domain.primary-mailserver != null)
(let
mail-domain-name = config.fudo.hosts.${domain.primary-mailserver}.domain;
mx = optional (domain.primary-mailserver != null) (let
mail-domain-name =
config.fudo.hosts.${domain.primary-mailserver}.domain;
in "mail.${mail-domain-name}");
dmarc-report-address = "dmarc-report@${domain-name}";
@ -187,18 +228,15 @@ in {
(attrNames nameserver-hosts);
in internal ++ direct-external;
srv-records = dns-srv-records // mail-srv-records;
srv-records = dns-srv-records; # // mail-srv-records;
verbatim-dns-records = mkIf (zone-cfg.ksk != null) [
(readFile zone-cfg.ksk.public-key)
(readFile zone-cfg.ksk.ds)
];
}) cfg.zones;
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}";
is-primary-nameserver = primary-nameserver == hostname;
in {
dns = {
enable = is-primary-nameserver;
identity = "${hostname}.${domain-name}";
@ -207,9 +245,9 @@ in {
(pkgs.lib.network.host-ips config hostname);
domains = mapAttrs' (zone-name: zone-cfg:
nameValuePair zone-cfg.domain
{
dnssec = true;
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;
};

View File

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

View File

@ -1,11 +1,13 @@
{ config, lib, pkgs, ... }:
{ config, pkgs, ... }:
with lib;
with pkgs.lib;
let
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,9 +132,66 @@ in {
};
};
secrets.host-secrets."${hostname}" = let
realm-key =
config.fudo.secrets.files.kerberos.realm-master-keys."${realm}";
in {
realm-master-key = mkIf (kerberos-master || kerberos-slave) {
source-file = realm-key;
target-file = "/run/kdc/realm.key";
user = krb-user;
group = krb-group;
};
kdc-principals = mkIf (kerberos-master || kerberos-slave) {
source-file =
config.fudo.secrets.files.kerberos.realm-principals."${realm}";
target-file = "/run/kdc/realm.principals";
user = krb-user;
group = krb-group;
};
kadmind-keytab = mkIf kerberos-master {
source-file = extractFudoKeytab {
inherit realm;
principals = [ "kadmin/admin" ];
};
target-file = "/run/kdc/kadmind.keytab";
user = krb-user;
group = krb-group;
};
kpasswdd-keytab = mkIf kerberos-master {
source-file = extractFudoKeytab {
inherit realm;
principals = [ "kadmin/changepw" ];
};
target-file = "/run/kdc/kpasswdd.keytab";
user = krb-user;
group = krb-group;
};
hprop-keytab =
mkIf (kerberos-master && (domain.kerberos-slaves != [ ])) {
source-file = extractFudoKeytab {
inherit realm;
principals = [ "kadmin/hprop" ];
};
target-file = "/run/kdc/hprop.keytab";
user = krb-user;
group = krb-group;
};
hpropd-keytab = mkIf kerberos-slave {
source-file = extractFudoHostKeytab {
inherit hostname realm;
services = [ "hprop" ];
};
target-file = "/run/kdc/hpropd.keytab";
user = krb-user;
group = krb-group;
};
};
auth = {
ldap-server = mkIf (ldap-server)
(let
ldap-server = mkIf ldap-server (let
ldap-cert-copy =
config.fudo.acme.host-domains.${hostname}.${cfg.ldap.hostname}.local-copies.openldap;
in {
@ -98,27 +214,28 @@ in {
ssl-ca-certificate = "${pkgs.letsencrypt-ca}";
});
kerberos = {
inherit realm;
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) {
master-key-file = host-secrets.realm-master-key.target-file;
primary = mkIf kerberos-master {
enable = true;
acl = let
admin-entries = genAttrs config.instance.local-admins
(admin: {
perms = [ "add" "change-password" "list" ];
});
in admin-entries // {
"*/root".perms = [ "all" ];
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;
};
};
slave-config = mkIf (kerberos-slave) {
master-host = domain.kerberos-master;
ipropd-keytab = cfg.kerberos.ipropd-keytab;
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;

View File

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

View File

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

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

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

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

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

View File

@ -13,8 +13,7 @@ let
host-secrets = config.fudo.secrets.host-secrets.${hostname};
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,7 +48,8 @@ in {
};
};
secrets.host-secrets.${hostname}.postgres-keytab = mkIf (cfg.keytab != null) {
secrets.host-secrets.${hostname}.postgres-keytab =
mkIf (cfg.keytab != null) {
source-file = cfg.keytab;
target-file = "/run/postgresql/postgres.keytab";
user = postgresUser;
@ -60,7 +60,8 @@ in {
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 ];

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

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

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

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

View File

@ -22,25 +22,6 @@ let
in {
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;
private = {
enable = true;
listeners = [{
settings.allow_anonymous = false;
port = cfg.mqtt.port;
address = cfg.mqtt.listen-address;
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;
}];
};
};
};
};

View File

@ -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
];

View File

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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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")

View File

@ -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.