From dac2e0b8cfcc5fa2c3cf135501b7524a715b4a6a Mon Sep 17 00:00:00 2001 From: Christine Elisabeth Koppel Date: Thu, 12 Feb 2026 13:20:16 +0100 Subject: [PATCH] Create preliminary documentation for age key generation and implement wireguard setup. --- .sops.yaml | 10 ++ .../modules/secrets-config/notes.md | 6 ++ .../modules/system/wireguard_server.nix | 101 ++++++++++++++++++ .../modules/toolsets/wireguard_peer.nix | 43 ++++++++ .../secrets/wireguard/secrets.yaml | 18 ++++ 5 files changed, 178 insertions(+) create mode 100644 nix-system-configs/modules/secrets-config/notes.md create mode 100644 nix-system-configs/modules/system/wireguard_server.nix create mode 100644 nix-system-configs/modules/toolsets/wireguard_peer.nix create mode 100644 nix-system-configs/secrets/wireguard/secrets.yaml diff --git a/.sops.yaml b/.sops.yaml index 7733a9d..df91613 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -3,6 +3,7 @@ keys: - &server_songsheet age1la8yjuc2ws9pyx70rc83jd2084v5e08v8fvh6muvfzrl2ulp8fms6frs86 - &server_traefik age1rdcs8y4fjfyagwt2q9599ax329thceersh6dg2f0p6nsghm5xufq00qu0p - &server_database age1k9ddvzypz986a7dt403ja6evql2agz0gehll79mx64zceteya38smxph8m + - &server_christine age1kzsrlz86y5nqe4vaufv8chupq2hrf3avlmxsp3d5p9t5xj593deszslkmp creation_rules: - path_regex: nix-system-configs/secrets/songsheet/[^/]+\.(yaml|json|env|ini)$ key_groups: @@ -19,3 +20,12 @@ creation_rules: - age: - *admin_christine - *server_database + - path_regex: nix-system-configs/secrets/christine/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: + - *server_christine + - *admin_christine + - path_regex: nix-system-configs/secrets/wireguard/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - age: + - *admin_christine \ No newline at end of file diff --git a/nix-system-configs/modules/secrets-config/notes.md b/nix-system-configs/modules/secrets-config/notes.md new file mode 100644 index 0000000..a0c2863 --- /dev/null +++ b/nix-system-configs/modules/secrets-config/notes.md @@ -0,0 +1,6 @@ +To generate the keys beforehand +```ssh +nix-shell -p age +/var/lib/sops-nix/key.txt +``` +And then update the .sops.yaml in the project directory accordingly. \ No newline at end of file diff --git a/nix-system-configs/modules/system/wireguard_server.nix b/nix-system-configs/modules/system/wireguard_server.nix new file mode 100644 index 0000000..71be160 --- /dev/null +++ b/nix-system-configs/modules/system/wireguard_server.nix @@ -0,0 +1,101 @@ +{ + config, + pkgs, + lib, + ... +}: { + options.local = { + hostname = lib.mkOption { + type = lib.types.str; + default = "nixos-default"; + description = "System hostname"; + }; + username = lib.mkOption { + type = lib.types.str; + default = "user"; + description = "Primary user username"; + }; + userDescription = lib.mkOption { + type = lib.types.str; + default = "NixOS User"; + description = "Primary user description"; + }; + address = lib.mkOption { + type = lib.types.str; + default = "10.1.1.100"; + description = "Static IP address"; + }; + }; + + imports = [ + ./modules/desktop-manager/sway_greetd_homemanager.nix + ./modules/local/hostname_username.nix + ./modules/local/networking_local.nix + ./modules/bootloader/seabios-assigned-iso-at-birth.nix + ./modules/lix-default.nix + # Optionally to enable remote building: ./modules/toolsets/remote_building.nix + #./modules/songsheet/wavelog/docker-compose.nix + #./modules/secrets-config/sops-the-blank-system.nix + ]; + + config = { + # https://wiki.archlinux.org/title/WireGuard + # https://wiki.nixos.org/wiki/WireGuard + local.hostname = "nixos-local-wireguard-server"; + local.username = "wireguardprg_local"; + local.userDescription = "NixOS PRG OpenVPN Service (Local)"; + local.address = "10.1.1.6"; + system.stateVersion = "25.11"; + + # enable NAT + networking.nat = { + enable = true; + enableIPv6 = true; + externalInterface = "ens18"; + internalInterfaces = ["wg0"]; + }; + + networking.wireguard.interfaces = { + wg0 = { + listenPort = 51820; + + # This allows the wireguard server to route your traffic to the internet and hence be like a VPN + # Note: You ***really should*** to use IPv6 addresses, to ensure that there is no long term risk of *local* IPv4 address exhaustion. + # How IPv6 works - Basically imagine IPv4 with hexadecimal, but without forcing you to learn it, the handrule + # for local assignments is to start with fc00::, where appending "1" after the infix `::` as suffix gives you a proper address, + # "fc00::1" (imagine this as 10.0.0.1 in IPv4 thought, where technically it is "252.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1" + # in IPv6 dotted hexadecimal notation). + # Then you can add additional infix before the suffix to go more inside of the address prefix space, for example "fc00::1:1" + # becomes in IPv4 thinking as 10.0.1.1 (in IPv6 " 252.0.0.0.0.0.0.0.0.0.0.0.0.1.0.255"). + # As you might have noticed, that each semicolon is assigned into 16 bits, thus you can assign each subnet address from + # in IPv4 like-thinking from .1 to .65536, thus in hexadecimal from ::1 to ::ffff. + # Prefixes are read 1:1 from IPv4 thinking, but you have 1 to 128 length range, instead of 1 to 31. + + # IPv6 IP assignments, let us use the following IPv6 network range pre-set "fc00:5182::" aka. "252.0.81.130.0.0.0.0.0.0.0.0.0.0.0.0" + # Why? Because we just be just in case and consistent with documenting to everyone. + # Why 5182(0)? WireGuard server is running on port 51820, + # thus we can use the "5182" infix in the IPv6 prefix to make it more memorable and less likely to cause confusion + # with other local network services in the future. + postUp = '' + ${pkgs.iptables}/bin/ip6tables -A FORWARD -i wg0 -j ACCEPT + ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fc00:5182::1:1/112 -o eth0 -j MASQUERADE + ''; + + # Undo the above + preDown = '' + ${pkgs.iptables}/bin/ip6tables -D FORWARD -i wg0 -j ACCEPT + ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fc00:5182::1:1/112 -o eth0 -j MASQUERADE + ''; + + privateKeyFile = config.sops.secrets.wireguard_private.path; + }; + }; + + networking.firewall.allowedTCPPorts = [ + 51820 + ]; + networking.firewall.allowedUDPPorts = [ + 51820 + ]; + }; +} diff --git a/nix-system-configs/modules/toolsets/wireguard_peer.nix b/nix-system-configs/modules/toolsets/wireguard_peer.nix new file mode 100644 index 0000000..ab8b29b --- /dev/null +++ b/nix-system-configs/modules/toolsets/wireguard_peer.nix @@ -0,0 +1,43 @@ +{ + config, + pkgs, + lib, + ... +}: { + networking.firewall.allowedUDPPorts = [51820]; + + networking.wireguard = { + enable = true; + interfaces = { + # network interface name. + # You can name the interface arbitrarily. + wg0 = { + # the IP address and subnet of this peer + #ips = ["fc00:5182::1:2/112"]; + ips = [config.local.wireguard-peer-ip]; + + # WireGuard Port + # Must be accessible by peers + listenPort = config.local.wireguard-peer-port or 51820; + + peers = [ + { + ## NOTE! CHECK THE .sops.yaml and RUN SOPS `sops updatekeys`! + name = config.local.wireguard-peer-name or "default-wireguard-peer"; + publicKey = config.sops.secrets.wireguard_public; + preSharedKey = config.sops.secrets.wireguard_preshared; + allowedIPs = [ + "::/0" # Route all IPv6 traffic through the VPN, TODO: Dynamic Function to choose between different options + ]; + endpoint = "wireguard.prg-radio.org:51820"; + # ToDo: route to endpoint not automatically configured + # https://wiki.archlinux.org/index.php/WireGuard#Loop_routing + # https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577 + # Send keepalives every 25 seconds. Important to keep NAT tables alive. + persistentKeepalive = 60; + } + ]; + }; + }; + }; +} diff --git a/nix-system-configs/secrets/wireguard/secrets.yaml b/nix-system-configs/secrets/wireguard/secrets.yaml new file mode 100644 index 0000000..dfe5761 --- /dev/null +++ b/nix-system-configs/secrets/wireguard/secrets.yaml @@ -0,0 +1,18 @@ +wireguard_private: ENC[AES256_GCM,data:zQX9es61aCtDjXSudGmbCk3b6jwJ1u6/vHdIxbidM3AWQkiNYwUzrZ8kw4E=,iv:nk2q61HZP6qbfEg9YlciPUmr67PcQ28VXAQitSjesMg=,tag:CMPSd9QuGg4NOUeqDop5rQ==,type:str] +wireguard_public: ENC[AES256_GCM,data:qIN4WSJr+FKAfiT9ahx/HaY0ry3nJTPfn34wXpUjBb0sxvTayArY6QZdsrc=,iv:R0IZ/ZLPJ4Z9I7/SOo/c1BUpxGER3ftjnSjuV26QMws=,tag:sTqTOiTCQP1xUUfxHThGsA==,type:str] +wireguard_preshared: ENC[AES256_GCM,data:VSOzSwT1YMMC2CyM03Wh1x0tRRzaTxb/pEMBcmKeTHuD6QS+avjW6nnWDac=,iv:I21ybpLurR22LTrKLYNJLuVZVU1TiCZ+HIapcXpYR8Y=,tag:N9uMvAMVk/+6iV4tFYIp8A==,type:str] +sops: + age: + - recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5RXBhRjlYYWtEUk1PYldC + NEVqaXZvSFRCb09jWiswTkJ6UUFMeTBPUGtZClU4QXZXOStUMUkxcGtsQVdWcmNw + WFVpbW83c3hMNFZxaTNnS1dURDZuNjAKLS0tIC9vTGo5bS9Xejh0ZGMxZm1JV3Qx + TjBMR1c0MFR6MkxRR0xVenhxOFBiZW8KsbATDqbORxGfJLgLvqpozCt4PgKN48qb + /4TVQK20DH0GJz7zqZ6NjcmcOT7sVeoJyAjXMITw3TKA+YJGlxabFw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-12T12:06:08Z" + mac: ENC[AES256_GCM,data:O3eVe437LrbfaxEJaNkuS85AK19MAavHho0FNiFnDxQD5c7y7JMuhWeGCPpzT1P0/e/QwLTQmNzVogm/+KWOA/cjK/2vOn2L2+VdIkEWSu2mTxy7Uwx65mDWFjn1iVqKzpKKUD+73Z3b3WBTFI4fshXGh2V3tDQR5DRR3r8O/A0=,iv:JKgGCPWVJpS0W6qLz2pU5U2EIlePXgVn0sL/0E5TX0w=,tag:jTlbUL3ylSNlWse2djjGRA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0