summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sys/auth/login.nix7
-rw-r--r--sys/auth/oath.nix10
-rw-r--r--sys/auth/openssh.nix146
-rw-r--r--sys/baseline/default.nix38
-rw-r--r--sys/boot/chain.nix18
-rw-r--r--sys/boot/detached-luks.nix91
-rw-r--r--sys/boot/efi.nix15
-rw-r--r--sys/boot/firmware.nix14
-rw-r--r--sys/boot/fscrypt.nix17
-rw-r--r--sys/boot/impermanence.nix13
-rw-r--r--sys/boot/namespaced.nix27
-rw-r--r--sys/boot/secure-boot.nix12
-rw-r--r--sys/boot/stack/btrfs-toplevel-multidrive.nix21
-rw-r--r--sys/boot/stack/luks-ext4-fscrypt-impermanence.nix78
-rw-r--r--sys/boot/tpm.nix13
-rw-r--r--sys/btrfs/mounts.nix58
-rw-r--r--sys/btrfs/snapper.nix99
-rw-r--r--sys/default.nix8
-rw-r--r--sys/gitea/default.nix9
-rw-r--r--sys/hardware/altera.nix9
-rw-r--r--sys/hardware/apc.nix9
-rw-r--r--sys/hardware/athena.nix14
-rw-r--r--sys/hardware/bluetooth.nix9
-rw-r--r--sys/hardware/epson.nix10
-rw-r--r--sys/hardware/laptop.nix9
-rw-r--r--sys/hardware/printing.nix15
-rw-r--r--sys/hardware/thinkpad.nix18
-rw-r--r--sys/hardware/yubico.nix12
-rw-r--r--sys/home-assistant/hass.nix27
-rw-r--r--sys/home-assistant/yaml-extra.nix27
-rw-r--r--sys/jobs/pki-expiry/default.nix53
-rw-r--r--sys/kiosk/default.nix17
-rw-r--r--sys/mail/default.nix328
-rw-r--r--sys/mta/default.nix232
-rw-r--r--sys/net/fail2ban.nix10
-rw-r--r--sys/net/interfaces.nix10
-rw-r--r--sys/net/options.nix170
-rw-r--r--sys/net/vsock.nix88
-rw-r--r--sys/ns/mx.nix79
-rw-r--r--sys/ns/ns.nix237
-rw-r--r--sys/ns/nsd.nix23
-rw-r--r--sys/ns/ptr/default.nix6
-rw-r--r--sys/ns/ptr/gate-public-v4/default.nix6
-rw-r--r--sys/ns/ptr/gate-public-v4/serial.nix1
-rw-r--r--sys/ns/ptr/gate-public-v6/default.nix6
-rw-r--r--sys/ns/ptr/gate-public-v6/serial.nix1
-rw-r--r--sys/ns/ptr/static-prefix-v6/default.nix6
-rw-r--r--sys/ns/ptr/static-prefix-v6/serial.nix1
-rw-r--r--sys/ns/rr.nix764
-rw-r--r--sys/nspawn/dmz.nix129
-rw-r--r--sys/preset/dmz.nix12
-rw-r--r--sys/preset/user.nix11
-rw-r--r--sys/seat/default.nix49
-rw-r--r--sys/syncthing/default.nix15
-rw-r--r--sys/virt/libvirt.nix38
-rw-r--r--sys/web/nginx.nix17
-rw-r--r--sys/web/php-fpm.nix252
-rw-r--r--sys/web/sites/home.nix11
-rw-r--r--sys/web/sites/host.nix61
-rw-r--r--sys/web/sites/portal.nix15
60 files changed, 1910 insertions, 1591 deletions
diff --git a/sys/auth/login.nix b/sys/auth/login.nix
index 5bc8f2e..f252c1c 100644
--- a/sys/auth/login.nix
+++ b/sys/auth/login.nix
@@ -1,4 +1,9 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; {
# TODO
config = mkIf true {
diff --git a/sys/auth/oath.nix b/sys/auth/oath.nix
index 7030bab..6b00680 100644
--- a/sys/auth/oath.nix
+++ b/sys/auth/oath.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.auth.oath;
-in
-{
+in {
options.local.auth.oath = {
enable = lib.mkEnableOption "pam-oath";
};
diff --git a/sys/auth/openssh.nix b/sys/auth/openssh.nix
index 07e6977..44fb49a 100644
--- a/sys/auth/openssh.nix
+++ b/sys/auth/openssh.nix
@@ -1,15 +1,22 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.auth.openssh;
withOath = config.local.auth.oath.enable;
withPassword = config.local.auth.openssh.passwordAuthentication;
- port = if cfg.shiftPortNumber then 2234 else 22;
+ port =
+ if cfg.shiftPortNumber
+ then 2234
+ else 22;
restrict = cfg.restrictListen;
exemptList = optionals config.local.net.fail2ban.enable config.services.fail2ban.ignoreIP;
-in
-{
+in {
options.local.auth.openssh = {
enable = mkEnableOption "openssh";
tunnel.enable = mkEnableOption "ssh tunnel user";
@@ -23,28 +30,29 @@ in
type = types.bool;
default = false;
};
- }) [ "ecdsa" "ed25519" "rsa" ]);
+ }) ["ecdsa" "ed25519" "rsa"]);
restrictListen = mkOption {
default = null;
- type = with types; nullOr (submodule {
- options = {
- addresses = mkOption {
- type = listOf str;
+ type = with types;
+ nullOr (submodule {
+ options = {
+ addresses = mkOption {
+ type = listOf str;
+ };
+
+ interface = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ vsockCid = mkOption {
+ type = nullOr ints.u32;
+ default = null;
+ };
};
-
- interface = mkOption {
- type = nullOr str;
- default = null;
- };
-
- vsockCid = mkOption {
- type = nullOr ints.u32;
- default = null;
- };
- };
- });
+ });
};
passwordAuthentication = mkOption {
@@ -70,7 +78,7 @@ in
message = "SSH tunnel requires oath";
}
{
- assertion = restrict != null -> (restrict.vsockCid != null -> (restrict.interface == null && restrict.addresses == [ ]));
+ assertion = restrict != null -> (restrict.vsockCid != null -> (restrict.interface == null && restrict.addresses == []));
message = "SSH vsock restrict requires disabling inet";
}
{
@@ -88,11 +96,11 @@ in
];
local.boot.impermanence.files =
- flatten (map (key: [ key.path "${key.path}.pub" ]) config.services.openssh.hostKeys);
+ flatten (map (key: [key.path "${key.path}.pub"]) config.services.openssh.hostKeys);
networking.firewall = {
interfaces = optionalAttrs (restrict != null && restrict.interface != null) {
- ${restrict.interface}.allowedTCPPorts = [ port ];
+ ${restrict.interface}.allowedTCPPorts = [port];
};
allowedTCPPorts = optional (restrict == null || restrict.interface == null) port;
@@ -101,36 +109,41 @@ in
services.openssh = {
enable = true;
- ports = optional (restrict != null -> restrict.addresses != [ ]) port;
+ ports = optional (restrict != null -> restrict.addresses != []) port;
startWhenNeeded = mkDefault (!config.services.fail2ban.enable);
- extraConfig = optionalString (exemptList != [ ]) ''
- PerSourcePenaltyExemptList ${concatStringsSep "," exemptList}
- '' + optionalString cfg.tunnel.enable ''
- # User 'tunnel' has no password. Use PAM OATH
- # and connect with -N, forward with -R.
- Match User tunnel
- AllowTcpForwarding remote
- AllowStreamLocalForwarding no
- X11Forwarding no
- PermitTunnel no
- GatewayPorts no
- AllowAgentForwarding no
- PermitOpen none
- PermitListen 60220 60221 60222 60223 60224 60225 60226 60227 60228 60229
-
- Banner ${pkgs.writeText "tunnel-banner" ''
- This is a reverse tunnel
- ''}
- '';
-
- hostKeys = map
- (name: {
- path = "/etc/ssh/ssh_host_${name}_key";
- type = name;
- } // optionalAttrs (name == "rsa") {
- bits = 4096;
- })
+ extraConfig =
+ optionalString (exemptList != []) ''
+ PerSourcePenaltyExemptList ${concatStringsSep "," exemptList}
+ ''
+ + optionalString cfg.tunnel.enable ''
+ # User 'tunnel' has no password. Use PAM OATH
+ # and connect with -N, forward with -R.
+ Match User tunnel
+ AllowTcpForwarding remote
+ AllowStreamLocalForwarding no
+ X11Forwarding no
+ PermitTunnel no
+ GatewayPorts no
+ AllowAgentForwarding no
+ PermitOpen none
+ PermitListen 60220 60221 60222 60223 60224 60225 60226 60227 60228 60229
+
+ Banner ${pkgs.writeText "tunnel-banner" ''
+ This is a reverse tunnel
+ ''}
+ '';
+
+ hostKeys =
+ map
+ (name:
+ {
+ path = "/etc/ssh/ssh_host_${name}_key";
+ type = name;
+ }
+ // optionalAttrs (name == "rsa") {
+ bits = 4096;
+ })
(attrNames (filterAttrs (name: enable: enable) cfg.hostKeys));
settings = {
@@ -139,26 +152,29 @@ in
PasswordAuthentication = withOath || withPassword; # Necesario para oath, no reemplaza a oath
};
- listenAddresses = mkIf (restrict != null)
- (map (addr: { inherit addr; }) restrict.addresses);
+ listenAddresses =
+ mkIf (restrict != null)
+ (map (addr: {inherit addr;}) restrict.addresses);
};
systemd.sockets = mkIf (restrict != null && restrict.vsockCid != null) {
- sshd =
- let
- kernelMod = "modprobe@${if restrict.vsockCid == 2 then "vhost_" else ""}vsock.service";
- in
- {
- after = [ kernelMod ];
- wants = [ kernelMod ];
-
- socketConfig.ListenStream = mkForce [ "vsock:${toString restrict.vsockCid}:${toString port}" ];
- };
+ sshd = let
+ kernelMod = "modprobe@${
+ if restrict.vsockCid == 2
+ then "vhost_"
+ else ""
+ }vsock.service";
+ in {
+ after = [kernelMod];
+ wants = [kernelMod];
+
+ socketConfig.ListenStream = mkForce ["vsock:${toString restrict.vsockCid}:${toString port}"];
+ };
};
users.users = {
root = mkIf cfg.withDeployKeys {
- openssh.authorizedKeys.keyFiles = [ ./ssh-key.pub ];
+ openssh.authorizedKeys.keyFiles = [./ssh-key.pub];
};
tunnel = mkIf cfg.tunnel.enable {
diff --git a/sys/baseline/default.nix b/sys/baseline/default.nix
index 3a425f7..96654d8 100644
--- a/sys/baseline/default.nix
+++ b/sys/baseline/default.nix
@@ -1,4 +1,10 @@
-{ config, flakes, lib, pkgs, ... }:
+{
+ config,
+ flakes,
+ lib,
+ pkgs,
+ ...
+}:
with lib; {
config = {
# This value determines the NixOS release from which the default
@@ -10,30 +16,32 @@ with lib; {
system.stateVersion = "21.11"; # Did you read the comment?
environment = {
- pathsToLink = [ "/share/zsh" ];
-
- systemPackages = with pkgs; [
- git
- ] ++ optionals (!config.boot.isContainer) [
- lm_sensors
- lshw
- parted
- pciutils
- smartmontools
- usbutils
- ];
+ pathsToLink = ["/share/zsh"];
+
+ systemPackages = with pkgs;
+ [
+ git
+ ]
+ ++ optionals (!config.boot.isContainer) [
+ lm_sensors
+ lshw
+ parted
+ pciutils
+ smartmontools
+ usbutils
+ ];
};
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
- extraSpecialArgs = { inherit flakes; };
+ extraSpecialArgs = {inherit flakes;};
};
lib.local = pkgs.local.lib;
- local.boot.impermanence.directories = [ "/var/lib/dhparams" ];
+ local.boot.impermanence.directories = ["/var/lib/dhparams"];
nix = {
package = pkgs.nix;
diff --git a/sys/boot/chain.nix b/sys/boot/chain.nix
index aeb3bbe..43edcb4 100644
--- a/sys/boot/chain.nix
+++ b/sys/boot/chain.nix
@@ -1,11 +1,15 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot;
-in
-{
+in {
options.local.boot = {
loader = mkOption {
- type = types.enum [ "none" "grub" "systemd-boot" ];
+ type = types.enum ["none" "grub" "systemd-boot"];
};
kernel = mkOption {
@@ -18,13 +22,15 @@ in
kernelPackages = cfg.kernel;
loader =
- if cfg.loader == "grub" then {
+ if cfg.loader == "grub"
+ then {
grub = {
enable = true;
device = "nodev";
efiSupport = true;
};
- } else {
+ }
+ else {
systemd-boot = {
enable = true;
editor = true;
diff --git a/sys/boot/detached-luks.nix b/sys/boot/detached-luks.nix
index 8be7de1..78ae35c 100644
--- a/sys/boot/detached-luks.nix
+++ b/sys/boot/detached-luks.nix
@@ -1,4 +1,9 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot.detachedLuks;
@@ -6,8 +11,7 @@ with lib; let
tpmInitrd = config.local.boot.tpm.initrd.enable;
pcrList = concatStringsSep "," (map toString config.local.boot.tpm.initrd.pcrs);
-in
-{
+in {
options.local.boot.detachedLuks = {
enable = mkEnableOption "detached LUKS header in initrd";
@@ -30,43 +34,43 @@ in
};
config = mkIf cfg.enable {
- boot.initrd =
- let
- headerPath = "/initrd-boot/${cfg.headerFromBoot}";
- headerPathEscaped = escapeShellArg headerPath;
-
- tpmPath = escapeShellArg "/initrd-boot/${cfg.tpmStorageFromBoot}";
- hardwareKeyPath = "/tpm/unsealed.luks-key";
- in
- {
- preDeviceCommands = ''
- mkdir -p `dirname ${headerPathEscaped}`
- touch ${headerPathEscaped}
- '';
-
- postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) ''
- # Set the system time from the hardware clock to work around a
- # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
- # to the *boot time* of the host).
- hwclock -s
- '';
-
- #FIXME: Demasiado vulgar
- preLVMCommands = optionalString (config.local.boot.efi.enable && config.local.boot.efi.removable) ''
- sleep 2
- '';
-
- luks.devices.${cfg.target} = {
- device = cfg.crypt;
- header = headerPath;
- preLVM = false;
-
- keyFile = mkIf tpmInitrd hardwareKeyPath;
- fallbackToPassword = tpmInitrd;
-
- preOpenCommands = ''
+ boot.initrd = let
+ headerPath = "/initrd-boot/${cfg.headerFromBoot}";
+ headerPathEscaped = escapeShellArg headerPath;
+
+ tpmPath = escapeShellArg "/initrd-boot/${cfg.tpmStorageFromBoot}";
+ hardwareKeyPath = "/tpm/unsealed.luks-key";
+ in {
+ preDeviceCommands = ''
+ mkdir -p `dirname ${headerPathEscaped}`
+ touch ${headerPathEscaped}
+ '';
+
+ postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) ''
+ # Set the system time from the hardware clock to work around a
+ # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
+ # to the *boot time* of the host).
+ hwclock -s
+ '';
+
+ #FIXME: Demasiado vulgar
+ preLVMCommands = optionalString (config.local.boot.efi.enable && config.local.boot.efi.removable) ''
+ sleep 2
+ '';
+
+ luks.devices.${cfg.target} = {
+ device = cfg.crypt;
+ header = headerPath;
+ preLVM = false;
+
+ keyFile = mkIf tpmInitrd hardwareKeyPath;
+ fallbackToPassword = tpmInitrd;
+
+ preOpenCommands =
+ ''
mount -o ro -t ${bootFs.fsType} ${bootFs.device} /initrd-boot
- '' + optionalString tpmInitrd ''
+ ''
+ + optionalString tpmInitrd ''
mkdir /tpm
touch ${escapeShellArg hardwareKeyPath}
@@ -92,18 +96,19 @@ in
unseal_tpm_key
'';
- postOpenCommands = mkBefore (''
+ postOpenCommands = mkBefore (''
umount /initrd-boot
- '' + optionalString tpmInitrd ''
+ ''
+ + optionalString tpmInitrd ''
rm -r /tpm
'');
- };
};
+ };
local.boot = {
stack = {
btrfsToplevelMultidrive.toplevel.device = "/dev/mapper/${cfg.target}";
- luksExt4FscryptImpermanence = { inherit (cfg) target; };
+ luksExt4FscryptImpermanence = {inherit (cfg) target;};
};
tpm.initrd.enable = mkDefault config.local.boot.tpm.enable;
diff --git a/sys/boot/efi.nix b/sys/boot/efi.nix
index cbcefd9..71c42c8 100644
--- a/sys/boot/efi.nix
+++ b/sys/boot/efi.nix
@@ -1,14 +1,17 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.boot.efi;
-in
-{
+in {
options.local.boot.efi = {
enable = mkEnableOption "EFI with FAT32 system partition";
esp = {
mountpoint = mkOption {
- type = types.enum [ "/boot" "/boot/efi" ];
+ type = types.enum ["/boot" "/boot/efi"];
default = "/boot";
};
@@ -24,7 +27,7 @@ in
config = mkIf cfg.enable {
boot = {
- initrd.supportedFilesystems = [ "vfat" ];
+ initrd.supportedFilesystems = ["vfat"];
loader = {
efi = {
@@ -39,7 +42,7 @@ in
fileSystems.${cfg.esp.mountpoint} = {
device = "/dev/disk/by-uuid/${cfg.esp.uuid}";
fsType = "vfat";
- options = [ "noatime" "umask=027" "sync" ];
+ options = ["noatime" "umask=027" "sync"];
neededForBoot = true;
};
};
diff --git a/sys/boot/firmware.nix b/sys/boot/firmware.nix
index 70a3c4b..b3598a7 100644
--- a/sys/boot/firmware.nix
+++ b/sys/boot/firmware.nix
@@ -1,15 +1,19 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot.firmware;
-in
-{
+in {
options.local.boot.firmware = {
mode = mkOption {
- type = types.enum [ "none" "redistributable" "all" ];
+ type = types.enum ["none" "redistributable" "all"];
};
cpuVendor = mkOption {
- type = types.enum [ "amd" "intel" ];
+ type = types.enum ["amd" "intel"];
};
};
diff --git a/sys/boot/fscrypt.nix b/sys/boot/fscrypt.nix
index e6a745c..459e02b 100644
--- a/sys/boot/fscrypt.nix
+++ b/sys/boot/fscrypt.nix
@@ -1,18 +1,25 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot.fscrypt;
-in
-{
+in {
options.local.boot.fscrypt = {
enable = mkEnableOption "fscrypt support";
};
config = mkIf cfg.enable {
- environment.systemPackages = [ pkgs.fscrypt-experimental ];
+ environment.systemPackages = [pkgs.fscrypt-experimental];
local.boot.impermanence = {
directories = [
- { directory = "/.fscrypt"; mode = "u=rwx,g=rx,o=rx"; }
+ {
+ directory = "/.fscrypt";
+ mode = "u=rwx,g=rx,o=rx";
+ }
];
files = [
diff --git a/sys/boot/impermanence.nix b/sys/boot/impermanence.nix
index 4902239..632094b 100644
--- a/sys/boot/impermanence.nix
+++ b/sys/boot/impermanence.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.boot.impermanence;
-in
-{
+in {
options.local.boot.impermanence = {
enable = mkEnableOption "root fs impermanence";
@@ -10,12 +13,12 @@ in
directories = mkOption {
type = with lib.types; listOf (either str attrs);
- default = [ ];
+ default = [];
};
files = mkOption {
type = with lib.types; listOf (either str attrs);
- default = [ ];
+ default = [];
};
};
diff --git a/sys/boot/namespaced.nix b/sys/boot/namespaced.nix
index db01d55..3f95960 100644
--- a/sys/boot/namespaced.nix
+++ b/sys/boot/namespaced.nix
@@ -1,8 +1,12 @@
-{ config, lib, options, ... }:
+{
+ config,
+ lib,
+ options,
+ ...
+}:
with lib; let
cfg = config.local.boot.namespaced;
-in
-{
+in {
options.local.boot.namespaced = {
enable = mkEnableOption "system containerization";
};
@@ -11,15 +15,16 @@ in
boot.isContainer = true;
local.boot = mkMerge ([
- {
- loader = mkForce "none";
+ {
+ loader = mkForce "none";
- efi.enable = mkForce false;
- firmware.mode = mkForce "none";
- secureBoot.enable = mkForce false;
- impermanence.enable = mkForce false;
- }
- ] ++ map
+ efi.enable = mkForce false;
+ firmware.mode = mkForce "none";
+ secureBoot.enable = mkForce false;
+ impermanence.enable = mkForce false;
+ }
+ ]
+ ++ map
(name: {
stack.${name}.enable = mkForce false;
})
diff --git a/sys/boot/secure-boot.nix b/sys/boot/secure-boot.nix
index 3e874c3..b13ab7c 100644
--- a/sys/boot/secure-boot.nix
+++ b/sys/boot/secure-boot.nix
@@ -1,4 +1,9 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot.secureBoot;
@@ -6,8 +11,7 @@ with lib; let
if cfg.legacyPath
then "/etc/secureboot"
else "/var/lib/sbctl";
-in
-{
+in {
options.local.boot.secureBoot = {
enable = mkEnableOption "secure boot";
@@ -42,6 +46,6 @@ in
pkgs.sbctl
];
- local.boot.impermanence.directories = [ pkiBundle ];
+ local.boot.impermanence.directories = [pkiBundle];
};
}
diff --git a/sys/boot/stack/btrfs-toplevel-multidrive.nix b/sys/boot/stack/btrfs-toplevel-multidrive.nix
index 1dbfa14..52db865 100644
--- a/sys/boot/stack/btrfs-toplevel-multidrive.nix
+++ b/sys/boot/stack/btrfs-toplevel-multidrive.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.boot.stack.btrfsToplevelMultidrive;
-in
-{
+in {
options.local.boot.stack.btrfsToplevelMultidrive = {
enable = mkEnableOption "filesystem stack: persistent btrfs toplevel with optional hdd drive";
@@ -80,15 +83,17 @@ in
};
};
- snapper = optionalAttrs cfg.toplevel.snapshot
+ snapper =
+ optionalAttrs cfg.toplevel.snapshot
{
root = "/";
- } // optionalAttrs cfg.secondary.snapshot {
- home = "/home";
- };
+ }
+ // optionalAttrs cfg.secondary.snapshot {
+ home = "/home";
+ };
};
# Asegura que /hdd sea descifrado antes de intentar montar /home
- fileSystems."/home".depends = [ "/hdd" ];
+ fileSystems."/home".depends = ["/hdd"];
};
}
diff --git a/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix b/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
index 72336d6..81feb60 100644
--- a/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
+++ b/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot.stack.luksExt4FscryptImpermanence;
-in
-{
+in {
options.local.boot.stack.luksExt4FscryptImpermanence = {
enable = mkEnableOption "filesystem stack: whatever LUKS approach+ext4+impermanence with per-boot keys";
@@ -30,60 +34,58 @@ in
# - /toplevel/boots/...
# - /toplevel/boots/last -> 2000-01-01T00:00:00-06:00 (mounted as /)
config = mkIf cfg.enable {
- boot.initrd.luks.devices.${cfg.target}.postOpenCommands =
- let
- fscryptctl = "${pkgs.fscryptctl}/bin/fscryptctl";
- in
- ''
- # FIXME: posiblemente algunos --make-* son innecesarios a partir de aquĆ­
- mkdir -p /mnt-root /mnt-toplevel
- mount -o noatime /dev/mapper/${cfg.target} /mnt-toplevel
- mount --make-private /mnt-toplevel
+ boot.initrd.luks.devices.${cfg.target}.postOpenCommands = let
+ fscryptctl = "${pkgs.fscryptctl}/bin/fscryptctl";
+ in ''
+ # FIXME: posiblemente algunos --make-* son innecesarios a partir de aquĆ­
+ mkdir -p /mnt-root /mnt-toplevel
+ mount -o noatime /dev/mapper/${cfg.target} /mnt-toplevel
+ mount --make-private /mnt-toplevel
- boot_stamp="$(date -Is)"
- root_from_toplevel="/mnt-toplevel/boots/$boot_stamp"
+ boot_stamp="$(date -Is)"
+ root_from_toplevel="/mnt-toplevel/boots/$boot_stamp"
- mkdir -p "$root_from_toplevel" /mnt-toplevel/boot-keys
- chmod 700 /mnt-toplevel/boot-keys
+ mkdir -p "$root_from_toplevel" /mnt-toplevel/boot-keys
+ chmod 700 /mnt-toplevel/boot-keys
- head -c64 /dev/urandom >/boot-key
- key_id=$(${fscryptctl} add_key /mnt-toplevel </boot-key)
- ${fscryptctl} set_policy "$key_id" "$root_from_toplevel"
- (umask 077; test -f /mnt-toplevel/boot-archive.pub && \
- ${pkgs.openssl}/bin/openssl pkeyutl -encrypt \
- -in /boot-key -pubin -inkey /mnt-toplevel/boot-archive.pub \
- -out "/mnt-toplevel/boot-keys/$boot_stamp.key.crypt")
- rm -f /boot-key
+ head -c64 /dev/urandom >/boot-key
+ key_id=$(${fscryptctl} add_key /mnt-toplevel </boot-key)
+ ${fscryptctl} set_policy "$key_id" "$root_from_toplevel"
+ (umask 077; test -f /mnt-toplevel/boot-archive.pub && \
+ ${pkgs.openssl}/bin/openssl pkeyutl -encrypt \
+ -in /boot-key -pubin -inkey /mnt-toplevel/boot-archive.pub \
+ -out "/mnt-toplevel/boot-keys/$boot_stamp.key.crypt")
+ rm -f /boot-key
- ln -Tsf "$boot_stamp" /mnt-toplevel/boots/last
- ln -Tsf "$boot_stamp.key.crypt" /mnt-toplevel/boot-keys/last.key.crypt
+ ln -Tsf "$boot_stamp" /mnt-toplevel/boots/last
+ ln -Tsf "$boot_stamp.key.crypt" /mnt-toplevel/boot-keys/last.key.crypt
- mount --bind "$root_from_toplevel" /mnt-root
- mount --make-shared /mnt-root
+ mount --bind "$root_from_toplevel" /mnt-root
+ mount --make-shared /mnt-root
- # mount --move es mala idea, ya que "moving a mount residing under a
- # shared mount is unsupported"
- mkdir -p /mnt-root/toplevel
- mount --bind /mnt-toplevel /mnt-root/toplevel
- mount --make-private /mnt-root/toplevel
- umount /mnt-toplevel
- '';
+ # mount --move es mala idea, ya que "moving a mount residing under a
+ # shared mount is unsupported"
+ mkdir -p /mnt-root/toplevel
+ mount --bind /mnt-toplevel /mnt-root/toplevel
+ mount --make-private /mnt-root/toplevel
+ umount /mnt-toplevel
+ '';
fileSystems = {
"/" = {
device = "none";
fsType = "ext4";
- options = [ "remount" ];
+ options = ["remount"];
};
"/nix" = {
device = "/persist/nix";
- options = [ "bind" ];
+ options = ["bind"];
};
"/persist" = {
device = "/toplevel/persist";
- options = [ "bind" ];
+ options = ["bind"];
neededForBoot = true;
};
};
diff --git a/sys/boot/tpm.nix b/sys/boot/tpm.nix
index 0e29066..ecc115b 100644
--- a/sys/boot/tpm.nix
+++ b/sys/boot/tpm.nix
@@ -1,4 +1,9 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.boot.tpm;
@@ -52,13 +57,12 @@ with lib; let
openssl dgst -sha256 -sign /dev/stdin -out auth.sig auth.policy
'';
};
-in
-{
+in {
options.local.boot.tpm = {
enable = mkEnableOption "Trusted Platform Module 2.0";
driver = mkOption {
- type = types.enum [ "tis" "crb" ];
+ type = types.enum ["tis" "crb"];
};
initrd = {
@@ -81,7 +85,6 @@ in
12 # kernel-config
13 # sysexts
14 # shim-policy
-
];
};
};
diff --git a/sys/btrfs/mounts.nix b/sys/btrfs/mounts.nix
index 133f08f..3863356 100644
--- a/sys/btrfs/mounts.nix
+++ b/sys/btrfs/mounts.nix
@@ -1,39 +1,47 @@
-{ lib, config, pkgs, ... }:
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.btrfs;
-in
-{
+in {
options.local.btrfs = {
mounts = mkOption {
- default = { };
+ default = {};
- type = with lib.types; attrsOf (submodule {
- options = {
- ssd = mkOption {
- type = bool;
- };
+ type = with lib.types;
+ attrsOf (submodule {
+ options = {
+ ssd = mkOption {
+ type = bool;
+ };
- device = mkOption {
- type = str;
- };
+ device = mkOption {
+ type = str;
+ };
- subvol = mkOption {
- type = str;
+ subvol = mkOption {
+ type = str;
+ };
};
- };
- });
+ });
};
};
- config = mkIf (cfg.mounts != { }) {
- fileSystems =
- let
- btrfsMount = { device, subvol, ssd }: {
- inherit device;
- fsType = "btrfs";
- options = [ "noatime" "compress=zstd" "subvol=${subvol}" ] ++ optional ssd "ssd";
- };
- in
+ config = mkIf (cfg.mounts != {}) {
+ fileSystems = let
+ btrfsMount = {
+ device,
+ subvol,
+ ssd,
+ }: {
+ inherit device;
+ fsType = "btrfs";
+ options = ["noatime" "compress=zstd" "subvol=${subvol}"] ++ optional ssd "ssd";
+ };
+ in
mapAttrs (_: btrfsMount) cfg.mounts;
};
}
diff --git a/sys/btrfs/snapper.nix b/sys/btrfs/snapper.nix
index 27d2779..2d29aa4 100644
--- a/sys/btrfs/snapper.nix
+++ b/sys/btrfs/snapper.nix
@@ -1,73 +1,76 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.btrfs;
-in
-{
+in {
options.local.btrfs = {
snapper = mkOption {
type = with lib.types; attrsOf str;
- default = { };
+ default = {};
};
};
- config = mkIf (cfg.snapper != { }) {
- environment.systemPackages = [ pkgs.local.btclone ];
+ config = mkIf (cfg.snapper != {}) {
+ environment.systemPackages = [pkgs.local.btclone];
- services.snapper.configs =
- let
- snapperConfig = _: subvolume: {
- SUBVOLUME = subvolume;
+ services.snapper.configs = let
+ snapperConfig = _: subvolume: {
+ SUBVOLUME = subvolume;
- # btrfs qgroup for space aware cleanup algorithms
- QGROUP = "";
+ # btrfs qgroup for space aware cleanup algorithms
+ QGROUP = "";
- # fraction of the filesystems space the snapshots may use
- SPACE_LIMIT = "0.5";
+ # fraction of the filesystems space the snapshots may use
+ SPACE_LIMIT = "0.5";
- # fraction of the filesystems space that should be free
- FREE_LIMIT = "0.2";
+ # fraction of the filesystems space that should be free
+ FREE_LIMIT = "0.2";
- # users and groups allowed to work with config
- ALLOW_USERS = [ ];
- ALLOW_GROUPS = [ ];
+ # users and groups allowed to work with config
+ ALLOW_USERS = [];
+ ALLOW_GROUPS = [];
- # sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
- # directory
- SYNC_ACL = "no";
+ # sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
+ # directory
+ SYNC_ACL = "no";
- # start comparing pre- and post-snapshot in background after creating
- # post-snapshot
- BACKGROUND_COMPARISON = "yes";
+ # start comparing pre- and post-snapshot in background after creating
+ # post-snapshot
+ BACKGROUND_COMPARISON = "yes";
- # run daily number cleanup
- NUMBER_CLEANUP = "yes";
+ # run daily number cleanup
+ NUMBER_CLEANUP = "yes";
- # limit for number cleanup
- NUMBER_MIN_AGE = "1800";
- NUMBER_LIMIT = "100";
- NUMBER_LIMIT_IMPORTANT = "10";
+ # limit for number cleanup
+ NUMBER_MIN_AGE = "1800";
+ NUMBER_LIMIT = "100";
+ NUMBER_LIMIT_IMPORTANT = "10";
- # create hourly snapshots
- TIMELINE_CREATE = true;
+ # create hourly snapshots
+ TIMELINE_CREATE = true;
- # cleanup hourly snapshots after some time
- TIMELINE_CLEANUP = true;
+ # cleanup hourly snapshots after some time
+ TIMELINE_CLEANUP = true;
- # limits for timeline cleanup
- TIMELINE_MIN_AGE = "1800";
- TIMELINE_LIMIT_HOURLY = "24";
- TIMELINE_LIMIT_DAILY = "7";
- TIMELINE_LIMIT_WEEKLY = "4";
- TIMELINE_LIMIT_MONTHLY = "12";
- TIMELINE_LIMIT_YEARLY = "10";
+ # limits for timeline cleanup
+ TIMELINE_MIN_AGE = "1800";
+ TIMELINE_LIMIT_HOURLY = "24";
+ TIMELINE_LIMIT_DAILY = "7";
+ TIMELINE_LIMIT_WEEKLY = "4";
+ TIMELINE_LIMIT_MONTHLY = "12";
+ TIMELINE_LIMIT_YEARLY = "10";
- # cleanup empty pre-post-pairs
- EMPTY_PRE_POST_CLEANUP = "yes";
+ # cleanup empty pre-post-pairs
+ EMPTY_PRE_POST_CLEANUP = "yes";
- # limits for empty pre-post-pair cleanup
- EMPTY_PRE_POST_MIN_AGE = "1800";
- };
- in
+ # limits for empty pre-post-pair cleanup
+ EMPTY_PRE_POST_MIN_AGE = "1800";
+ };
+ in
mapAttrs snapperConfig cfg.snapper;
};
}
diff --git a/sys/default.nix b/sys/default.nix
index 0ce00a1..131ddeb 100644
--- a/sys/default.nix
+++ b/sys/default.nix
@@ -1,4 +1,10 @@
-{ lib, config, flakes, pkgs, ... }:
+{
+ lib,
+ config,
+ flakes,
+ pkgs,
+ ...
+}:
with lib; {
imports = [
flakes.nixpkgs.nixosModules.notDetected
diff --git a/sys/gitea/default.nix b/sys/gitea/default.nix
index 69dfbc2..212b9f1 100644
--- a/sys/gitea/default.nix
+++ b/sys/gitea/default.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.gitea;
-in
-{
+in {
options.local.gitea = {
enable = mkEnableOption "gitea";
};
diff --git a/sys/hardware/altera.nix b/sys/hardware/altera.nix
index 2fc1bb6..fddd722 100644
--- a/sys/hardware/altera.nix
+++ b/sys/hardware/altera.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.hardware.altera;
-in
-{
+in {
options.local.hardware.altera = {
enable = mkEnableOption "Altera USB Blaster";
};
diff --git a/sys/hardware/apc.nix b/sys/hardware/apc.nix
index 9614c48..97a5bb0 100644
--- a/sys/hardware/apc.nix
+++ b/sys/hardware/apc.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.hardware.apc;
-in
-{
+in {
options.local.hardware.apc = {
enable = mkEnableOption "APC UPS support";
};
diff --git a/sys/hardware/athena.nix b/sys/hardware/athena.nix
index 06d10b3..755c184 100644
--- a/sys/hardware/athena.nix
+++ b/sys/hardware/athena.nix
@@ -1,10 +1,14 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.hardware.athena;
athena = pkgs.local.athena-bccr.${cfg.release};
-in
-{
+in {
options.local.hardware.athena = {
enable = mkEnableOption "Athena ASEDrive III smartcard reader";
@@ -25,11 +29,11 @@ in
'';
};
- systemPackages = [ athena.ase-pkcs11 ];
+ systemPackages = [athena.ase-pkcs11];
};
#FIXME: Extremadamente peligroso si BCCR o MICITT caen, investigar polĆ­tica nacional de root CA
- security.pki.certificateFiles = [ "${athena.bccr-cacerts}/root-ca.pem" ];
+ security.pki.certificateFiles = ["${athena.bccr-cacerts}/root-ca.pem"];
services = {
pcscd.enable = true;
diff --git a/sys/hardware/bluetooth.nix b/sys/hardware/bluetooth.nix
index 0d53750..63e3f0c 100644
--- a/sys/hardware/bluetooth.nix
+++ b/sys/hardware/bluetooth.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.hardware.bluetooth;
-in
-{
+in {
options.local.hardware.bluetooth = {
enable = mkEnableOption "bluetooth services";
};
diff --git a/sys/hardware/epson.nix b/sys/hardware/epson.nix
index 66304f9..30b1303 100644
--- a/sys/hardware/epson.nix
+++ b/sys/hardware/epson.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.hardware.epson;
-in
-{
+in {
options.local.hardware.epson = {
enable = mkEnableOption "Epson printers and scanners";
};
diff --git a/sys/hardware/laptop.nix b/sys/hardware/laptop.nix
index d9ba753..3b5b772 100644
--- a/sys/hardware/laptop.nix
+++ b/sys/hardware/laptop.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.hardware.laptop;
-in
-{
+in {
options.local.hardware.laptop = {
enable = mkEnableOption "laptop stuff";
};
diff --git a/sys/hardware/printing.nix b/sys/hardware/printing.nix
index 30c6962..e11a016 100644
--- a/sys/hardware/printing.nix
+++ b/sys/hardware/printing.nix
@@ -1,15 +1,18 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.hardware.printing;
inherit (config.local.net) dhcpInterface;
-in
-{
+in {
options.local.hardware.printing = {
enable = mkEnableOption "print and scan services";
users = mkOption {
type = with types; listOf str;
- default = [ ];
+ default = [];
};
};
@@ -32,7 +35,7 @@ in
hardware.sane.enable = true;
networking.firewall.interfaces = mkIf (dhcpInterface != null) {
- ${dhcpInterface}.allowedUDPPorts = [ 5353 ];
+ ${dhcpInterface}.allowedUDPPorts = [5353];
};
services.printing.enable = true;
@@ -40,7 +43,7 @@ in
users.users = listToAttrs (map
(user: {
name = user;
- value.extraGroups = [ "scanner" "lp" ];
+ value.extraGroups = ["scanner" "lp"];
})
cfg.users);
};
diff --git a/sys/hardware/thinkpad.nix b/sys/hardware/thinkpad.nix
index 7341e68..ab18694 100644
--- a/sys/hardware/thinkpad.nix
+++ b/sys/hardware/thinkpad.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.hardware.thinkpad;
-in
-{
+in {
options.local.hardware.thinkpad = {
enable = mkEnableOption "Thinkpad hardware support";
};
@@ -13,18 +17,18 @@ in
# Fingerprint sensor requires a firmware-update to work.
boot = {
- extraModulePackages = with config.boot.kernelPackages; [ acpi_call ];
+ extraModulePackages = with config.boot.kernelPackages; [acpi_call];
extraModprobeConfig = "options iwlwifi 11n_disable=1 wd_disable=1";
# acpi_call makes tlp work for newer thinkpads
- kernelModules = [ "acpi_call" ];
+ kernelModules = ["acpi_call"];
# Force use of the thinkpad_acpi driver for backlight control.
# This allows the backlight save/load systemd service to work.
- kernelParams = [ "acpi_backlight=native" ];
+ kernelParams = ["acpi_backlight=native"];
};
- hardware.firmware = [ pkgs.sof-firmware ];
+ hardware.firmware = [pkgs.sof-firmware];
local.hardware.laptop.enable = true;
diff --git a/sys/hardware/yubico.nix b/sys/hardware/yubico.nix
index 0078210..0c8478c 100644
--- a/sys/hardware/yubico.nix
+++ b/sys/hardware/yubico.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.hardware.yubico;
-in
-{
+in {
options.local.hardware.yubico = {
enable = mkEnableOption "Yubico hardware support";
};
@@ -14,7 +18,7 @@ in
services = {
pcscd.enable = true;
- udev.packages = [ pkgs.yubikey-personalization ];
+ udev.packages = [pkgs.yubikey-personalization];
};
};
}
diff --git a/sys/home-assistant/hass.nix b/sys/home-assistant/hass.nix
index 4a3ba31..7fd3251 100644
--- a/sys/home-assistant/hass.nix
+++ b/sys/home-assistant/hass.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.home-assistant;
-in
-{
+in {
options.local.home-assistant = {
enable = mkEnableOption "home-assistant";
};
@@ -12,20 +16,25 @@ in
environment.etc."fail2ban/filter.d/home-assistant.local".text = ''
[Definition]
failregex = ^.* \[homeassistant\.components\.http\.ban\] Login attempt or request with invalid authentication from <HOST>.*$
-
+
ignoreregex =
-
+
journalmatch = _SYSTEMD_UNIT=home-assistant.service + _COMM=home-assistant
-
+
datepattern = {^LN-BEG}
'';
local.boot.impermanence.directories = [
- { directory = "/var/lib/hass"; user = "hass"; group = "hass"; mode = "u=rwx,g=,o="; }
+ {
+ directory = "/var/lib/hass";
+ user = "hass";
+ group = "hass";
+ mode = "u=rwx,g=,o=";
+ }
];
services = {
- fail2ban.jails.home-assistant = { };
+ fail2ban.jails.home-assistant = {};
home-assistant = {
enable = true;
@@ -43,7 +52,7 @@ in
config = {
# Includes dependencies for a basic setup
# https://www.home-assistant.io/integrations/default_config/
- default_config = { };
+ default_config = {};
switch = [
# Televisor 192.168.42.205
diff --git a/sys/home-assistant/yaml-extra.nix b/sys/home-assistant/yaml-extra.nix
index 6275e12..77d1ed2 100644
--- a/sys/home-assistant/yaml-extra.nix
+++ b/sys/home-assistant/yaml-extra.nix
@@ -1,22 +1,23 @@
-{ lib, ... }:
+{lib, ...}:
with lib; {
options.services.home-assistant = {
config = mkOption {
- type = with lib.types; nullOr (submodule {
- options = {
- http = {
- use_x_forwarded_for = mkOption {
- type = nullOr bool;
- default = null;
- };
+ type = with lib.types;
+ nullOr (submodule {
+ options = {
+ http = {
+ use_x_forwarded_for = mkOption {
+ type = nullOr bool;
+ default = null;
+ };
- trusted_proxies = mkOption {
- type = nullOr (either str (listOf str));
- default = null;
+ trusted_proxies = mkOption {
+ type = nullOr (either str (listOf str));
+ default = null;
+ };
};
};
- };
- });
+ });
};
};
}
diff --git a/sys/jobs/pki-expiry/default.nix b/sys/jobs/pki-expiry/default.nix
index b61d6f5..553cdc8 100644
--- a/sys/jobs/pki-expiry/default.nix
+++ b/sys/jobs/pki-expiry/default.nix
@@ -1,9 +1,13 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.jobs.pkiExpiry;
inherit (config.local) pki;
-in
-{
+in {
options.local.jobs.pkiExpiry = {
enable = mkEnableOption "PKI expiration reminder";
};
@@ -11,43 +15,40 @@ in
config = mkIf cfg.enable {
systemd = {
services.pki-expiry = {
- after = [ "postfix.service" ];
- path = [ "/run/wrappers" ];
+ after = ["postfix.service"];
+ path = ["/run/wrappers"];
- environment.PKI_PUBLIC =
- let
- mkdir = "mkdir -p $out/{ca,cert,crl}";
+ environment.PKI_PUBLIC = let
+ mkdir = "mkdir -p $out/{ca,cert,crl}";
- cas = mapAttrsToList (_: ca: "ln -s ${ca.cert} $out/ca/${ca.path}") pki.ca;
- crls = mapAttrsToList (_: ca: "ln -s ${ca.crl} $out/crl/${ca.path}") pki.ca;
+ cas = mapAttrsToList (_: ca: "ln -s ${ca.cert} $out/ca/${ca.path}") pki.ca;
+ crls = mapAttrsToList (_: ca: "ln -s ${ca.crl} $out/crl/${ca.path}") pki.ca;
- certs = mapAttrsToList
- (path: leaf: "ln -s ${leaf.cert} $out/cert/${path}")
- (filterAttrs (_: object: ! object ? leaves) pki.byPath);
+ certs =
+ mapAttrsToList
+ (path: leaf: "ln -s ${leaf.cert} $out/cert/${path}")
+ (filterAttrs (_: object: ! object ? leaves) pki.byPath);
- pkiPublic = pkgs.runCommandNoCCLocal "pki-public" { } (concatLines ([ mkdir ] ++ cas ++ crls ++ certs));
- in
- "${pkiPublic}";
+ pkiPublic = pkgs.runCommandNoCCLocal "pki-public" {} (concatLines ([mkdir] ++ cas ++ crls ++ certs));
+ in "${pkiPublic}";
serviceConfig = {
Type = "oneshot";
StateDirectory = "pki-expiry";
WorkingDirectory = "/var/lib/pki-expiry";
- ExecStart =
- let
- script = pkgs.writeShellApplication {
- name = "pki-expiry";
- text = readFile ./pki-expiry.sh;
- runtimeInputs = with pkgs; [ diffutils openssl ];
- };
- in
- "${getExe script}";
+ ExecStart = let
+ script = pkgs.writeShellApplication {
+ name = "pki-expiry";
+ text = readFile ./pki-expiry.sh;
+ runtimeInputs = with pkgs; [diffutils openssl];
+ };
+ in "${getExe script}";
};
};
timers.pki-expiry = {
- wantedBy = [ "timers.target" ];
+ wantedBy = ["timers.target"];
timerConfig = {
OnStartupSec = "10m";
diff --git a/sys/kiosk/default.nix b/sys/kiosk/default.nix
index b450733..be20829 100644
--- a/sys/kiosk/default.nix
+++ b/sys/kiosk/default.nix
@@ -1,8 +1,11 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.kiosk;
-in
-{
+in {
options.local.kiosk = {
enable = mkEnableOption "kiosk mode";
@@ -26,7 +29,13 @@ in
enable = true;
inherit (cfg) program user;
- extraArguments = [ (if cfg.allowVTSwitch then "-sd" else "-d") ];
+ extraArguments = [
+ (
+ if cfg.allowVTSwitch
+ then "-sd"
+ else "-d"
+ )
+ ];
};
physlock = {
diff --git a/sys/mail/default.nix b/sys/mail/default.nix
index 6eba9cd..f87b6fe 100644
--- a/sys/mail/default.nix
+++ b/sys/mail/default.nix
@@ -1,4 +1,9 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.mailHost;
imapHostname = config.local.domains.imap.main;
@@ -6,8 +11,7 @@ with lib; let
cert = config.security.acme.certs.${imapHostname}.directory;
inherit (config.local) users virtual;
-in
-{
+in {
options.local.mailHost = {
enable = mkEnableOption "mailbox host service";
@@ -45,7 +49,7 @@ in
mailUser = "vmail";
mailGroup = "vmail";
mailLocation = "maildir:~/mail";
- mailPlugins.perProtocol.lmtp.enable = [ "sieve" ];
+ mailPlugins.perProtocol.lmtp.enable = ["sieve"];
# https://github.com/NixOS/nixpkgs/issues/286859
sieve.extensions = [
@@ -53,168 +57,164 @@ in
"mailbox"
];
- extraConfig =
- let
- inherit (config.networking) domain;
-
- # https://dovecot.org/list/dovecot/2019-March/115250.html
- # Otra solución posible (https://serverfault.com/a/1062274/980378):
- # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
- localEntry = canonical: username: ''
- ${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
- '';
-
- localMailboxes =
- pkgs.writeText "local-mailboxes"
- (concatStrings
- (flatten (mapAttrsToList
- (canonical: user:
- map (localEntry canonical) ([ canonical ] ++ user.hardAliases))
- users)));
-
- localCerts =
- flatten (mapAttrsToList
- (canonical: user:
- let
- certNames = {
- inherit canonical;
- logins = [ canonical ] ++ user.hardAliases;
- };
- in
- map (flip nameValuePair certNames) user.mail.certs)
- users);
-
- vmailCerts =
- flatten (flatten (mapAttrsToList
- (domain: virtual: mapAttrsToList
- (username: user:
- let
- address = "${username}@${domain}";
-
- certNames = {
- canonical = address;
- logins = [ address ];
- };
- in
- map (flip nameValuePair certNames) user.mail.certs)
- virtual.users)
- virtual));
-
- certLogins =
- pkgs.writeText "cert-logins"
- (concatLines (flatten (mapAttrsToList
- (certPath: names: map
- (addr: "${config.local.pki.byPath.${certPath}.commonName}@nodomain,${addr}:::::::user=${names.canonical}")
- names.logins)
- (listToAttrs (localCerts ++ vmailCerts)))));
-
- vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
- in
- ''
- auth_mechanisms = plain login external
-
- ssl_ca = <${config.local.pki.ca.mail.fullchain}
- ssl_require_crl = yes
- ssl_verify_client_cert = yes
-
- # Esto descarta @domain.tld de locales explƭcitos, pero lo exige para los demƔs.
- # Implicación: locales implícitos sin dominio fallan en autenticar
- auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}}
- auth_ssl_username_from_cert = yes
-
- # TODO: los defaults de nixpkgs dejan los sockets bajo
- # /run/dovecot2 con demasiados permisos rwx, arreglar
-
- service auth {
- inet_listener mta-sasl {
- port = ${toString cfg.saslPort}
- address = ${cfg.mdaListen}
- }
- }
-
- service lmtp {
- inet_listener mta-lmtp {
- port = ${toString cfg.lmtpPort}
- address = ${cfg.mdaListen}
- }
- }
-
- # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
- # falle para usuarios locales, pero todo lo demƔs sirve. Parece
- # ser debido a que pam no puede enumerar.
-
- passdb {
- driver = static
- args = nopassword
-
- master = yes
- mechanisms = external
-
- result_success = continue-fail
- result_failure = return-fail
- result_internalfail = return-fail
- }
-
- passdb {
- driver = passwd-file
- args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins}
-
- mechanisms = external
- override_fields = nopassword
-
- result_failure = return-fail
- result_internalfail = return-fail
- }
-
- passdb {
- driver = passwd-file
- args = username_format=%Ln ${vmailPath}/passwd
- }
-
- passdb {
- driver = passwd-file
- args = scheme=PLAIN ${localMailboxes}
-
- # Esta es una forma de determinar si se encontró el usuario en
- # el passwd-file por medio de nopassword sin realmente
- # autenticarlo. Cuidado con result_success, porque si eso se
- # configura mal se permite inicio de sesión con cualquier
- # contraseƱa (!!!).
- result_success = continue
- result_failure = return-fail
- result_internalfail = return-fail
-
- username_filter = !*@*
- }
+ extraConfig = let
+ inherit (config.networking) domain;
- passdb {
- driver = pam
- args = dovecot2
- username_filter = !*@*
- #TODO: algo como 'override_fields = allow_nets=...'
- }
-
- userdb {
- driver = passwd-file
- args = username_format=%Ln ${vmailPath}/passwd
- override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
- }
-
- userdb {
- driver = passwd-file
- args = ${localMailboxes}
+ # https://dovecot.org/list/dovecot/2019-March/115250.html
+ # Otra solución posible (https://serverfault.com/a/1062274/980378):
+ # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
+ localEntry = canonical: username: ''
+ ${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
+ '';
- result_success = continue-ok
- result_internalfail = return-fail
- skip = found
+ localMailboxes =
+ pkgs.writeText "local-mailboxes"
+ (concatStrings
+ (flatten (mapAttrsToList
+ (canonical: user:
+ map (localEntry canonical) ([canonical] ++ user.hardAliases))
+ users)));
+
+ localCerts = flatten (mapAttrsToList
+ (canonical: user: let
+ certNames = {
+ inherit canonical;
+ logins = [canonical] ++ user.hardAliases;
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ users);
+
+ vmailCerts = flatten (flatten (mapAttrsToList
+ (domain: virtual:
+ mapAttrsToList
+ (username: user: let
+ address = "${username}@${domain}";
+
+ certNames = {
+ canonical = address;
+ logins = [address];
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ virtual.users)
+ virtual));
+
+ certLogins =
+ pkgs.writeText "cert-logins"
+ (concatLines (flatten (mapAttrsToList
+ (certPath: names:
+ map
+ (addr: "${config.local.pki.byPath.${certPath}.commonName}@nodomain,${addr}:::::::user=${names.canonical}")
+ names.logins)
+ (listToAttrs (localCerts ++ vmailCerts)))));
+
+ vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
+ in ''
+ auth_mechanisms = plain login external
+
+ ssl_ca = <${config.local.pki.ca.mail.fullchain}
+ ssl_require_crl = yes
+ ssl_verify_client_cert = yes
+
+ # Esto descarta @domain.tld de locales explƭcitos, pero lo exige para los demƔs.
+ # Implicación: locales implícitos sin dominio fallan en autenticar
+ auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}}
+ auth_ssl_username_from_cert = yes
+
+ # TODO: los defaults de nixpkgs dejan los sockets bajo
+ # /run/dovecot2 con demasiados permisos rwx, arreglar
+
+ service auth {
+ inet_listener mta-sasl {
+ port = ${toString cfg.saslPort}
+ address = ${cfg.mdaListen}
}
+ }
- userdb {
- driver = passwd
- args = blocking=no
- skip = notfound
+ service lmtp {
+ inet_listener mta-lmtp {
+ port = ${toString cfg.lmtpPort}
+ address = ${cfg.mdaListen}
}
- '';
+ }
+
+ # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
+ # falle para usuarios locales, pero todo lo demƔs sirve. Parece
+ # ser debido a que pam no puede enumerar.
+
+ passdb {
+ driver = static
+ args = nopassword
+
+ master = yes
+ mechanisms = external
+
+ result_success = continue-fail
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins}
+
+ mechanisms = external
+ override_fields = nopassword
+
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN ${localMailboxes}
+
+ # Esta es una forma de determinar si se encontró el usuario en
+ # el passwd-file por medio de nopassword sin realmente
+ # autenticarlo. Cuidado con result_success, porque si eso se
+ # configura mal se permite inicio de sesión con cualquier
+ # contraseƱa (!!!).
+ result_success = continue
+ result_failure = return-fail
+ result_internalfail = return-fail
+
+ username_filter = !*@*
+ }
+
+ passdb {
+ driver = pam
+ args = dovecot2
+ username_filter = !*@*
+ #TODO: algo como 'override_fields = allow_nets=...'
+ }
+
+ userdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
+ }
+
+ userdb {
+ driver = passwd-file
+ args = ${localMailboxes}
+
+ result_success = continue-ok
+ result_internalfail = return-fail
+ skip = found
+ }
+
+ userdb {
+ driver = passwd
+ args = blocking=no
+ skip = notfound
+ }
+ '';
};
fail2ban.jails.dovecot.settings = {
@@ -225,12 +225,12 @@ in
security = {
# Necesario debido a 'enablePAM = false'
- pam.services.dovecot2 = { };
+ pam.services.dovecot2 = {};
acme.certs.${imapHostname} = {
inherit (config.services.dovecot2) group;
- reloadServices = [ "dovecot2.service" ];
+ reloadServices = ["dovecot2.service"];
};
};
@@ -239,7 +239,7 @@ in
groups.${config.services.dovecot2.mailGroup}.gid = 993;
};
- networking.firewall.allowedTCPPorts = [ 143 993 ];
+ networking.firewall.allowedTCPPorts = [143 993];
local.certs.imap.enable = true;
};
diff --git a/sys/mta/default.nix b/sys/mta/default.nix
index 4305f70..57c1c27 100644
--- a/sys/mta/default.nix
+++ b/sys/mta/default.nix
@@ -1,4 +1,9 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.mta;
@@ -22,13 +27,12 @@ with lib; let
if isPrimary
then "lmtp:inet:${cfg.mdaAddr}:${toString cfg.lmtpPort}"
else "error:bad transport";
-in
-{
+in {
options.local.mta = {
enable = mkEnableOption "mail transfer agent";
mode = mkOption {
- type = types.enum [ "primary" "backup" ];
+ type = types.enum ["primary" "backup"];
};
mdaAddr = mkOption {
@@ -58,7 +62,7 @@ in
enable = true;
group = "postfix";
- domains = "csl:" + concatStringsSep "," ([ domain ] ++ attrNames virtualDomains);
+ domains = "csl:" + concatStringsSep "," ([domain] ++ attrNames virtualDomains);
selector = "202408";
configFile = pkgs.writeText "opendkim.conf" ''
@@ -76,7 +80,7 @@ in
hostname = mtaDomain.main;
#TODO: check_recipient_access para rechazar localhost desde afuera
- destination = optionals isPrimary [ "localhost" "$mydomain" ];
+ destination = optionals isPrimary ["localhost" "$mydomain"];
origin = "$mydomain";
networksStyle = "host";
@@ -95,20 +99,25 @@ in
# TambiƩn es postmaster
rootAlias = config.local.sysadmin;
- extraAliases = optionalString isPrimary
+ extraAliases =
+ optionalString isPrimary
(concatLines (flatten (mapAttrsToList
- (name: user: map
+ (name: user:
+ map
(alias: "${alias}: ${name}")
user.hardAliases)
users)));
- localRecipients = optionals isPrimary
+ localRecipients =
+ optionals isPrimary
(map (user: "${user}@${domain}")
(attrNames (users // virtual.${domain}.users)));
- virtual = optionalString isPrimary
+ virtual =
+ optionalString isPrimary
(concatLines (flatten (mapAttrsToList
- (name: virtual: mapAttrsToList
+ (name: virtual:
+ mapAttrsToList
(alias: targets: "${alias}@${name} ${concatStringsSep ", " targets}")
virtual.aliases)
virtual)));
@@ -116,101 +125,108 @@ in
mapFiles = optionalAttrs isPrimary {
sender_ccerts =
pkgs.writeText "postfix-sender_ccerts"
- (concatLines (flatten (mapAttrsToList
- (username: user: map
- (alias: "${alias}@${domain} CCERTS ${concatStringsSep ","
- (map (certPath: config.local.pki.byPath.${certPath}.fingerprint.sha256-bytes-upper)
- user.mail.certs)}")
- ([ username ] ++ user.hardAliases))
- (filterAttrs (_: user: user.mail.certs != [ ]) users))));
+ (concatLines (flatten (mapAttrsToList
+ (username: user:
+ map
+ (alias: "${alias}@${domain} CCERTS ${concatStringsSep ","
+ (map (certPath: config.local.pki.byPath.${certPath}.fingerprint.sha256-bytes-upper)
+ user.mail.certs)}")
+ ([username] ++ user.hardAliases))
+ (filterAttrs (_: user: user.mail.certs != []) users))));
sender_login =
pkgs.writeText "postfix-sender_login"
- (concatLines (flatten (mapAttrsToList
- (username: user: map
- (alias: "${alias}@${domain} ${username}")
- ([ username ] ++ user.hardAliases))
- users)));
+ (concatLines (flatten (mapAttrsToList
+ (username: user:
+ map
+ (alias: "${alias}@${domain} ${username}")
+ ([username] ++ user.hardAliases))
+ users)));
virtual_recipients =
pkgs.writeText "postfix-virtual_recipients"
- (concatLines (flatten (mapAttrsToList
- (virtualDomain: virtual: mapAttrsToList
- # El lado derecho de esta tabla debe existir pero nunca se usa
- (username: _: "${username}@${virtualDomain} foo")
- virtual.users)
- virtualDomains)));
+ (concatLines (flatten (mapAttrsToList
+ (virtualDomain: virtual:
+ mapAttrsToList
+ # El lado derecho de esta tabla debe existir pero nunca se usa
+ (username: _: "${username}@${virtualDomain} foo")
+ virtual.users)
+ virtualDomains)));
virtual_rules =
pkgs.writeText "postfix-virtual_rules"
- (concatLines (flatten (mapAttrsToList
- (name: virtual: map
- (rule: "/^${rule.pattern}@${name}$/ ${concatStringsSep ", " rule.targets}")
- virtual.rules)
- virtual)));
+ (concatLines (flatten (mapAttrsToList
+ (name: virtual:
+ map
+ (rule: "/^${rule.pattern}@${name}$/ ${concatStringsSep ", " rule.targets}")
+ virtual.rules)
+ virtual)));
};
- config = {
- # user+extension@domain.tld
- recipient_delimiter = optionalString isPrimary "+";
-
- message_size_limit = toString (50 * 1048576);
-
- local_transport = mdaTransport;
- virtual_transport = mdaTransport;
-
- smtpd_tls_auth_only = true;
- # Nota: smtpd_tls_dh1024_param_file fue deprecado en 3.9
-
- tls_append_default_CA = false; # CrĆ­tico
-
- # https://linux-audit.com/postfix-hardening-guide-for-security-and-privacy/
- smtpd_helo_required = true;
- disable_vrfy_command = true;
- } // optionalAttrs isPrimary {
- virtual_alias_maps = mkAfter [ "pcre:/etc/postfix/virtual_rules" ];
- virtual_mailbox_domains = attrNames virtualDomains;
- virtual_mailbox_maps = [ "hash:/etc/postfix/virtual_recipients" ];
-
- smtpd_sasl_type = "dovecot";
- smtpd_sasl_path = "inet:${cfg.mdaAddr}:${toString cfg.saslPort}";
- smtpd_sasl_local_domain = "$mydomain";
- smtpd_sasl_security_options = [ "noanonymous" ];
-
- smtpd_tls_CAfile = "${config.local.pki.ca.mail.fullchain}";
- smtpd_tls_ccert_verifydepth = "1";
-
- # Inventado, no es parƔmetro de postfix
- local_submission_client_restrictions = [
- "permit_tls_all_clientcerts"
- "permit_sasl_authenticated"
- "reject"
- ];
-
- smtpd_sender_login_maps = [ "hash:/etc/postfix/sender_login" ];
-
- smtpd_relay_restrictions = [
- "permit_mynetworks"
- "permit_tls_all_clientcerts"
- "permit_sasl_authenticated"
- "reject_unauth_destination"
- ];
-
- smtpd_sender_restrictions = [
- "check_sender_access hash:/etc/postfix/sender_ccerts"
- "reject_sender_login_mismatch"
- ];
-
- smtpd_milters = "unix:/run/opendkim/opendkim.sock";
- non_smtpd_milters = "$smtpd_milters";
- milter_default_action = "accept";
- } // optionalAttrs isBackup {
- inet_interfaces = [ cfg.relayListen ];
-
- smtpd_relay_restrictions = [
- "reject_unauth_destination"
- ];
- };
+ config =
+ {
+ # user+extension@domain.tld
+ recipient_delimiter = optionalString isPrimary "+";
+
+ message_size_limit = toString (50 * 1048576);
+
+ local_transport = mdaTransport;
+ virtual_transport = mdaTransport;
+
+ smtpd_tls_auth_only = true;
+ # Nota: smtpd_tls_dh1024_param_file fue deprecado en 3.9
+
+ tls_append_default_CA = false; # CrĆ­tico
+
+ # https://linux-audit.com/postfix-hardening-guide-for-security-and-privacy/
+ smtpd_helo_required = true;
+ disable_vrfy_command = true;
+ }
+ // optionalAttrs isPrimary {
+ virtual_alias_maps = mkAfter ["pcre:/etc/postfix/virtual_rules"];
+ virtual_mailbox_domains = attrNames virtualDomains;
+ virtual_mailbox_maps = ["hash:/etc/postfix/virtual_recipients"];
+
+ smtpd_sasl_type = "dovecot";
+ smtpd_sasl_path = "inet:${cfg.mdaAddr}:${toString cfg.saslPort}";
+ smtpd_sasl_local_domain = "$mydomain";
+ smtpd_sasl_security_options = ["noanonymous"];
+
+ smtpd_tls_CAfile = "${config.local.pki.ca.mail.fullchain}";
+ smtpd_tls_ccert_verifydepth = "1";
+
+ # Inventado, no es parƔmetro de postfix
+ local_submission_client_restrictions = [
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject"
+ ];
+
+ smtpd_sender_login_maps = ["hash:/etc/postfix/sender_login"];
+
+ smtpd_relay_restrictions = [
+ "permit_mynetworks"
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject_unauth_destination"
+ ];
+
+ smtpd_sender_restrictions = [
+ "check_sender_access hash:/etc/postfix/sender_ccerts"
+ "reject_sender_login_mismatch"
+ ];
+
+ smtpd_milters = "unix:/run/opendkim/opendkim.sock";
+ non_smtpd_milters = "$smtpd_milters";
+ milter_default_action = "accept";
+ }
+ // optionalAttrs isBackup {
+ inet_interfaces = [cfg.relayListen];
+
+ smtpd_relay_restrictions = [
+ "reject_unauth_destination"
+ ];
+ };
# Importante: existe submissionOptions por aparte, no son iguales
submissionsOptions = optionalAttrs isPrimary {
@@ -223,19 +239,31 @@ in
};
#TODO: solo para las destination addresses necesarias
- networking.firewall.allowedTCPPorts = optionals isPrimary [ 25 465 ];
+ networking.firewall.allowedTCPPorts = optionals isPrimary [25 465];
local = {
- boot.impermanence.directories = [
- { directory = "/var/lib/postfix"; user = "root"; group = "root"; mode = "u=rwx,g=rx,o=rx"; }
- ] ++ optionals isPrimary [
- { directory = "/var/lib/opendkim"; user = "opendkim"; group = "postfix"; mode = "u=rwx,g=,o="; }
- ];
+ boot.impermanence.directories =
+ [
+ {
+ directory = "/var/lib/postfix";
+ user = "root";
+ group = "root";
+ mode = "u=rwx,g=rx,o=rx";
+ }
+ ]
+ ++ optionals isPrimary [
+ {
+ directory = "/var/lib/opendkim";
+ user = "opendkim";
+ group = "postfix";
+ mode = "u=rwx,g=,o=";
+ }
+ ];
certs.smtp.enable = isPrimary;
certs.smtp-backup.enable = isBackup;
};
- security.acme.certs.${mtaDomain.main}.reloadServices = [ "postfix.service" ];
+ security.acme.certs.${mtaDomain.main}.reloadServices = ["postfix.service"];
};
}
diff --git a/sys/net/fail2ban.nix b/sys/net/fail2ban.nix
index 8d3aa3d..32197b6 100644
--- a/sys/net/fail2ban.nix
+++ b/sys/net/fail2ban.nix
@@ -1,9 +1,13 @@
-{ lib, config, pkgs, ... }:
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.net.fail2ban;
inherit (config.local) nets;
-in
-{
+in {
options.local.net.fail2ban = {
enable = mkEnableOption "fail2ban";
};
diff --git a/sys/net/interfaces.nix b/sys/net/interfaces.nix
index 281f5ca..3b0abcd 100644
--- a/sys/net/interfaces.nix
+++ b/sys/net/interfaces.nix
@@ -1,8 +1,12 @@
-{ lib, config, pkgs, ... }:
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.net;
-in
-{
+in {
options.local.net = with lib.types; {
enable = mkEnableOption "networking stack";
diff --git a/sys/net/options.nix b/sys/net/options.nix
index 11b913c..0608fb9 100644
--- a/sys/net/options.nix
+++ b/sys/net/options.nix
@@ -1,65 +1,71 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
v4PtrHierarchy = address: bits: reverseList (sublist 0 (bits / 8) (splitString "." address));
- v6PtrHierarchy = address: bits:
- let
- separator = lists.findFirstIndex (hextet: hextet == "") null colonSplit;
- colonSplit = splitString ":" address;
+ v6PtrHierarchy = address: bits: let
+ separator = lists.findFirstIndex (hextet: hextet == "") null colonSplit;
+ colonSplit = splitString ":" address;
- zeroFill = replicate (8 - length colonSplit + 1) "0000";
- leftSplit = sublist 0 separator colonSplit;
- rightSplit = sublist (separator + 1) (length colonSplit - separator - 1) colonSplit;
+ zeroFill = replicate (8 - length colonSplit + 1) "0000";
+ leftSplit = sublist 0 separator colonSplit;
+ rightSplit = sublist (separator + 1) (length colonSplit - separator - 1) colonSplit;
- fullSplit =
- if separator != null
- then leftSplit ++ zeroFill ++ rightSplit
- else colonSplit;
+ fullSplit =
+ if separator != null
+ then leftSplit ++ zeroFill ++ rightSplit
+ else colonSplit;
- padded = map (hextet: strings.replicate (4 - stringLength hextet) "0" + hextet) fullSplit;
- in
+ padded = map (hextet: strings.replicate (4 - stringLength hextet) "0" + hextet) fullSplit;
+ in
reverseList (sublist 0 (bits / 4) (flatten (map stringToCharacters padded)));
- matchPtrRecordName = { splitter, netAddress, netBits, targetAddress, targetBits }:
- let
- netSplit = splitter netAddress netBits;
- targetSplit = splitter targetAddress targetBits;
-
- netLength = length netSplit;
- lengthDelta = length targetSplit - netLength;
-
- withinNet = lengthDelta >= 0 && sublist lengthDelta netLength targetSplit == netSplit;
- throwMessage = "${targetAddress}/${toString targetBits} is not a subset of ${netAddress}/${toString netBits}";
-
- recordHierarchy = sublist 0 lengthDelta targetSplit;
-
- recordName =
- if recordHierarchy != [ ]
- then concatStringsSep "." recordHierarchy
- else "@";
- in
+ matchPtrRecordName = {
+ splitter,
+ netAddress,
+ netBits,
+ targetAddress,
+ targetBits,
+ }: let
+ netSplit = splitter netAddress netBits;
+ targetSplit = splitter targetAddress targetBits;
+
+ netLength = length netSplit;
+ lengthDelta = length targetSplit - netLength;
+
+ withinNet = lengthDelta >= 0 && sublist lengthDelta netLength targetSplit == netSplit;
+ throwMessage = "${targetAddress}/${toString targetBits} is not a subset of ${netAddress}/${toString netBits}";
+
+ recordHierarchy = sublist 0 lengthDelta targetSplit;
+
+ recordName =
+ if recordHierarchy != []
+ then concatStringsSep "." recordHierarchy
+ else "@";
+ in
throwIfNot withinNet throwMessage recordName;
-in
-{
- options.local.nets = with lib.types; mkOption {
- readOnly = true;
+in {
+ options.local.nets = with lib.types;
+ mkOption {
+ readOnly = true;
- type = attrsOf (submodule ({ config, ... }: {
- options =
- let
+ type = attrsOf (submodule ({config, ...}: {
+ options = let
v4config = config.v4;
v6config = config.v6;
- in
- {
+ in {
hosts = mkOption {
- default = { };
+ default = {};
type = attrsOf (submodule {
options = {
v4 = mkOption {
default = null;
- type = nullOr (submodule ({ config, ... }: {
+ type = nullOr (submodule ({config, ...}: {
options = {
suffix = mkOption {
type = str;
@@ -98,7 +104,7 @@ in
v6 = mkOption {
default = null;
- type = nullOr (submodule ({ config, ... }: {
+ type = nullOr (submodule ({config, ...}: {
options = {
suffix = mkOption {
type = str;
@@ -121,19 +127,21 @@ in
};
config = {
- address =
- let
- hextets = fragment: length (splitString ":" fragment);
- separator = if doubleColon then "::" else ":";
- doubleColon = hextets v6config.prefix + hextets config.suffix < 8;
-
- joined =
- if v6config.bits == 128
- then v6config.prefix
- else if v6config.bits == 0
- then config.suffix
- else "${v6config.prefix}${separator}${config.suffix}";
- in
+ address = let
+ hextets = fragment: length (splitString ":" fragment);
+ separator =
+ if doubleColon
+ then "::"
+ else ":";
+ doubleColon = hextets v6config.prefix + hextets config.suffix < 8;
+
+ joined =
+ if v6config.bits == 128
+ then v6config.prefix
+ else if v6config.bits == 0
+ then config.suffix
+ else "${v6config.prefix}${separator}${config.suffix}";
+ in
joined;
cidr = "${config.address}/${toString v6config.bits}";
@@ -148,10 +156,10 @@ in
v4 = mkOption {
default = null;
- type = nullOr (submodule ({ config, ... }: {
+ type = nullOr (submodule ({config, ...}: {
options = {
bits = mkOption {
- type = enum [ 0 8 16 24 32 ];
+ type = enum [0 8 16 24 32];
};
prefix = mkOption {
@@ -189,15 +197,16 @@ in
ptrDomain = concatStrings (map (x: x + ".") (v4PtrHierarchy config.subnet config.bits)) + "in-addr.arpa";
- ptrRecordName = address: bits: matchPtrRecordName {
- splitter = v4PtrHierarchy;
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v4PtrHierarchy;
- netBits = config.bits;
- netAddress = config.subnet;
+ netBits = config.bits;
+ netAddress = config.subnet;
- targetBits = bits;
- targetAddress = address;
- };
+ targetBits = bits;
+ targetAddress = address;
+ };
};
}));
};
@@ -205,12 +214,14 @@ in
v6 = mkOption {
default = null;
- type = nullOr (submodule ({ config, ... }: {
+ type = nullOr (submodule ({config, ...}: {
options = {
bits = mkOption {
- type = addCheck (ints.between 0 128) (b: mod b 4 == 0) // {
- description = "IPv6 subnet bits at nibble boundary";
- };
+ type =
+ addCheck (ints.between 0 128) (b: mod b 4 == 0)
+ // {
+ description = "IPv6 subnet bits at nibble boundary";
+ };
};
prefix = mkOption {
@@ -248,19 +259,20 @@ in
ptrDomain = concatStrings (map (x: x + ".") (v6PtrHierarchy config.subnet config.bits)) + "ip6.arpa";
- ptrRecordName = address: bits: matchPtrRecordName {
- splitter = v6PtrHierarchy;
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v6PtrHierarchy;
- netBits = config.bits;
- netAddress = config.subnet;
+ netBits = config.bits;
+ netAddress = config.subnet;
- targetBits = bits;
- targetAddress = address;
- };
+ targetBits = bits;
+ targetAddress = address;
+ };
};
}));
};
};
- }));
- };
+ }));
+ };
}
diff --git a/sys/net/vsock.nix b/sys/net/vsock.nix
index d1bd250..c6b0ad6 100644
--- a/sys/net/vsock.nix
+++ b/sys/net/vsock.nix
@@ -1,59 +1,63 @@
-{ lib, config, pkgs, ... }:
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.net.vsock;
-in
-{
+in {
options.local.net.vsock = {
connect = mkOption {
- default = { };
- type = with lib.types; attrsOf (submodule ({ name, ... }: {
- options = {
- enable = mkEnableOption "vsock connect '${name}'";
+ default = {};
+ type = with lib.types;
+ attrsOf (submodule ({name, ...}: {
+ options = {
+ enable = mkEnableOption "vsock connect '${name}'";
- cid = mkOption {
- type = ints.u32;
- default = 2;
- };
+ cid = mkOption {
+ type = ints.u32;
+ default = 2;
+ };
- localPort = mkOption {
- type = port;
- };
+ localPort = mkOption {
+ type = port;
+ };
- vsockPort = mkOption {
- type = port;
+ vsockPort = mkOption {
+ type = port;
+ };
};
- };
- }));
+ }));
};
};
config = {
- systemd =
- let
- connects = mapAttrs
- (_: connect: {
- service.serviceConfig = {
- Type = "simple";
- ExecStart = "${getExe pkgs.socat} - VSOCK:${toString connect.cid}:${toString connect.vsockPort}";
- StandardInput = "socket";
- };
-
- socket = {
- wantedBy = [ "sockets.target" ];
+ systemd = let
+ connects =
+ mapAttrs
+ (_: connect: {
+ service.serviceConfig = {
+ Type = "simple";
+ ExecStart = "${getExe pkgs.socat} - VSOCK:${toString connect.cid}:${toString connect.vsockPort}";
+ StandardInput = "socket";
+ };
- socketConfig = {
- Accept = true;
- ListenStream = "[::1]:${toString connect.localPort}";
- };
+ socket = {
+ wantedBy = ["sockets.target"];
- unitConfig.ConditionVirtualization = "kvm";
+ socketConfig = {
+ Accept = true;
+ ListenStream = "[::1]:${toString connect.localPort}";
};
- })
- cfg.connect;
- in
- {
- sockets = mapAttrs' (name: connect: nameValuePair "vsock-${name}" connect.socket) connects;
- services = mapAttrs' (name: connect: nameValuePair "vsock-${name}@" connect.service) connects;
- };
+
+ unitConfig.ConditionVirtualization = "kvm";
+ };
+ })
+ cfg.connect;
+ in {
+ sockets = mapAttrs' (name: connect: nameValuePair "vsock-${name}" connect.socket) connects;
+ services = mapAttrs' (name: connect: nameValuePair "vsock-${name}@" connect.service) connects;
+ };
};
}
diff --git a/sys/ns/mx.nix b/sys/ns/mx.nix
index 40a5574..892b684 100644
--- a/sys/ns/mx.nix
+++ b/sys/ns/mx.nix
@@ -1,33 +1,60 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
inherit (config.local) domains;
-in
-{
+in {
options.local.ns.zones = mkOption {
- type = with lib.types; attrsOf (submodule ({ config, name, ... }: {
- options.localMX = {
- enable = mkEnableOption "local MX settings";
- };
+ type = with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: {
+ options.localMX = {
+ enable = mkEnableOption "local MX settings";
+ };
- config = mkIf config.localMX.enable {
- mx = [
- { name = "@"; priority = 10; host = "${domains.smtp.gated}."; }
- { name = "@"; priority = 20; host = "${domains.smtp-backup.main}."; }
- # Many thanks to junkemailfilter.com for all their years of service. RIP.
- #{ name = "@"; priority = 30; host = "mxbackup1.junkemailfilter.com."; }
- #{ name = "@"; priority = 40; host = "mxbackup2.junkemailfilter.com."; }
- ];
+ config = mkIf config.localMX.enable {
+ mx = [
+ {
+ name = "@";
+ priority = 10;
+ host = "${domains.smtp.gated}.";
+ }
+ {
+ name = "@";
+ priority = 20;
+ host = "${domains.smtp-backup.main}.";
+ }
+ # Many thanks to junkemailfilter.com for all their years of service. RIP.
+ #{ name = "@"; priority = 30; host = "mxbackup1.junkemailfilter.com."; }
+ #{ name = "@"; priority = 40; host = "mxbackup2.junkemailfilter.com."; }
+ ];
- txt = [
- { name = "@"; text = "v=spf1 mx a -all"; }
- { name = "_dmarc"; text = "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;fo=1;rf=afrf;rua=mailto:postmaster@${name}"; }
- { name = "_adsp._domainkey"; text = "dkim=all"; }
- ] ++ map
- (selector: {
- name = "${toString selector}._domainkey";
- text = readFile (./dkim + "/${toString selector}.txt");
- }) [ 202001 202102 202402 202408 ];
- };
- }));
+ txt =
+ [
+ {
+ name = "@";
+ text = "v=spf1 mx a -all";
+ }
+ {
+ name = "_dmarc";
+ text = "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;fo=1;rf=afrf;rua=mailto:postmaster@${name}";
+ }
+ {
+ name = "_adsp._domainkey";
+ text = "dkim=all";
+ }
+ ]
+ ++ map
+ (selector: {
+ name = "${toString selector}._domainkey";
+ text = readFile (./dkim + "/${toString selector}.txt");
+ }) [202001 202102 202402 202408];
+ };
+ }));
};
}
diff --git a/sys/ns/ns.nix b/sys/ns/ns.nix
index 1e74502..e5b30e8 100644
--- a/sys/ns/ns.nix
+++ b/sys/ns/ns.nix
@@ -1,130 +1,153 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
inherit (config.networking) domain;
inherit (config.local.nets) gate-public;
inherit (config.local.ns.server) tsigName;
ptrNets = config.local.ns.ptr;
-in
-{
+in {
options.local.ns.zones = mkOption {
- type = with lib.types; attrsOf
+ type = with lib.types;
+ attrsOf
(submodule
- ({ config, name, ... }:
- let
- inherit (config.soa) primary;
-
- cfg = config.localNS;
- ptrDomain = cfg.ptrNet.v4 != null || cfg.ptrNet.v6 != null;
- in
- {
- options.localNS = {
- enable = mkEnableOption "local NS settings";
-
- acme = mkOption {
- default = { };
- type = attrsOf str;
- };
+ ({
+ config,
+ name,
+ ...
+ }: let
+ inherit (config.soa) primary;
+
+ cfg = config.localNS;
+ ptrDomain = cfg.ptrNet.v4 != null || cfg.ptrNet.v6 != null;
+ in {
+ options.localNS = {
+ enable = mkEnableOption "local NS settings";
+
+ acme = mkOption {
+ default = {};
+ type = attrsOf str;
+ };
- ptrNet = {
- v4 = mkOption {
- type = nullOr str;
- default = null;
- };
+ ptrNet = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
- v6 = mkOption {
- type = nullOr str;
- default = null;
- };
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
};
};
-
- config = mkIf cfg.enable
- {
- ptrName =
- let
- name =
- if cfg.ptrNet.v6 != null
- then "${cfg.ptrNet.v6}-v6"
- else "${cfg.ptrNet.v4}-v4";
- in
- mkIf ptrDomain name;
-
- # https://docs.gandi.net/en/domain_names/advanced_users/secondary_nameserver.html
- nsdConfig =
- let
- providerSecondary = [
- "37.205.15.45 ${tsigName}" # ns3.vpsfree.cz
- "37.205.11.85 ${tsigName}" # ns4.vpsfree.cz
- "2a03:3b40:fe:2be::1 ${tsigName}" # ns3.vpsfree.cz
- "2a03:3b40:101:4::1 ${tsigName}" # ns4.vpsfree.cz
- ];
- in
- {
- notify = providerSecondary;
- provideXFR = providerSecondary;
- };
-
- ns = [
- { name = "@"; host = primary; }
- { name = "@"; host = "ns3.vpsfree.cz."; }
- { name = "@"; host = "ns4.vpsfree.cz."; }
+ };
+
+ config =
+ mkIf cfg.enable
+ {
+ ptrName = let
+ name =
+ if cfg.ptrNet.v6 != null
+ then "${cfg.ptrNet.v6}-v6"
+ else "${cfg.ptrNet.v4}-v4";
+ in
+ mkIf ptrDomain name;
+
+ # https://docs.gandi.net/en/domain_names/advanced_users/secondary_nameserver.html
+ nsdConfig = let
+ providerSecondary = [
+ "37.205.15.45 ${tsigName}" # ns3.vpsfree.cz
+ "37.205.11.85 ${tsigName}" # ns4.vpsfree.cz
+ "2a03:3b40:fe:2be::1 ${tsigName}" # ns3.vpsfree.cz
+ "2a03:3b40:101:4::1 ${tsigName}" # ns4.vpsfree.cz
];
+ in {
+ notify = providerSecondary;
+ provideXFR = providerSecondary;
+ };
- a = optional (!ptrDomain)
- { name = primary; ipv4 = gate-public.hosts.gate.v4.address; ptr = null; };
-
- aaaa = optional (!ptrDomain)
- { name = primary; ipv6 = gate-public.hosts.gate.v6.address; ptr = null; };
+ ns = [
+ {
+ name = "@";
+ host = primary;
+ }
+ {
+ name = "@";
+ host = "ns3.vpsfree.cz.";
+ }
+ {
+ name = "@";
+ host = "ns4.vpsfree.cz.";
+ }
+ ];
+
+ a =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv4 = gate-public.hosts.gate.v4.address;
+ ptr = null;
+ };
- ptr =
- let
- ptrsToRecords = mapAttrsToList (suffix: target: {
- name = suffix;
- inherit target;
- });
+ aaaa =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv6 = gate-public.hosts.gate.v6.address;
+ ptr = null;
+ };
- v4Net = cfg.ptrNet.v4;
- v6Net = cfg.ptrNet.v6;
+ ptr = let
+ ptrsToRecords = mapAttrsToList (suffix: target: {
+ name = suffix;
+ inherit target;
+ });
- v4Records = optionals (v4Net != null) (ptrsToRecords ptrNets.${v4Net}.v4.targets);
- v6Records = optionals (v6Net != null) (ptrsToRecords ptrNets.${v6Net}.v6.targets);
- in
- v4Records ++ v6Records;
+ v4Net = cfg.ptrNet.v4;
+ v6Net = cfg.ptrNet.v6;
- soa = mkIf ptrDomain {
- authorityZone = mkDefault "${domain}.";
- };
+ v4Records = optionals (v4Net != null) (ptrsToRecords ptrNets.${v4Net}.v4.targets);
+ v6Records = optionals (v6Net != null) (ptrsToRecords ptrNets.${v6Net}.v6.targets);
+ in
+ v4Records ++ v6Records;
- cname = mapAttrsToList
- (name: id: {
- name = "_acme-challenge" + optionalString (name != "@") ".${name}";
- target = "${id}.acme-challenge.${domain}.";
- })
- cfg.acme;
+ soa = mkIf ptrDomain {
+ authorityZone = mkDefault "${domain}.";
};
- }));
- };
- config =
- {
- assertions = mapAttrsToList
- (name: zone: {
- assertion = zone.localNS.ptrNet.v4 != null -> zone.localNS.ptrNet.v6 == null;
- message = "zone '${name}' defined as both a v4 and v6 PTR zone";
- })
- config.local.ns.zones;
-
- local.ns.ptr =
- let
- zonePtrNets = name: zone:
- optionalAttrs (zone.localNS.ptrNet.v4 != null)
- {
- ${zone.localNS.ptrNet.v4}.v4.zone = name;
- } // optionalAttrs (zone.localNS.ptrNet.v6 != null) {
- ${zone.localNS.ptrNet.v6}.v6.zone = name;
+ cname =
+ mapAttrsToList
+ (name: id: {
+ name = "_acme-challenge" + optionalString (name != "@") ".${name}";
+ target = "${id}.acme-challenge.${domain}.";
+ })
+ cfg.acme;
};
- in
- mkMerge (flatten (mapAttrsToList zonePtrNets (filterAttrs (_: zone: zone.localNS.enable) config.local.ns.zones)));
- };
+ }));
+ };
+
+ config = {
+ assertions =
+ mapAttrsToList
+ (name: zone: {
+ assertion = zone.localNS.ptrNet.v4 != null -> zone.localNS.ptrNet.v6 == null;
+ message = "zone '${name}' defined as both a v4 and v6 PTR zone";
+ })
+ config.local.ns.zones;
+
+ local.ns.ptr = let
+ zonePtrNets = name: zone:
+ optionalAttrs (zone.localNS.ptrNet.v4 != null)
+ {
+ ${zone.localNS.ptrNet.v4}.v4.zone = name;
+ }
+ // optionalAttrs (zone.localNS.ptrNet.v6 != null) {
+ ${zone.localNS.ptrNet.v6}.v6.zone = name;
+ };
+ in
+ mkMerge (flatten (mapAttrsToList zonePtrNets (filterAttrs (_: zone: zone.localNS.enable) config.local.ns.zones)));
+ };
}
diff --git a/sys/ns/nsd.nix b/sys/ns/nsd.nix
index 1dfa16b..d49e464 100644
--- a/sys/ns/nsd.nix
+++ b/sys/ns/nsd.nix
@@ -1,12 +1,15 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
inherit (config.networking) domain;
cfg = config.local.ns.server;
acmeChallengeDomain = "acme-challenge.${domain}";
-in
-{
+in {
options. local. ns. server = {
enable = mkEnableOption "nsd authoritative server";
@@ -34,14 +37,12 @@ in
}
];
- networking.firewall =
- let
- inherit (config.services.nsd) port;
- in
- {
- allowedTCPPorts = [ port ];
- allowedUDPPorts = [ port ];
- };
+ networking.firewall = let
+ inherit (config.services.nsd) port;
+ in {
+ allowedTCPPorts = [port];
+ allowedUDPPorts = [port];
+ };
services = {
acme-dns = {
diff --git a/sys/ns/ptr/default.nix b/sys/ns/ptr/default.nix
index d583dd7..b4fba7e 100644
--- a/sys/ns/ptr/default.nix
+++ b/sys/ns/ptr/default.nix
@@ -1,8 +1,6 @@
-{ config, ... }:
-let
+{config, ...}: let
inherit (config.local) nets;
-in
-{
+in {
config.local.ns.zones = {
${nets.gate-public.v4.ptrDomain} = import ./gate-public-v4;
${nets.gate-public.v6.ptrDomain} = import ./gate-public-v6;
diff --git a/sys/ns/ptr/gate-public-v4/default.nix b/sys/ns/ptr/gate-public-v4/default.nix
index a2595d9..44c7f2e 100644
--- a/sys/ns/ptr/gate-public-v4/default.nix
+++ b/sys/ns/ptr/gate-public-v4/default.nix
@@ -1,8 +1,6 @@
-{ config, ... }:
-let
+{config, ...}: let
inherit (config.local) nets;
-in
-{
+in {
imports = [
./serial.nix
];
diff --git a/sys/ns/ptr/gate-public-v4/serial.nix b/sys/ns/ptr/gate-public-v4/serial.nix
index c3a41e9..008e5d8 100644
--- a/sys/ns/ptr/gate-public-v4/serial.nix
+++ b/sys/ns/ptr/gate-public-v4/serial.nix
@@ -4,4 +4,3 @@
nullSerialHash = "sha256-afaedee02017aabd45b944a657ce91515866982c7cb900927edcee6d2b39c731";
};
}
-
diff --git a/sys/ns/ptr/gate-public-v6/default.nix b/sys/ns/ptr/gate-public-v6/default.nix
index 15a4095..674421f 100644
--- a/sys/ns/ptr/gate-public-v6/default.nix
+++ b/sys/ns/ptr/gate-public-v6/default.nix
@@ -1,8 +1,6 @@
-{ config, ... }:
-let
+{config, ...}: let
inherit (config.local) nets;
-in
-{
+in {
imports = [
./serial.nix
];
diff --git a/sys/ns/ptr/gate-public-v6/serial.nix b/sys/ns/ptr/gate-public-v6/serial.nix
index 2f1b4a9..126a17e 100644
--- a/sys/ns/ptr/gate-public-v6/serial.nix
+++ b/sys/ns/ptr/gate-public-v6/serial.nix
@@ -4,4 +4,3 @@
nullSerialHash = "sha256-9a8ac8849ea6c8993e44feefe439b96c643e2ccf3a03d0d700558e9a188f57d7";
};
}
-
diff --git a/sys/ns/ptr/static-prefix-v6/default.nix b/sys/ns/ptr/static-prefix-v6/default.nix
index f02222c..7688b97 100644
--- a/sys/ns/ptr/static-prefix-v6/default.nix
+++ b/sys/ns/ptr/static-prefix-v6/default.nix
@@ -1,8 +1,6 @@
-{ config, ... }:
-let
+{config, ...}: let
inherit (config.local) nets;
-in
-{
+in {
imports = [
./serial.nix
];
diff --git a/sys/ns/ptr/static-prefix-v6/serial.nix b/sys/ns/ptr/static-prefix-v6/serial.nix
index 454b3dd..a7c214a 100644
--- a/sys/ns/ptr/static-prefix-v6/serial.nix
+++ b/sys/ns/ptr/static-prefix-v6/serial.nix
@@ -4,4 +4,3 @@
nullSerialHash = "sha256-a5ce7781b014aa816998410db440dd40278d8b566d1de76e06776a83c9839b35";
};
}
-
diff --git a/sys/ns/rr.nix b/sys/ns/rr.nix
index e4fbe12..8b4d119 100644
--- a/sys/ns/rr.nix
+++ b/sys/ns/rr.nix
@@ -1,4 +1,10 @@
-{ config, lib, options, pkgs, ... }:
+{
+ config,
+ lib,
+ options,
+ pkgs,
+ ...
+}:
with lib; let
inherit (config.local) nets;
@@ -11,15 +17,13 @@ with lib; let
domainRefType = lib.types.strMatching "@|${segmentRegex}\\.?";
domainNameType = lib.types.strMatching "${segmentRegex}\\.";
- zoneHashCheck = name: zone:
- let
- zoneHash = algorithm: "${algorithm}-${builtins.hashString algorithm cfg.nullSerialZones.${name}.content}";
- expected = zoneHash "sha256";
- in
- {
- inherit expected zone;
- needsUpdate = zone.soa.serial == null || zone.nullSerialHash != expected;
- };
+ zoneHashCheck = name: zone: let
+ zoneHash = algorithm: "${algorithm}-${builtins.hashString algorithm cfg.nullSerialZones.${name}.content}";
+ expected = zoneHash "sha256";
+ in {
+ inherit expected zone;
+ needsUpdate = zone.soa.serial == null || zone.nullSerialHash != expected;
+ };
rrTypes = [
"A"
@@ -32,8 +36,7 @@ with lib; let
"SRV"
"TXT"
];
-in
-{
+in {
options.local.ns = {
nullSerialZones = mkOption {
type = options.local.ns.zones.type;
@@ -41,54 +44,62 @@ in
};
ptr = mkOption {
- default = { };
+ default = {};
- type = with lib.types; attrsOf (submodule {
- options = {
- v4 = {
- zone = mkOption {
- type = nullOr str;
- default = null;
- };
+ type = with lib.types;
+ attrsOf (submodule {
+ options = {
+ v4 = {
+ zone = mkOption {
+ type = nullOr str;
+ default = null;
+ };
- targets = mkOption {
- type = attrsOf str;
- default = { };
+ targets = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
};
- };
- v6 = {
- zone = mkOption {
- type = nullOr str;
- default = null;
- };
+ v6 = {
+ zone = mkOption {
+ type = nullOr str;
+ default = null;
+ };
- targets = mkOption {
- type = attrsOf str;
- default = { };
+ targets = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
};
};
- };
- });
+ });
};
zones = mkOption {
- default = { };
-
- type = with lib.types; attrsOf (submodule ({ config, name, ... }:
- let
- nameOption = args@{ defaultZone ? "${name}.", permitRelative ? true, ... }:
- mkOption (removeAttrs args [ "defaultZone" "permitRelative" ] // {
+ default = {};
+
+ type = with lib.types; attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: let
+ nameOption = args @ {
+ defaultZone ? "${name}.",
+ permitRelative ? true,
+ ...
+ }:
+ mkOption (removeAttrs args ["defaultZone" "permitRelative"]
+ // {
type = domainRefType;
- apply = value:
- let
- zone =
- throwIfNot
- (hasSuffix "." defaultZone)
- "zone expression '${defaultZone}' must be absolute, not relative"
- defaultZone;
- in
+ apply = value: let
+ zone =
+ throwIfNot
+ (hasSuffix "." defaultZone)
+ "zone expression '${defaultZone}' must be absolute, not relative"
+ defaultZone;
+ in
if value == "@"
then zone
else if hasSuffix "." value
@@ -98,401 +109,410 @@ in
else throw "zone expression '${value}' in zone '${zone}' must be absolute, not relative";
});
- rrType = options: mkOption {
- default = [ ];
+ rrType = options:
+ mkOption {
+ default = [];
type = listOf (submodule {
- options = options // {
- name = nameOption { };
-
- ttl = mkOption {
- type = int;
- default = config.defaultTTL;
+ options =
+ options
+ // {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
};
- };
});
};
- rrConfig = { rrs, type, format, applyName ? (rr: rr.name) }: (map
- (rr: {
- inherit type;
- inherit (rr) ttl;
+ rrConfig = {
+ rrs,
+ type,
+ format,
+ applyName ? (rr: rr.name),
+ }: (map
+ (rr: {
+ inherit type;
+ inherit (rr) ttl;
+
+ data = format rr;
+ name = applyName rr;
+ })
+ rrs);
+ in {
+ options = {
+ local = mkOption {
+ type = unspecified;
+ default = globalConfig.local;
+ readOnly = true;
+ };
- data = format rr;
- name = applyName rr;
- })
- rrs);
- in
- {
- options = {
- local = mkOption {
- type = unspecified;
- default = globalConfig.local;
- readOnly = true;
- };
+ defaultTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
- defaultTTL = mkOption {
- type = int;
- default = 3600;
+ ptrName = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ defaultPtr = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
};
- ptrName = mkOption {
+ v6 = mkOption {
type = nullOr str;
default = null;
};
+ };
- defaultPtr = {
- v4 = mkOption {
- type = nullOr str;
- default = null;
- };
+ nsdConfig = mkOption {
+ type = attrsOf unspecified;
+ default = {};
+ };
- v6 = mkOption {
- type = nullOr str;
- default = null;
- };
+ content = mkOption {
+ type = lines;
+ readOnly = true;
+ };
+
+ nullSerialHash = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ rr = mkOption {
+ default = [];
+ type =
+ listOf
+ (submodule {
+ options = {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ };
+
+ class = mkOption {
+ type = enum ["IN"];
+ default = "IN";
+ };
+
+ type = mkOption {
+ type = enum rrTypes;
+ };
+
+ data = mkOption {
+ type = listOf (either int str);
+ default = [];
+ };
+ };
+ });
+ };
+
+ soa = {
+ authorityZone = nameOption {
+ default = "@";
+ permitRelative = false;
+ };
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
};
- nsdConfig = mkOption {
- type = attrsOf unspecified;
- default = { };
+ primary = nameOption {
+ default = "ns1";
+ defaultZone = config.soa.authorityZone;
};
- content = mkOption {
- type = lines;
- readOnly = true;
+ hostmaster = mkOption {
+ type = emailType;
+ default = "hostmaster";
+
+ apply = address: let
+ split = splitString "@" address;
+
+ user = head split;
+ domain =
+ if length split == 2
+ then head (tail split)
+ else removeSuffix "." config.soa.authorityZone;
+ in
+ if hasSuffix "." address
+ then address
+ else "${replaceStrings ["."] ["\\."] user}.${domain}.";
};
- nullSerialHash = mkOption {
- type = nullOr str;
+ serial = mkOption {
+ type = nullOr int;
default = null;
};
- rr = mkOption {
- default = [ ];
- type = listOf
- (submodule {
- options = {
- name = nameOption { };
-
- ttl = mkOption {
- type = int;
- };
-
- class = mkOption {
- type = enum [ "IN" ];
- default = "IN";
- };
-
- type = mkOption {
- type = enum rrTypes;
- };
-
- data = mkOption {
- type = listOf (either int str);
- default = [ ];
- };
- };
- });
+ refresh = mkOption {
+ type = int;
+ default = 3 * 3600;
};
- soa = {
- authorityZone = nameOption { default = "@"; permitRelative = false; };
-
- ttl = mkOption {
- type = int;
- default = config.defaultTTL;
- };
+ retry = mkOption {
+ type = int;
+ default = 3600;
+ };
- primary = nameOption {
- default = "ns1";
- defaultZone = config.soa.authorityZone;
- };
+ expire = mkOption {
+ type = int;
+ default = 7 * 24 * 3600;
+ };
- hostmaster = mkOption {
- type = emailType;
- default = "hostmaster";
+ negativeTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
+ };
- apply = address:
- let
- split = splitString "@" address;
+ a = rrType {
+ ipv4 = mkOption {
+ type = str;
+ };
- user = head split;
- domain = if length split == 2 then head (tail split) else removeSuffix "." config.soa.authorityZone;
- in
- if hasSuffix "." address
- then address
- else "${replaceStrings [ "." ] [ "\\." ] user}.${domain}.";
- };
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v4;
+ };
+ };
- serial = mkOption {
- type = nullOr int;
- default = null;
- };
+ aaaa = rrType {
+ ipv6 = mkOption {
+ type = str;
+ };
- refresh = mkOption {
- type = int;
- default = 3 * 3600;
- };
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v6;
+ };
+ };
- retry = mkOption {
- type = int;
- default = 3600;
- };
+ cname = rrType {
+ target = nameOption {};
+ };
- expire = mkOption {
- type = int;
- default = 7 * 24 * 3600;
- };
+ mx = rrType {
+ host = nameOption {};
- negativeTTL = mkOption {
- type = int;
- default = 3600;
- };
+ priority = mkOption {
+ type = int;
};
+ };
- a = rrType {
- ipv4 = mkOption {
- type = str;
- };
+ ns = rrType {
+ host = nameOption {};
+ };
- ptr = mkOption {
- type = nullOr str;
- default = config.defaultPtr.v4;
- };
- };
+ ptr = rrType {
+ target = nameOption {};
+ };
- aaaa = rrType {
- ipv6 = mkOption {
- type = str;
- };
+ srv = rrType {
+ host = nameOption {};
- ptr = mkOption {
- type = nullOr str;
- default = config.defaultPtr.v6;
- };
+ port = mkOption {
+ type = port;
};
- cname = rrType {
- target = nameOption { };
+ priority = mkOption {
+ type = int;
};
- mx = rrType {
- host = nameOption { };
+ proto = mkOption {
+ type = enum ["tcp" "udp"];
+ };
- priority = mkOption {
- type = int;
- };
+ service = mkOption {
+ type = str;
};
- ns = rrType {
- host = nameOption { };
+ weight = mkOption {
+ type = int;
};
+ };
- ptr = rrType {
- target = nameOption { };
+ txt = rrType {
+ text = mkOption {
+ type = strMatching "[^\"\n\\]*\n?";
+ apply = removeSuffix "\n";
};
+ };
+ };
- srv = rrType {
- host = nameOption { };
+ config = {
+ nsdConfig.data = config.content;
+
+ content = let
+ rrLine = rr: concatMapStringsSep " " toString ([rr.name rr.ttl rr.class rr.type] ++ rr.data);
+ in
+ ''
+ $ORIGIN ${name}.
+ $TTL ${toString config.defaultTTL}
+ ''
+ + concatLines (map rrLine config.rr);
+
+ rr = mkMerge [
+ (mkOrder 0 (singleton {
+ inherit (config.soa) ttl;
+
+ name = "${name}.";
+ type = "SOA";
+
+ data = with config.soa; [
+ primary
+ hostmaster
+ (throwIf (serial == null) "No serial defined for zone ${name}" serial)
+ refresh
+ retry
+ expire
+ negativeTTL
+ ];
+ }))
+
+ (mkOrder 1 (rrConfig {
+ rrs = config.ns;
+ type = "NS";
+ format = rr: [rr.host];
+ }))
+
+ (rrConfig {
+ rrs = config.a;
+ type = "A";
+ format = rr: [rr.ipv4];
+ })
- port = mkOption {
- type = port;
- };
+ (rrConfig {
+ rrs = config.aaaa;
+ type = "AAAA";
+ format = rr: [rr.ipv6];
+ })
- priority = mkOption {
- type = int;
- };
+ (rrConfig {
+ rrs = config.cname;
+ type = "CNAME";
+ format = rr: [rr.target];
+ })
- proto = mkOption {
- type = enum [ "tcp" "udp" ];
- };
+ (rrConfig {
+ rrs = config.mx;
+ type = "MX";
+ format = rr: [rr.priority rr.host];
+ })
- service = mkOption {
- type = str;
- };
+ (rrConfig {
+ rrs = config.ptr;
+ type = "PTR";
+ format = rr: [rr.target];
+ })
- weight = mkOption {
- type = int;
- };
- };
+ (rrConfig {
+ rrs = config.srv;
+ type = "SRV";
- txt = rrType {
- text = mkOption {
- type = strMatching "[^\"\n\\]*\n?";
- apply = removeSuffix "\n";
- };
- };
- };
+ format = rr: [rr.priority rr.weight rr.port rr.host];
+ applyName = rr: "_${rr.service}._${rr.proto}.${rr.name}";
+ })
- config = {
- nsdConfig.data = config.content;
+ (rrConfig {
+ rrs = config.txt;
+ type = "TXT";
- content =
- let
- rrLine = rr: concatMapStringsSep " " toString ([ rr.name rr.ttl rr.class rr.type ] ++ rr.data);
+ format = rr: let
+ # nsd-zonecheck: text string is longer than 255 characters, try splitting it into multiple parts
+ txtFragments = text: let
+ max = 255;
+ length = stringLength text;
+ in
+ singleton (substring 0 max text) ++ optionals (length > max) (txtFragments (substring max length text));
in
- ''
- $ORIGIN ${name}.
- $TTL ${toString config.defaultTTL}
- '' + concatLines (map rrLine config.rr);
-
- rr = mkMerge [
- (mkOrder 0 (singleton {
- inherit (config.soa) ttl;
-
- name = "${name}.";
- type = "SOA";
-
- data = with config.soa; [
- primary
- hostmaster
- (throwIf (serial == null) "No serial defined for zone ${name}" serial)
- refresh
- retry
- expire
- negativeTTL
- ];
- }))
-
- (mkOrder 1 (rrConfig {
- rrs = config.ns;
- type = "NS";
- format = rr: [ rr.host ];
- }))
-
- (rrConfig {
- rrs = config.a;
- type = "A";
- format = rr: [ rr.ipv4 ];
- })
-
- (rrConfig {
- rrs = config.aaaa;
- type = "AAAA";
- format = rr: [ rr.ipv6 ];
- })
-
- (rrConfig {
- rrs = config.cname;
- type = "CNAME";
- format = rr: [ rr.target ];
- })
-
- (rrConfig {
- rrs = config.mx;
- type = "MX";
- format = rr: [ rr.priority rr.host ];
- })
-
- (rrConfig {
- rrs = config.ptr;
- type = "PTR";
- format = rr: [ rr.target ];
- })
-
- (rrConfig {
- rrs = config.srv;
- type = "SRV";
-
- format = rr: [ rr.priority rr.weight rr.port rr.host ];
- applyName = rr: "_${rr.service}._${rr.proto}.${rr.name}";
- })
-
- (rrConfig {
- rrs = config.txt;
- type = "TXT";
-
- format = rr:
- let
- # nsd-zonecheck: text string is longer than 255 characters, try splitting it into multiple parts
- txtFragments = text:
- let
- max = 255;
- length = stringLength text;
- in
- singleton (substring 0 max text) ++ optionals (length > max) (txtFragments (substring max length text));
- in
- map (fragment: "\"${fragment}\"") (txtFragments rr.text);
- })
- ];
- };
- }));
+ map (fragment: "\"${fragment}\"") (txtFragments rr.text);
+ })
+ ];
+ };
+ }));
};
};
config = {
- assertions = [
- (
- let
- badZones = attrNames (filterAttrs (name: zone: (zoneHashCheck name zone).needsUpdate) cfg.zones);
- in
- {
- assertion = badZones == [ ];
- message = "Update serials for these zones (null-serial hash mismatch): ${concatStringsSep ", " badZones}";
- }
- )
- ] ++ flatten (mapAttrsToList
- (name: ptr: [
- {
- assertion = ptr.v4.targets != { } -> ptr.v4.zone != null;
- message = "undefined v4 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v4.targets)}";
- }
- {
- assertion = ptr.v6.targets != { } -> ptr.v6.zone != null;
- message = "undefined v6 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v6.targets)}";
- }
- ])
- cfg.ptr);
-
- lib.local.zoneSerialUpdates =
- let
- ptrChecks = filterAttrs (_: check: check.zone.ptrName != null) allZoneChecks;
- zoneChecks = filterAttrs (_: check: check.zone.ptrName == null) allZoneChecks;
- allZoneChecks = filterAttrs (_: check: check.needsUpdate) (mapAttrs zoneHashCheck cfg.zones);
-
- updateInfo = name: check: {
- inherit name;
- inherit (check) expected;
- inherit (check.zone.soa) serial;
- };
- in
- {
- ptr = mapAttrs (_: check: updateInfo check.zone.ptrName check) ptrChecks;
- zones = mapAttrs updateInfo zoneChecks;
+ assertions =
+ [
+ (
+ let
+ badZones = attrNames (filterAttrs (name: zone: (zoneHashCheck name zone).needsUpdate) cfg.zones);
+ in {
+ assertion = badZones == [];
+ message = "Update serials for these zones (null-serial hash mismatch): ${concatStringsSep ", " badZones}";
+ }
+ )
+ ]
+ ++ flatten (mapAttrsToList
+ (name: ptr: [
+ {
+ assertion = ptr.v4.targets != {} -> ptr.v4.zone != null;
+ message = "undefined v4 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v4.targets)}";
+ }
+ {
+ assertion = ptr.v6.targets != {} -> ptr.v6.zone != null;
+ message = "undefined v6 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v6.targets)}";
+ }
+ ])
+ cfg.ptr);
+
+ lib.local.zoneSerialUpdates = let
+ ptrChecks = filterAttrs (_: check: check.zone.ptrName != null) allZoneChecks;
+ zoneChecks = filterAttrs (_: check: check.zone.ptrName == null) allZoneChecks;
+ allZoneChecks = filterAttrs (_: check: check.needsUpdate) (mapAttrs zoneHashCheck cfg.zones);
+
+ updateInfo = name: check: {
+ inherit name;
+ inherit (check) expected;
+ inherit (check.zone.soa) serial;
};
+ in {
+ ptr = mapAttrs (_: check: updateInfo check.zone.ptrName check) ptrChecks;
+ zones = mapAttrs updateInfo zoneChecks;
+ };
local.ns = {
- nullSerialZones =
- let
- defaultAttrs = [ "defaultTTL" "defaultPtr" "ptrName" ];
- filteredAttrs = defaultAttrs ++ map toLower rrTypes;
- in
+ nullSerialZones = let
+ defaultAttrs = ["defaultTTL" "defaultPtr" "ptrName"];
+ filteredAttrs = defaultAttrs ++ map toLower rrTypes;
+ in
mapAttrs
- (_: zone: mkMerge [
+ (_: zone:
+ mkMerge [
(filterAttrs (name: _: elem name filteredAttrs) zone)
- { soa.serial = mkOverride 0 0; }
+ {soa.serial = mkOverride 0 0;}
])
- cfg.zones;
-
- ptr =
- let
- zonePtrs = zone:
- let
- v4Ptrs = map
- (a: {
- ${a.ptr}.v4.targets.${nets.${a.ptr}.v4.ptrRecordName a.ipv4 32} = a.name;
- })
- (filter (a: a.ptr != null) zone.a);
-
- v6Ptrs = map
- (aaaa: {
- ${aaaa.ptr}.v6.targets.${nets.${aaaa.ptr}.v6.ptrRecordName aaaa.ipv6 128} = aaaa.name;
- })
- (filter (aaaa: aaaa.ptr != null) zone.aaaa);
- in
- v4Ptrs ++ v6Ptrs;
+ cfg.zones;
+
+ ptr = let
+ zonePtrs = zone: let
+ v4Ptrs =
+ map
+ (a: {
+ ${a.ptr}.v4.targets.${nets.${a.ptr}.v4.ptrRecordName a.ipv4 32} = a.name;
+ })
+ (filter (a: a.ptr != null) zone.a);
+ v6Ptrs =
+ map
+ (aaaa: {
+ ${aaaa.ptr}.v6.targets.${nets.${aaaa.ptr}.v6.ptrRecordName aaaa.ipv6 128} = aaaa.name;
+ })
+ (filter (aaaa: aaaa.ptr != null) zone.aaaa);
in
+ v4Ptrs ++ v6Ptrs;
+ in
mkMerge (flatten (mapAttrsToList (_: zonePtrs) cfg.zones));
};
};
diff --git a/sys/nspawn/dmz.nix b/sys/nspawn/dmz.nix
index fb3acea..805ca72 100644
--- a/sys/nspawn/dmz.nix
+++ b/sys/nspawn/dmz.nix
@@ -1,4 +1,10 @@
-{ lib, config, flakes, pkgs, ... }:
+{
+ lib,
+ config,
+ flakes,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.nspawn.dmz;
inherit (config.local) mailHost;
@@ -7,8 +13,7 @@ with lib; let
hassPort = config.services.home-assistant.config.http.server_port;
hassEnable = config.local.home-assistant.enable;
-in
-{
+in {
options.local.nspawn.dmz = {
enable = mkEnableOption "DMZ services in a container";
@@ -60,71 +65,70 @@ in
nspawn.dmz = {
hostAddr6 = dmzNet.hosts.gateway.v6.address;
- system =
- let
- containerModule = { ... }: {
- #TODO: urgente: bloquear puertos de dovecot a non-postfix con iptables
- config = {
- local = {
- preset.dmz = {
- enable = true;
- container = true;
- };
+ system = let
+ containerModule = {...}: {
+ #TODO: urgente: bloquear puertos de dovecot a non-postfix con iptables
+ config = {
+ local = {
+ preset.dmz = {
+ enable = true;
+ container = true;
+ };
- mta = {
- mdaAddr = "[${mailHost.mdaListen}]";
- inherit (mailHost) saslPort lmtpPort;
- };
+ mta = {
+ mdaAddr = "[${mailHost.mdaListen}]";
+ inherit (mailHost) saslPort lmtpPort;
+ };
- web.sites = {
- home = {
- enable = hassEnable;
- proxyUrl = "http://[${cfg.hostAddr6}]:${toString hassPort}";
- };
+ web.sites = {
+ home = {
+ enable = hassEnable;
+ proxyUrl = "http://[${cfg.hostAddr6}]:${toString hassPort}";
};
};
+ };
- nixpkgs = {
- pkgs = mkDefault pkgs;
- localSystem = mkDefault pkgs.stdenv.hostPlatform;
- };
+ nixpkgs = {
+ pkgs = mkDefault pkgs;
+ localSystem = mkDefault pkgs.stdenv.hostPlatform;
+ };
- services.nginx.virtualHosts = {
- "${config.local.domains.imap.main}".locations."^~ /.well-known/acme-challenge/" = {
- root = "/var/lib/acme/acme-challenge";
+ services.nginx.virtualHosts = {
+ "${config.local.domains.imap.main}".locations."^~ /.well-known/acme-challenge/" = {
+ root = "/var/lib/acme/acme-challenge";
- extraConfig = ''
- auth_basic off;
- auth_request off;
- '';
- };
+ extraConfig = ''
+ auth_basic off;
+ auth_request off;
+ '';
};
+ };
- systemd.network.networks."40-host0" = {
- name = "host0";
+ systemd.network.networks."40-host0" = {
+ name = "host0";
- networkConfig = {
- DNS = [ cfg.dns64 ];
+ networkConfig = {
+ DNS = [cfg.dns64];
- DHCP = "no";
- IPv6AcceptRA = "yes";
- LinkLocalAddressing = "ipv6";
- };
+ DHCP = "no";
+ IPv6AcceptRA = "yes";
+ LinkLocalAddressing = "ipv6";
+ };
- ipv6AcceptRAConfig = {
- Token = [
- "static:::${dmzNet.hosts.dmz.v6.suffix}"
- "eui64"
- "static:::${dmzNet.hosts.mta.v6.suffix}"
- "static:::${dmzNet.hosts.web.v6.suffix}"
- ];
+ ipv6AcceptRAConfig = {
+ Token = [
+ "static:::${dmzNet.hosts.dmz.v6.suffix}"
+ "eui64"
+ "static:::${dmzNet.hosts.mta.v6.suffix}"
+ "static:::${dmzNet.hosts.web.v6.suffix}"
+ ];
- UseDNS = false;
- };
+ UseDNS = false;
};
};
};
- in
+ };
+ in
# Tomado de la definición de pkgs.nixos junto con definición de nixpkgs.{pkgs,localSystem} arriba
import "${flakes.nixpkgs}/nixos/lib/eval-config.nix" {
modules = [
@@ -133,15 +137,15 @@ in
];
system = null;
- specialArgs = { inherit flakes; };
+ specialArgs = {inherit flakes;};
};
};
};
services = {
home-assistant.config.http = mkIf hassEnable {
- server_host = [ cfg.hostAddr6 ];
- trusted_proxies = [ dmzNet.hosts.web.v6.address ];
+ server_host = [cfg.hostAddr6];
+ trusted_proxies = [dmzNet.hosts.web.v6.address];
use_x_forwarded_for = true;
};
};
@@ -199,26 +203,27 @@ in
};
services = {
- dovecot2.after = [ "systemd-nspawn@dmz.service" ];
+ dovecot2.after = ["systemd-nspawn@dmz.service"];
"systemd-nspawn@dmz" = {
overrideStrategy = "asDropin";
- after = [ "network-online.target" ];
- wants = [ "network-online.target" ];
- wantedBy = [ "machines.target" ];
+ after = ["network-online.target"];
+ wants = ["network-online.target"];
+ wantedBy = ["machines.target"];
};
};
};
networking.firewall = {
- allowedTCPPorts = [ 25 80 443 ];
+ allowedTCPPorts = [25 80 443];
interfaces.ve-dmz = {
- allowedTCPPorts = [ mailHost.saslPort mailHost.lmtpPort ]
+ allowedTCPPorts =
+ [mailHost.saslPort mailHost.lmtpPort]
++ optional hassEnable hassPort;
- allowedUDPPorts = [ 67 ]; # DHCP
+ allowedUDPPorts = [67]; # DHCP
};
};
};
diff --git a/sys/preset/dmz.nix b/sys/preset/dmz.nix
index d740d14..5a04c1e 100644
--- a/sys/preset/dmz.nix
+++ b/sys/preset/dmz.nix
@@ -1,8 +1,12 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.preset.dmz;
-in
-{
+in {
options.local.preset.dmz = {
enable = mkEnableOption "dmz preset";
@@ -48,7 +52,7 @@ in
services = {
resolved = {
llmnr = "false";
- fallbackDns = [ ]; # Disable the default systemd-resolved server list
+ fallbackDns = []; # Disable the default systemd-resolved server list
};
};
diff --git a/sys/preset/user.nix b/sys/preset/user.nix
index 886adae..fd9c5ff 100644
--- a/sys/preset/user.nix
+++ b/sys/preset/user.nix
@@ -1,9 +1,12 @@
-{ config, lib, pkgs, ... }:
-let
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
inherit (lib) mkDefault;
cfg = config.local.preset.user;
-in
-{
+in {
options.local.preset.user = {
enable = lib.mkEnableOption "user-like preset";
};
diff --git a/sys/seat/default.nix b/sys/seat/default.nix
index be545e8..402047f 100644
--- a/sys/seat/default.nix
+++ b/sys/seat/default.nix
@@ -1,10 +1,14 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.seat;
users = filterAttrs (_: user: user.install) config.local.users;
-in
-{
+in {
options.local.seat = {
enable = mkEnableOption "user seat";
@@ -23,9 +27,10 @@ in
};
};
- config = mkIf cfg.enable
+ config =
+ mkIf cfg.enable
(mkMerge [
- ({
+ {
hardware = {
acpilight.enable = true;
};
@@ -50,11 +55,14 @@ in
};
users = {
- groups = mapAttrs (_: user: { inherit (user) gid; }) users // {
- adbusers.gid = 1008;
- };
+ groups =
+ mapAttrs (_: user: {inherit (user) gid;}) users
+ // {
+ adbusers.gid = 1008;
+ };
- users = mapAttrs
+ users =
+ mapAttrs
(username: user: {
isNormalUser = true;
@@ -62,13 +70,16 @@ in
description = user.gecos;
group = username;
- extraGroups = [ "users" ] ++ user.groups;
+ extraGroups = ["users"] ++ user.groups;
- shell = if user.allowLogin then pkgs.zsh else null;
+ shell =
+ if user.allowLogin
+ then pkgs.zsh
+ else null;
})
users;
};
- })
+ }
(mkIf cfg.graphical {
environment = {
sessionVariables.NIXOS_OZONE_WL = "1";
@@ -87,8 +98,8 @@ in
gtklock = {
enable = true;
- config = { };
- modules = [ ];
+ config = {};
+ modules = [];
};
};
@@ -101,7 +112,7 @@ in
xserver = mkIf (!cfg.wayland) {
enable = true;
- videoDrivers = cfg.videoDrivers ++ [ "modesetting" "fbdev" ];
+ videoDrivers = cfg.videoDrivers ++ ["modesetting" "fbdev"];
displayManager.startx.enable = mkDefault true;
};
};
@@ -109,18 +120,18 @@ in
xdg.portal = {
enable = true;
wlr.enable = true;
- extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
+ extraPortals = [pkgs.xdg-desktop-portal-gtk];
xdgOpenUsePortal = true;
# warning: xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
# should either set `xdg.portal.config` or `xdg.portal.configPackages`
# to specify which portal backend to use for the requested interface.
- #
+ #
# https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
- #
+ #
# If you simply want to keep the behaviour in < 1.17, which uses the first
# portal implementation found in lexicographical order, use the following:
- #
+ #
# xdg.portal.config.common.default = "*";
config.common.default = "*";
};
diff --git a/sys/syncthing/default.nix b/sys/syncthing/default.nix
index b87e683..951ad30 100644
--- a/sys/syncthing/default.nix
+++ b/sys/syncthing/default.nix
@@ -1,20 +1,23 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.syncthing;
-in
-{
+in {
options.local.syncthing = {
enable = mkEnableOption "syncthing server";
openFirewall = mkEnableOption "syncthing firewall rules";
};
config = mkMerge [
- ({
+ {
networking.firewall = {
allowedTCPPorts = optional cfg.openFirewall 22000;
allowedUDPPorts = optional cfg.openFirewall 22000;
};
- })
+ }
(mkIf cfg.enable {
local.syncthing.openFirewall = true;
@@ -33,7 +36,7 @@ in
relay = {
enable = true;
- pools = [ ];
+ pools = [];
providedBy = "${config.networking.hostName}.${config.networking.domain}";
};
};
diff --git a/sys/virt/libvirt.nix b/sys/virt/libvirt.nix
index 1cc42a9..ebbfbcd 100644
--- a/sys/virt/libvirt.nix
+++ b/sys/virt/libvirt.nix
@@ -1,16 +1,22 @@
-{ config, flakes, lib, pkgs, ... }:
+{
+ config,
+ flakes,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.local.virt;
inherit (config.lib.local) importAll;
- doms = mapAttrs (_: dom: dom { inherit config lib pkgs; }) (importAll { root = ./dom; });
-in
-{
+ doms = mapAttrs (_: dom: dom {inherit config lib pkgs;}) (importAll {root = ./dom;});
+in {
options.local.virt = {
enable = mkEnableOption "hypervisor support";
- dom = mapAttrs
+ dom =
+ mapAttrs
(name: _: {
enable = mkEnableOption "domain ${name}";
})
@@ -19,21 +25,25 @@ in
config = mkIf cfg.enable {
local.boot.impermanence.directories = [
- { directory = "/var/dom"; user = "root"; group = "qemu-libvirtd"; mode = "u=rwx,g=rx,o="; }
+ {
+ directory = "/var/dom";
+ user = "root";
+ group = "qemu-libvirtd";
+ mode = "u=rwx,g=rx,o=";
+ }
];
virtualisation = {
libvirt = {
enable = any (dom: dom.enable) (attrValues cfg.dom);
- connections."qemu:///system".domains =
- let
- makeDomain = def: {
- active = true;
- restart = false;
- definition = flakes.nixvirt.lib.domain.writeXML def;
- };
- in
+ connections."qemu:///system".domains = let
+ makeDomain = def: {
+ active = true;
+ restart = false;
+ definition = flakes.nixvirt.lib.domain.writeXML def;
+ };
+ in
map makeDomain (attrValues (filterAttrs (name: _: cfg.dom.${name}.enable) doms));
swtpm.enable = true;
diff --git a/sys/web/nginx.nix b/sys/web/nginx.nix
index b6e7414..a054289 100644
--- a/sys/web/nginx.nix
+++ b/sys/web/nginx.nix
@@ -1,9 +1,12 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.web;
inherit (config.local) domains;
-in
-{
+in {
options.local.web = {
enable = mkEnableOption "web server";
@@ -13,7 +16,7 @@ in
ownedCerts = mkOption {
type = with lib.types; listOf str;
- default = [ ];
+ default = [];
};
};
@@ -72,7 +75,7 @@ in
})
cfg.ownedCerts);
- networking.firewall.allowedTCPPorts = [ 80 443 ];
+ networking.firewall.allowedTCPPorts = [80 443];
security = {
acme.certs = listToAttrs (map
@@ -80,12 +83,12 @@ in
name = domains.${name}.main;
value = {
group = mkDefault config.services.nginx.group;
- reloadServices = [ "nginx.service" ];
+ reloadServices = ["nginx.service"];
};
})
cfg.ownedCerts);
- dhparams.params.nginx = { };
+ dhparams.params.nginx = {};
};
};
}
diff --git a/sys/web/php-fpm.nix b/sys/web/php-fpm.nix
index 65276ba..33efe1a 100644
--- a/sys/web/php-fpm.nix
+++ b/sys/web/php-fpm.nix
@@ -2,151 +2,153 @@
# See also:
# - <https://albert.cx/20181125-use-separate-systemd-units-for-php-fpm-pools>
# - <https://freedesktop.org/wiki/Software/systemd/DaemonSocketActivation/>
-
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
with lib; let
cfg = config.services.php-fpm-isolated;
- configFile = { pool, poolOpts, runtimeDir, sockFile, pidFile }:
- let
- config = {
- global = {
- daemonize = false;
- error_log = "syslog";
- pid = pidFile;
- };
+ configFile = {
+ pool,
+ poolOpts,
+ runtimeDir,
+ sockFile,
+ pidFile,
+ }: let
+ config = {
+ global = {
+ daemonize = false;
+ error_log = "syslog";
+ pid = pidFile;
+ };
- "${pool}" =
- let
- enforced = {
- inherit (poolOpts) user group;
- listen = sockFile;
- };
+ "${pool}" = let
+ enforced = {
+ inherit (poolOpts) user group;
+ listen = sockFile;
+ };
- defaults = {
- "pm" = "dynamic";
- "pm.max_children" = 16;
- "pm.min_spare_servers" = 1;
- "pm.max_spare_servers" = 4;
- "pm.start_servers" = 1;
- "catch_workers_output" = true;
- "php_admin_flag[log_errors]" = true;
- "env[PATH]" = makeBinPath [ pkgs.php ];
- };
+ defaults = {
+ "pm" = "dynamic";
+ "pm.max_children" = 16;
+ "pm.min_spare_servers" = 1;
+ "pm.max_spare_servers" = 4;
+ "pm.start_servers" = 1;
+ "catch_workers_output" = true;
+ "php_admin_flag[log_errors]" = true;
+ "env[PATH]" = makeBinPath [pkgs.php];
+ };
- env = mapAttrs'
- (name: value: {
- name = "env[${name}]";
- value = "\"${escape [ "\"" ] value}\"";
- })
- poolOpts.env;
- in
- defaults // poolOpts.config // env // enforced;
- };
- in
- (pkgs.formats.ini { }).generate "php-fpm-pool-${pool}.conf" config;
-in
-{
+ env =
+ mapAttrs'
+ (name: value: {
+ name = "env[${name}]";
+ value = "\"${escape ["\""] value}\"";
+ })
+ poolOpts.env;
+ in
+ defaults // poolOpts.config // env // enforced;
+ };
+ in
+ (pkgs.formats.ini {}).generate "php-fpm-pool-${pool}.conf" config;
+in {
options.services.php-fpm-isolated.pools = mkOption {
- default = { };
+ default = {};
- type = with types; attrsOf (submodule {
- options = {
- enable = mkEnableOption "PHP-FPM pool";
+ type = with types;
+ attrsOf (submodule {
+ options = {
+ enable = mkEnableOption "PHP-FPM pool";
- user = mkOption {
- type = str;
- };
+ user = mkOption {
+ type = str;
+ };
- group = mkOption {
- type = str;
- };
+ group = mkOption {
+ type = str;
+ };
- unveil = mkOption {
- type = listOf (either package str);
- };
+ unveil = mkOption {
+ type = listOf (either package str);
+ };
- env = mkOption {
- type = attrsOf str;
- default = { };
- };
+ env = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
- config = mkOption {
- type = attrsOf (oneOf [ int str bool ]);
- default = { };
+ config = mkOption {
+ type = attrsOf (oneOf [int str bool]);
+ default = {};
+ };
};
- };
- });
+ });
};
- config.systemd =
- let
- php-fpm = "${pkgs.php}/bin/php-fpm";
-
- unitsFor = pool: poolOpts:
- let
- runtimeBase = "php-fpm-isolated/${pool}";
- runtimeDir = "/run/${runtimeBase}";
- pidFile = "${runtimeDir}/${pool}.pid";
- sockFile = "${runtimeDir}/${pool}.sock";
- in
- {
- name = "php-fpm-pool-${pool}";
-
- value.service = {
- description = "PHP-FPM process manager for pool '${pool}'";
- after = [ "network.target" ];
-
- confinement.enable = true;
-
- serviceConfig = {
- Type = "notify";
- ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
- PIDFile = pidFile;
-
- Environment = "FPM_SOCKETS=${sockFile}=3";
-
- ExecStart =
- let
- fpmConfig = configFile {
- inherit pool poolOpts runtimeDir sockFile pidFile;
- };
- in
- "${php-fpm} --nodaemonize --fpm-config ${fpmConfig} --pid ${pidFile}";
-
- PrivateTmp = true;
- PrivateNetwork = true;
- PrivateDevices = true;
- # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
- RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
-
- User = poolOpts.user;
- Group = poolOpts.group;
- RuntimeDirectory = runtimeBase;
-
- BindReadOnlyPaths =
- let
- unveiled = map builtins.toString poolOpts.unveil;
- in
- [ "/run/systemd/journal/socket" ] ++ unveiled;
- };
- };
+ config.systemd = let
+ php-fpm = "${pkgs.php}/bin/php-fpm";
+
+ unitsFor = pool: poolOpts: let
+ runtimeBase = "php-fpm-isolated/${pool}";
+ runtimeDir = "/run/${runtimeBase}";
+ pidFile = "${runtimeDir}/${pool}.pid";
+ sockFile = "${runtimeDir}/${pool}.sock";
+ in {
+ name = "php-fpm-pool-${pool}";
- value.socket = {
- description = "PHP-FPM socket for pool '${pool}'";
- listenStreams = [ sockFile ];
+ value.service = {
+ description = "PHP-FPM process manager for pool '${pool}'";
+ after = ["network.target"];
- socketConfig = {
- User = poolOpts.user;
- Group = poolOpts.group;
+ confinement.enable = true;
+
+ serviceConfig = {
+ Type = "notify";
+ ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+ PIDFile = pidFile;
+
+ Environment = "FPM_SOCKETS=${sockFile}=3";
+
+ ExecStart = let
+ fpmConfig = configFile {
+ inherit pool poolOpts runtimeDir sockFile pidFile;
};
- };
+ in "${php-fpm} --nodaemonize --fpm-config ${fpmConfig} --pid ${pidFile}";
+
+ PrivateTmp = true;
+ PrivateNetwork = true;
+ PrivateDevices = true;
+ # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
+ RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
+
+ User = poolOpts.user;
+ Group = poolOpts.group;
+ RuntimeDirectory = runtimeBase;
+
+ BindReadOnlyPaths = let
+ unveiled = map builtins.toString poolOpts.unveil;
+ in
+ ["/run/systemd/journal/socket"] ++ unveiled;
};
+ };
+
+ value.socket = {
+ description = "PHP-FPM socket for pool '${pool}'";
+ listenStreams = [sockFile];
- units = mapAttrs' unitsFor (filterAttrs (_: pool: pool.enable) cfg.pools);
- in
- {
- sockets = mapAttrs (_: unit: unit.socket) units;
- services = mapAttrs (_: unit: unit.service) units;
+ socketConfig = {
+ User = poolOpts.user;
+ Group = poolOpts.group;
+ };
+ };
};
+
+ units = mapAttrs' unitsFor (filterAttrs (_: pool: pool.enable) cfg.pools);
+ in {
+ sockets = mapAttrs (_: unit: unit.socket) units;
+ services = mapAttrs (_: unit: unit.service) units;
+ };
}
diff --git a/sys/web/sites/home.nix b/sys/web/sites/home.nix
index 616bf94..fed9b84 100644
--- a/sys/web/sites/home.nix
+++ b/sys/web/sites/home.nix
@@ -1,9 +1,12 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.web.sites.home;
inherit (config.local) domains;
-in
-{
+in {
options.local.web.sites.home = {
enable = mkEnableOption "home site";
@@ -15,7 +18,7 @@ in
config = mkIf cfg.enable {
local.web = {
enable = mkDefault true;
- ownedCerts = [ "home" ];
+ ownedCerts = ["home"];
};
services.nginx.virtualHosts.${domains.home.main} = {
diff --git a/sys/web/sites/host.nix b/sys/web/sites/host.nix
index 32ef1a6..ea6cc23 100644
--- a/sys/web/sites/host.nix
+++ b/sys/web/sites/host.nix
@@ -1,4 +1,8 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.web.sites.host;
@@ -10,15 +14,15 @@ with lib; let
hostDomainName = "host-${hostname}";
userCerts = flatten (flatten (mapAttrsToList
- (name: user: map
+ (name: user:
+ map
(cert: {
fprint = config.local.pki.byPath.${cert}.fingerprint.sha1-lower;
inherit name;
})
user.mail.certs)
users));
-in
-{
+in {
options.local.web.sites.host = {
enable = mkEnableOption "host site, restricted to per-user client certs";
};
@@ -26,7 +30,7 @@ in
config = mkIf cfg.enable {
local.web = {
enable = mkDefault true;
- ownedCerts = [ hostDomainName ];
+ ownedCerts = [hostDomainName];
};
services = {
@@ -53,31 +57,36 @@ in
#}
'';
- locations = {
- "/".return = 403;
- } // concatMapAttrs
- (name: user:
- let
- userLocation = config: {
- extraConfig = ''
+ locations =
+ {
+ "/".return = 403;
+ }
+ // concatMapAttrs
+ (name: user: let
+ userLocation = config: {
+ extraConfig =
+ ''
if ($host_user_from_fprint != "${name}") {
return 403;
}
- '' + config;
- };
+ ''
+ + config;
+ };
- userLocations = {
+ userLocations =
+ {
"/${name}" = ''
return 404;
'';
- } // optionalAttrs user.mail.dav {
+ }
+ // optionalAttrs user.mail.dav {
"/${name}/dav" = ''
proxy_pass http://unix:/run/host-www/${name}/dav.sock;
'';
};
- in
+ in
mapAttrs (_: userLocation) userLocations)
- (filterAttrs (_: user: user.mail.certs != [ ]) users);
+ (filterAttrs (_: user: user.mail.certs != []) users);
};
};
};
@@ -85,13 +94,13 @@ in
systemd.tmpfiles.settings."10-run-host-www" =
concatMapAttrs
- (name: _: {
- "/run/host-www/${name}".d = {
- mode = "0750";
- user = name;
- group = "nginx";
- };
- })
- users;
+ (name: _: {
+ "/run/host-www/${name}".d = {
+ mode = "0750";
+ user = name;
+ group = "nginx";
+ };
+ })
+ users;
};
}
diff --git a/sys/web/sites/portal.nix b/sys/web/sites/portal.nix
index 2365ba1..fe96cfb 100644
--- a/sys/web/sites/portal.nix
+++ b/sys/web/sites/portal.nix
@@ -1,9 +1,12 @@
-{ config, lib, ... }:
+{
+ config,
+ lib,
+ ...
+}:
with lib; let
cfg = config.local.web.sites.portal;
inherit (config.local) domains;
-in
-{
+in {
options.local.web.sites.portal = {
enable = mkEnableOption "public non-fqdn portal";
};
@@ -11,7 +14,7 @@ in
config = mkIf cfg.enable {
local.web = {
enable = mkDefault true;
- ownedCerts = [ "host" "exdev" ];
+ ownedCerts = ["host" "exdev"];
defaultACMEHost = domains.host.main;
};
@@ -19,13 +22,13 @@ in
${domains.host.www} = {
forceSSL = true;
useACMEHost = domains.host.main;
- serverAliases = [ domains.host.main ];
+ serverAliases = [domains.host.main];
};
${domains.exdev.main} = {
forceSSL = true;
useACMEHost = domains.exdev.main;
- serverAliases = [ domains.exdev.www ];
+ serverAliases = [domains.exdev.www];
locations."/fsociety".return = "301 https://meet.posixlycorrect.com/%C6%92%C6%A8%C5%8F%C4%8B%D3%80%C9%99%CF%AE%D0%A3";
};