From 3ccc7e784a0ed5b19910ab856f6d9774a6f27956 Mon Sep 17 00:00:00 2001 From: Kleidi Bujari Date: Sat, 23 Nov 2024 16:36:43 -0500 Subject: Initial scaffolding and layout Set up the modules of the flake. At this time, the flake is split into modules and machines. Considering that additional top-level sections -- such as packages and shells -- will also be added, it might make sense to keep all nix related things in one top-level directory, alongside the flake.nix file. This is all under the assumption that later amendments to the project will introduce other tech, such as terraform. --- flake.lock | 91 ++++++++++++++++++++++++ flake.nix | 35 ++++++++++ machines/flake-module.nix | 29 ++++++++ machines/iridium/default.nix | 1 + machines/iso/default.nix | 32 +++++++++ machines/t1/default.nix | 1 + machines/t480/default.nix | 38 ++++++++++ modules/flake-module.nix | 6 ++ modules/xlib/default.nix | 1 + modules/xnet/default.nix | 32 +++++++++ modules/xnet/desktop/default.nix | 123 +++++++++++++++++++++++++++++++++ modules/xnet/disk/boot.nix | 13 ++++ modules/xnet/disk/default.nix | 113 ++++++++++++++++++++++++++++++ modules/xnet/disk/layouts/mirror.nix | 43 ++++++++++++ modules/xnet/disk/layouts/single.nix | 29 ++++++++ modules/xnet/monitoring/default.nix | 38 ++++++++++ modules/xnet/monitoring/grafana.nix | 51 ++++++++++++++ modules/xnet/monitoring/prometheus.nix | 15 ++++ modules/xnet/net/default.nix | 69 ++++++++++++++++++ modules/xnet/net/vpn-gateway.nix | 103 +++++++++++++++++++++++++++ modules/xnet/users/default.nix | 8 +++ modules/xnet/users/radicale.nix | 28 ++++++++ modules/xnet/users/secret.yaml | 31 +++++++++ 23 files changed, 930 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 machines/flake-module.nix create mode 100644 machines/iridium/default.nix create mode 100644 machines/iso/default.nix create mode 100644 machines/t1/default.nix create mode 100644 machines/t480/default.nix create mode 100644 modules/flake-module.nix create mode 100644 modules/xlib/default.nix create mode 100644 modules/xnet/default.nix create mode 100644 modules/xnet/desktop/default.nix create mode 100644 modules/xnet/disk/boot.nix create mode 100644 modules/xnet/disk/default.nix create mode 100644 modules/xnet/disk/layouts/mirror.nix create mode 100644 modules/xnet/disk/layouts/single.nix create mode 100644 modules/xnet/monitoring/default.nix create mode 100644 modules/xnet/monitoring/grafana.nix create mode 100644 modules/xnet/monitoring/prometheus.nix create mode 100644 modules/xnet/net/default.nix create mode 100644 modules/xnet/net/vpn-gateway.nix create mode 100644 modules/xnet/users/default.nix create mode 100644 modules/xnet/users/radicale.nix create mode 100644 modules/xnet/users/secret.yaml diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..38f1513 --- /dev/null +++ b/flake.lock @@ -0,0 +1,91 @@ +{ + "nodes": { + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1715070411, + "narHash": "sha256-5CNvkH0Nf7yMwgKhjUNg/lUK40C7DXB4zKOuA2jVO90=", + "owner": "nix-community", + "repo": "disko", + "rev": "4677f6c53482a8b01ee93957e3bdd569d51261d6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "v1.6.1", + "repo": "disko", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1730504689, + "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "506278e768c2a08bec68eb62932193e341f55c90", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1731755305, + "narHash": "sha256-v5P3dk5JdiT+4x69ZaB18B8+Rcu3TIOrcdG4uEX7WZ8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "057f63b6dc1a2c67301286152eb5af20747a9cb4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "disko": "disko", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1732186149, + "narHash": "sha256-N9JGWe/T8BC0Tss2Cv30plvZUYoiRmykP7ZdY2on2b0=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "53c853fb1a7e4f25f68805ee25c83d5de18dc699", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..103de63 --- /dev/null +++ b/flake.nix @@ -0,0 +1,35 @@ +{ + description = "Personal monorepo"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; + + flake-parts.url = "github:hercules-ci/flake-parts"; + flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; + + disko.url = "github:nix-community/disko/v1.6.1"; + disko.inputs.nixpkgs.follows = "nixpkgs"; + + sops-nix.url = "github:Mic92/sops-nix"; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { flake-parts, ... } @ inputs: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ "x86_64-linux" "aarch64-linux" ]; + + imports = [ + ./machines/flake-module.nix + ./modules/flake-module.nix + ]; + + perSystem = { pkgs, inputs', ... }: { + formatter = pkgs.nixpkgs-fmt; + + apps.install = { + type = "app"; + program = inputs'.disko.packages.disko-install; + }; + }; + }; +} diff --git a/machines/flake-module.nix b/machines/flake-module.nix new file mode 100644 index 0000000..d06bfc2 --- /dev/null +++ b/machines/flake-module.nix @@ -0,0 +1,29 @@ +{ lib, self, ... }: +let + inherit (lib) nixosSystem; + inherit (self.nixosModules) xnet xlib; +in +{ + flake.nixosConfigurations = { + t480 = nixosSystem { + system = "x86_64-linux"; + specialArgs = { inherit xlib; }; + modules = [ ./t480 xnet ]; + }; + + iso = nixosSystem { + system = "x86_64-linux"; + modules = [ ./iso ]; + }; + + # t1 = nixosSystem { + # system = "x86_64-linux"; + # modules = [ ./t1 ]; + # }; + # + # iridium = nixosSystem { + # system = "x86_64-linux"; + # modules = [ ./iridium ]; + # }; + }; +} diff --git a/machines/iridium/default.nix b/machines/iridium/default.nix new file mode 100644 index 0000000..c915eb0 --- /dev/null +++ b/machines/iridium/default.nix @@ -0,0 +1 @@ +{ ... }: { } diff --git a/machines/iso/default.nix b/machines/iso/default.nix new file mode 100644 index 0000000..d7d5861 --- /dev/null +++ b/machines/iso/default.nix @@ -0,0 +1,32 @@ +{ modulesPath, pkgs, ... }: { + imports = [ + (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") + (modulesPath + "/installer/cd-dvd/channel.nix") + ]; + + nix.settings = { + experimental-features = [ "nix-command" "flakes" ]; + }; + + environment.systemPackages = with pkgs; [ + bash + git + gum + jq + (writeShellScriptBin "xinstall" '' + set -euo pipefail + + FLAKE="github:kbujari/depot/scaffolding" + + TARGET=$( + nix flake show "$FLAKE" --json 2>/dev/null \ + | jq -r '.["nixosConfigurations"] | keys[] | select(. != "iso")' \ + | gum choose + ) + + gum confirm --default=false "This will erase the selected disk, confirm:" + + echo selected "$FLAKE"#"$TARGET" + '') + ]; +} diff --git a/machines/t1/default.nix b/machines/t1/default.nix new file mode 100644 index 0000000..c915eb0 --- /dev/null +++ b/machines/t1/default.nix @@ -0,0 +1 @@ +{ ... }: { } diff --git a/machines/t480/default.nix b/machines/t480/default.nix new file mode 100644 index 0000000..d17899e --- /dev/null +++ b/machines/t480/default.nix @@ -0,0 +1,38 @@ +{ ... }: { + system.stateVersion = "24.05"; + + xnet = { + desktop.enable = true; + disk = { + enable = true; + device = "nvme0n1"; + extraDatasets = { + "persist/usr" = { + type = "zfs_fs"; + mountpoint = "/home/k6"; + options.mountpoint = "legacy"; + }; + }; + }; + }; + + networking = { + hostName = "t480"; + useDHCP = false; + dhcpcd.enable = false; + nameservers = [ "9.9.9.9" ]; + networkmanager = { + enable = true; + dns = "none"; + wifi = { + powersave = true; + backend = "iwd"; + }; + }; + }; + + systemd.tmpfiles.rules = [ + "d /persist/data/NetworkManager 0750 - - -" + "L+ /var/lib/NetworkManager - - - - /persist/data/NetworkManager" + ]; +} diff --git a/modules/flake-module.nix b/modules/flake-module.nix new file mode 100644 index 0000000..40ec4b4 --- /dev/null +++ b/modules/flake-module.nix @@ -0,0 +1,6 @@ +{ inputs, ... }: { + flake.nixosModules = { + xnet.imports = [ ./xnet inputs.disko.nixosModules.disko ]; + xlib.imports = [ ./xlib ]; + }; +} diff --git a/modules/xlib/default.nix b/modules/xlib/default.nix new file mode 100644 index 0000000..c915eb0 --- /dev/null +++ b/modules/xlib/default.nix @@ -0,0 +1 @@ +{ ... }: { } diff --git a/modules/xnet/default.nix b/modules/xnet/default.nix new file mode 100644 index 0000000..87d17e7 --- /dev/null +++ b/modules/xnet/default.nix @@ -0,0 +1,32 @@ +{ lib, ... }: +let + inherit (lib) mkDefault; +in +{ + imports = [ + ./disk + ./net + ./desktop + # ./monitoring + # ./users + ]; + + i18n.defaultLocale = mkDefault "en_US.UTF-8"; + time.timeZone = mkDefault "America/Toronto"; + + nix.settings = { + auto-optimise-store = true; + experimental-features = [ "nix-command" "flakes" ]; + warn-dirty = false; + }; + + nix.gc = { + automatic = true; + options = mkDefault "--delete-older-than 30d"; + }; + + documentation = { + doc.enable = mkDefault false; + info.enable = mkDefault false; + }; +} diff --git a/modules/xnet/desktop/default.nix b/modules/xnet/desktop/default.nix new file mode 100644 index 0000000..f919798 --- /dev/null +++ b/modules/xnet/desktop/default.nix @@ -0,0 +1,123 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.xnet.desktop; + inherit (lib) mkDefault mkOption mkIf types; +in +{ + options.xnet.desktop = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable graphical desktop."; + }; + }; + + config = mkIf cfg.enable { + security.rtkit.enable = true; + services.pipewire = { + enable = true; + pulse.enable = true; + alsa = { + enable = true; + support32Bit = true; + }; + }; + + programs.sway = { + enable = true; + wrapperFeatures = { + gtk = true; + base = true; + }; + extraPackages = with pkgs; [ + foot + fuzzel + grim + mako + pwvucontrol + playerctl + pop-icon-theme + pwvucontrol + slurp + sway-contrib.grimshot + swayidle + swaylock + waybar + wl-clipboard + ]; + extraSessionCommands = '' + export MOZ_ENABLE_WAYLAND=1 + export MOZ_USE_XINPUT2=1 + export MOZ_WEBRENDER=1 + export XDG_CURRENT_DESKTOP=sway + export XDG_SESSION_TYPE=wayland + ''; + }; + + programs.light.enable = mkDefault true; + + qt = { + enable = true; + style = "adwaita-dark"; + platformTheme = "gnome"; + }; + + fonts.packages = with pkgs; [ + departure-mono + noto-fonts + noto-fonts-cjk-sans + noto-fonts-emoji + (nerdfonts.override { fonts = [ "NerdFontsSymbolsOnly" ]; }) + ]; + + xdg.portal = { + enable = true; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + xdg-desktop-portal-gtk + ]; + }; + + programs.firefox = { + enable = true; + policies = { + DisableTelemetry = true; + DisableFirefoxStudies = true; + EnableTrackingProtection = { + Value = true; + Locked = true; + Cryptomining = true; + Fingerprinting = true; + }; + DisablePocket = true; + DisableFirefoxAccounts = true; + DisableAccounts = true; + DisableFirefoxScreenshots = true; + OverrideFirstRunPage = ""; + OverridePostUpdatePage = ""; + DontCheckDefaultBrowser = true; + DisplayBookmarksToolbar = "never"; + DisplayMenuBar = "default-off"; + SearchBar = "unified"; + ExtensionSettings = { + "*".installation_mode = "blocked"; # blocks all addons except the ones specified below + # uBlock Origin: + "uBlock0@raymondhill.net" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; + installation_mode = "force_installed"; + }; + # Bitwarden: + "{446900e4-71c2-419f-a6a7-df9c091e268b}" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi"; + installation_mode = "force_installed"; + }; + # Dark Reader: + "addon@darkreader.org" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi"; + installation_mode = "force_installed"; + }; + }; + }; + }; + }; +} diff --git a/modules/xnet/disk/boot.nix b/modules/xnet/disk/boot.nix new file mode 100644 index 0000000..65be2f3 --- /dev/null +++ b/modules/xnet/disk/boot.nix @@ -0,0 +1,13 @@ +{ lib, ... }: +let + inherit (lib) mkDefault; +in +{ + boot = { + loader.systemd-boot.enable = true; + initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; + kernelModules = [ "kvm-intel" "kvm-amd" ]; + swraid.mdadmConf = "MAILADDR = nobody@example.com"; + tmp.cleanOnBoot = mkDefault true; + }; +} diff --git a/modules/xnet/disk/default.nix b/modules/xnet/disk/default.nix new file mode 100644 index 0000000..aca6ae2 --- /dev/null +++ b/modules/xnet/disk/default.nix @@ -0,0 +1,113 @@ +{ config, lib, modulesPath, ... }: +let + cfg = config.xnet.disk; + commonOpts = { + acltype = "posixacl"; + atime = "off"; + compression = "on"; + normalization = "formD"; + relatime = "off"; + xattr = "sa"; + "com.sun:auto-snapshot" = "false"; + }; + + inherit (lib) mkOption mkDefault mkIf types; +in +{ + imports = [ + ./boot.nix + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + options.xnet.disk = { + enable = mkOption { + type = types.bool; + default = false; + description = "Apply xnet-standard ZFS disk layout."; + }; + + device = mkOption { + type = types.str; + description = "Underlying device that build the root ZFS pool."; + }; + + extraDatasets = mkOption { }; + }; + + config = mkIf cfg.enable { + networking.hostId = builtins.substring 0 8 + (builtins.hashString "md5" config.networking.hostName); + + services.zfs = { + autoScrub.enable = true; + trim.enable = true; + }; + + zramSwap.enable = mkDefault true; + + boot = { + kernelParams = [ "nohibernate" "elevator=none" ]; + supportedFilesystems = [ "vfat" "zfs" ]; + zfs.devNodes = "/dev/disk/by-partuuid"; + }; + + disko.devices = (import ./layouts/single.nix cfg.device) // { + nodev."/" = { + fsType = "tmpfs"; + mountOptions = [ "defaults" "size=2G" "mode=755" ]; + }; + + zpool.zroot = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + + datasets = { + "local" = { + type = "zfs_fs"; + options = commonOpts; + }; + + "local/reserved" = { + type = "zfs_fs"; + options = { + refreservation = "10G"; + mountpoint = "none"; + }; + }; + + "local/nix" = { + type = "zfs_fs"; + mountpoint = "/nix"; + options.mountpoint = "legacy"; + }; + + "local/certs" = { + type = "zfs_fs"; + mountpoint = "/certs"; + options.mountpoint = "legacy"; + }; + + "persist" = { + type = "zfs_fs"; + mountpoint = "/persist"; + options = { mountpoint = "legacy"; } // commonOpts; + }; + + "persist/data" = { + type = "zfs_fs"; + mountpoint = "/persist/data"; + options.mountpoint = "legacy"; + }; + } // cfg.extraDatasets; + }; + }; + + users.groups.backup = { + members = [ config.services.syncoid.group ]; + gid = 2001; + }; + }; +} diff --git a/modules/xnet/disk/layouts/mirror.nix b/modules/xnet/disk/layouts/mirror.nix new file mode 100644 index 0000000..5a9835b --- /dev/null +++ b/modules/xnet/disk/layouts/mirror.nix @@ -0,0 +1,43 @@ +devices: { + disk = builtins.listToAttrs (map + (device: { + name = device; + value = { + type = "disk"; + device = "/dev/${device}"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "1G"; + type = "EF00"; + content = { + type = "mdraid"; + name = "boot"; + }; + }; + ZFS = { + size = "100%"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; + }; + }; + }) + devices); + mdadm = { + boot = { + type = "mdadm"; + level = 1; + metadata = "1.0"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + }; +} diff --git a/modules/xnet/disk/layouts/single.nix b/modules/xnet/disk/layouts/single.nix new file mode 100644 index 0000000..b779a39 --- /dev/null +++ b/modules/xnet/disk/layouts/single.nix @@ -0,0 +1,29 @@ +device: { + disk = { + "${device}" = { + type = "disk"; + device = "/dev/${device}"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + ZFS = { + size = "100%"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/xnet/monitoring/default.nix b/modules/xnet/monitoring/default.nix new file mode 100644 index 0000000..87ae724 --- /dev/null +++ b/modules/xnet/monitoring/default.nix @@ -0,0 +1,38 @@ +{ config, ... }: +let + inherit (config.networking) hostName; + inherit (config.services.prometheus) exporters; +in +{ + imports = [ ./grafana.nix ./prometheus.nix ]; + + exporters = { + node = { + enable = true; + enabledCollectors = [ "processes" "systemd" ]; + }; + + systemd = { + enable = true; + extraFlags = [ + "--systemd.collector.enable-ip-accounting" + "--systemd.collector.enable-restart-count" + ]; + }; + }; + + services.prometheus.scrapeConfigs = [ + { + job_name = "node"; + static_configs = [{ + targets = [ "${hostName}:${toString exporters.node.port}" ]; + }]; + } + { + job_name = "systemd"; + static_configs = [{ + targets = [ "${hostName}:${toString exporters.systemd.port}" ]; + }]; + } + ]; +} diff --git a/modules/xnet/monitoring/grafana.nix b/modules/xnet/monitoring/grafana.nix new file mode 100644 index 0000000..6a37ce1 --- /dev/null +++ b/modules/xnet/monitoring/grafana.nix @@ -0,0 +1,51 @@ +{ config, pkgs, ... }: { + services.grafana.provision = { + enable = true; + datasources.settings.datasources = [{ + name = "Prometheus"; + type = "prometheus"; + url = "http://localhost:9090"; + access = "proxy"; + editable = false; + }]; + + dashboards.settings.providers = [{ + name = "Fetched Dashboards"; + options.path = "/etc/grafana/dashboards"; + }]; + }; + + environment.etc = { + "grafana/dashboards/node-exporter.json" = { + user = "grafana"; + group = "grafana"; + source = pkgs.fetchurl { + url = "https://grafana.com/api/dashboards/1860/revisions/37/download"; + hash = "sha256-1DE1aaanRHHeCOMWDGdOS1wBXxOF84UXAjJzT5Ek6mM="; + }; + }; + }; + + services.grafana = { + enable = true; + settings.server = { + domain = "grafana.web.4kb.net"; + protocol = "socket"; + }; + settings."auth.anonymous" = { + enabled = true; + org_role = "Admin"; + }; + }; + + users.groups.grafana.members = [ "nginx" ]; + systemd.services.nginx.serviceConfig.ProtectHome = false; + + services.nginx.virtualHosts."${config.services.grafana.settings.server.domain}" = { + useACMEHost = "4kb.net"; + addSSL = true; + locations."/" = { + proxyPass = "http://unix:/${toString config.services.grafana.settings.server.socket}"; + }; + }; +} diff --git a/modules/xnet/monitoring/prometheus.nix b/modules/xnet/monitoring/prometheus.nix new file mode 100644 index 0000000..e32e078 --- /dev/null +++ b/modules/xnet/monitoring/prometheus.nix @@ -0,0 +1,15 @@ +{ config, ... }: { + services.prometheus = { + enable = true; + globalConfig.scrape_interval = "1m"; + # scrapeConfigs = [{ + # job_name = "node"; + # relabel_configs = [{ + # source_labels = [ "__address__" ]; + # regex = "(.*):[0-9]+"; + # target_label = "instance"; + # replacement = "$1"; + # }]; + # }]; + }; +} diff --git a/modules/xnet/net/default.nix b/modules/xnet/net/default.nix new file mode 100644 index 0000000..143f189 --- /dev/null +++ b/modules/xnet/net/default.nix @@ -0,0 +1,69 @@ +{ config, lib, ... }: +let + cfg = config.xnet.net; + inherit (lib) mkOption mkIf types; + prefix = "10.26.4"; +in +{ + options.xnet.net = { + interface = mkOption { + type = types.str; + default = ""; + description = "Network interface connecting to xnet."; + }; + + addr = mkOption { + type = types.ints.between 0 255; + description = "Final octet for xnet address."; + example = 4; + }; + + sshd = mkOption { + type = types.bool; + default = false; + description = "Enable hardened SSH service."; + }; + }; + + # TODO: + # - Add assertion that each address is only used once across config + # - Add each host to each other hosts dns configuration + config = mkIf (builtins.stringLength cfg.interface > 0) { + networking.vlans = { + "${cfg.interface}.4" = { + inherit (cfg) interface; + id = 4; + }; + }; + + networking.interfaces = { + "${cfg.interface}.4".ipv4.addresses = [{ + address = "${prefix}.${toString cfg.addr}"; + prefixLength = 24; + }]; + }; + + services.openssh = { + enable = cfg.sshd; + startWhenNeeded = true; + settings = { + X11Forwarding = false; + UsePAM = false; + PermitRootLogin = "prohibit-password"; + }; + extraConfig = + let + p = [ + "sk-ssh-ed25519-cert-v01@openssh.com" + "ssh-ed25519-cert-v01@openssh.com" + "ssh-ed25519" + ]; + in + "PubkeyAcceptedKeyTypes ${lib.strings.concatStringsSep "," p}"; + hostKeys = [{ + path = "/certs/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + }]; + }; + }; +} diff --git a/modules/xnet/net/vpn-gateway.nix b/modules/xnet/net/vpn-gateway.nix new file mode 100644 index 0000000..d26ced1 --- /dev/null +++ b/modules/xnet/net/vpn-gateway.nix @@ -0,0 +1,103 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.xnet.net.vpnGateway; + inherit (lib) mkOption mkIf types; + + iface = "enp2s0"; + fwmark = "0x1"; + ip = "192.168.2.113"; + vpn = { + iface = "wg0"; + endpoint = "149.88.22.129:51820"; + addr = "10.69.70.71/32"; + peers = [ + + ]; + }; +in + +{ + # options.xnet.net.vpnGateway = { + # interface = mkOption { + # type = types.str; + # description = "Interface to forward VPN routed packets to internet"; + # }; + # + # vpn = types.subModule { + # interface = mkOption { + # type = types.str; + # default = "wg0"; + # description = "Name of VPN interface."; + # }; + # + # endpoint = mkOption { + # type = types.str; + # description = "ip:port of the VPN endpoint."; + # }; + # + # addr = mkOption { + # type = types.str; + # description = "Address of the VPN interface."; + # }; + # + # privateKeyFile = mkOption { + # type = types.str; + # description = "Path to private key."; + # }; + # + # peers = types.listOf types.subModule { + # + # }; + # }; + + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + "net.ipv6.conf.all.forwarding" = 1; + }; + + networking = { + wg-quick.interfaces."${vpn.iface}" = { + address = [ vpn.addr ]; + privateKeyFile = "/certs/wg/private.key"; + + peers = [{ + publicKey = "yxyntWsANEwxeR0pOPNAcfWY7zEVICZe9G+GxortzEY="; + allowedIPs = [ "0.0.0.0/0" ]; + endpoint = "149.88.22.129:51820"; + persistentKeepalive = 25; + }]; + }; + + nat = { + enable = true; + externalInterface = "wg0"; + internalInterfaces = [ "enp2s0" ]; + }; + + firewall = { + extraCommands = '' + # Create a new routing table for forwarded traffic + echo "200 vpn" >> /etc/iproute2/rt_tables + + # Mark packets from other hosts + iptables -t mangle -A PREROUTING -i enp2s0 ! -s 192.168.1.113 -j MARK --set-mark 0x1 + + # Route marked packets through WireGuard + ip rule add fwmark 0x1 table vpn + ip route add default dev wg0 table vpn + + # Allow forwarding + iptables -A FORWARD -i enp2s0 -o wg0 -j ACCEPT + iptables -A FORWARD -i wg0 -o enp2s0 -m state --state RELATED,ESTABLISHED -j ACCEPT + + # NAT only forwarded traffic + iptables -t nat -A POSTROUTING -o wg0 ! -s 192.168.1.113 -j MASQUERADE + ''; + + extraStopCommands = '' + ip rule del fwmark 0x1 table vpn 2>/dev/null || true + ip route flush table vpn 2>/dev/null || true + ''; + }; + }; +} diff --git a/modules/xnet/users/default.nix b/modules/xnet/users/default.nix new file mode 100644 index 0000000..c567c23 --- /dev/null +++ b/modules/xnet/users/default.nix @@ -0,0 +1,8 @@ +{ ... }: { + imports = [ ./radicale.nix ]; + + security.sudo = { + execWheelOnly = true; + extraConfig = "Defaults lecture = never"; + }; +} diff --git a/modules/xnet/users/radicale.nix b/modules/xnet/users/radicale.nix new file mode 100644 index 0000000..7d752f0 --- /dev/null +++ b/modules/xnet/users/radicale.nix @@ -0,0 +1,28 @@ +{ config, ... }: +let path = "/persist/data/radicale"; in { + services.radicale = { + enable = false; + settings = { + server.hosts = [ "127.0.0.1:5232" ]; + storage.filesystem_folder = "${path}/collections"; + auth = { + type = "htpasswd"; + htpasswd_filename = "${path}/users"; + htpasswd_encryption = "plain"; + }; + }; + }; + + systemd.tmpfiles.rules = [ + "d ${path} 0700 radicale radicale -" + "Z ${path} 0700 radicale radicale - -" + ]; + + services.nginx.virtualHosts."dav.web.4kb.net" = { + useACMEHost = "4kb.net"; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:5232/"; + }; + }; +} diff --git a/modules/xnet/users/secret.yaml b/modules/xnet/users/secret.yaml new file mode 100644 index 0000000..0381dea --- /dev/null +++ b/modules/xnet/users/secret.yaml @@ -0,0 +1,31 @@ +root: ENC[AES256_GCM,data:N0CdjX9uY9IeLX95SSzQYsV/6IVfs0r1rX0JTCbb6WD7/oID0/y9CwErPKhCP03x7aKS4mqwgU6dVECAqsEIs35AS/O84FELTw==,iv:8+jKwsBfUfiEkclW2moLtzwB6MDouNq7N4U24f18kiQ=,tag:Ekw+vOXyhMgw5oPRTzV/Qg==,type:str] +kleidi: ENC[AES256_GCM,data:r0C5/fuY/RwNv9FFCrDMr4UnDK4cA1vFcDPlGTHSKYExzd+T6zrw5Zl/YO98uB3WC4mEtIgfZQxGwMgYyCVU2piJeW40/wftLA==,iv:hRa2eUx7tgyoV/hh6H+e5QCrTtQc/rOYIYefs32yzNg=,tag:Z/m+f+SvOHGleLtWU49nsA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age15f6mcwjjav4z757kad8wksalgemael364wwxz7qsral5gmjzmd2qre78d5 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaRE85OWRmR1VtcWg0cnBz + SW9JRDJpN1RwRER5alAwUDBNM2ZrQ0Jna2tJClEweStEdmsyTnZNcXBsN3RIRXln + eUxUcUZwYU9CMDBjejlQRG0rdVRCUG8KLS0tIGt6MS9kN05MY0xhbWY5cjBBMlBG + dmpXeloxTDNydGRtd0ZFUVhKOWlMT1kKNj6BpUhgq6/AAHvFfNaEeHPsB2eRMzjS + lH7Vxn0mj00LdilatnWMajr8u3FWq+XYc2kPIo/XM8AmM/u17rMoag== + -----END AGE ENCRYPTED FILE----- + - recipient: age1nw5yklj57fegqllhqfjuy9f89cx9f9p0xptw9uv58rzleh8fdyssv0zyp4 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTWXBuWGZ3NzI4ZHJOZllm + UVJYYnB5RklPTkh3ODdhY3hXUnFnWnBEaTNvClQ4RXpkWDI0ZUF2NHdvT2lOZDUv + dmgvSWtXU3p0WjhWeHV3L0VjRGdweE0KLS0tIE1kSm4xajd6MVNsNUlsSHhlbXUz + c2NGY3luQ2prUFNLKytEVFlFdDhtWEUKl3tUxQIpJA9RJLs2Fvb7s4Cn21CEC3r6 + XZ1BXjXKxHoEPyTARvxDqJXJxSvaH76283rhSG1vcQzmGUm56LZcLw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-10-31T01:49:17Z" + mac: ENC[AES256_GCM,data:ye2kvRJCGn/h1QviQ+Zrhykau7gCSe78QWEd2QgvfIPMgcDh3COdhavsd9zDRmDMNJBAiDTWQkrgTtYDzx859TsxfJdEDp6X7xRWhI/2dU94aRVGQGxdKTRiswJR+RzHmO0Cf4tNqYYjIySym4v39yWKioQlV4Vm9BW2eUTYLNo=,iv:gSvqxLggrf085IY+u/VeNkYAho/gMC5U2xkqgfSpeTc=,tag:gRTfIoFqta+7udwANTqO2A==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.1 -- cgit v1.3.1