1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-11 07:10:39 +02:00

feat: remove the need to specify cidrs in wireguard addresses and

properly derive allowed ips
This commit is contained in:
oddlama 2023-05-20 18:24:30 +02:00
parent 4057ee9051
commit 3862bd6b14
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
4 changed files with 59 additions and 53 deletions

View file

@ -23,7 +23,7 @@ This is my personal nix config.
- `envoy/` - Hetzner Cloud server. Primarily used as my mailserver and VPN provider. - `envoy/` - Hetzner Cloud server. Primarily used as my mailserver and VPN provider.
- `zackbiene/` - ODROID N2+. Hosts IoT and Home Automation stuff and fully isolates that stuff from my internal network. - `zackbiene/` - ODROID N2+. Hosts IoT and Home Automation stuff and fully isolates that stuff from my internal network.
- not yet ready to be publicized: my main development machine, the powerful home server, some services ... (still in transition from gentoo :/) - not yet ready to be publicized: my main development machine, the powerful home server, some services ... (still in transition from gentoo :/)
- `modules/` additional NixOS modules that are not yet upstreamed. - `modules/` additional NixOS modules that are not yet upstreamed, or specific to this setup.
- `nix/` library functions and plumbing - `nix/` library functions and plumbing
- `apps/` Additional runnable actions for this flake - `apps/` Additional runnable actions for this flake
- `default.nix` Collects all apps and generates a definition for a specified system - `default.nix` Collects all apps and generates a definition for a specified system

View file

@ -67,15 +67,22 @@
# > net.cidr.canonicalize "192.168.1.100/24" # > net.cidr.canonicalize "192.168.1.100/24"
# "192.168.1.0/24" # "192.168.1.0/24"
canonicalize = x: libWithNet.net.cidr.make (libWithNet.net.cidr.length x) (ip x); canonicalize = x: libWithNet.net.cidr.make (libWithNet.net.cidr.length x) (ip x);
# coercev4 :: [cidr4] -> (cidr4 | null) # coercev4 :: [cidr4 | ipv4] -> (cidr4 | null)
# #
# Returns the smallest cidr network that includes all given addresses # Returns the smallest cidr network that includes all given addresses.
# If no cidr mask is given, /32 is assumed.
# #
# Examples: # Examples:
# #
# > net.cidr.coercev4 ["192.168.1.1/24" "192.168.6.1/32"] # > net.cidr.coercev4 ["192.168.1.1/24" "192.168.6.1/32"]
# "192.168.0.0/21" # "192.168.0.0/21"
coercev4 = addrs: let coercev4 = addrs_: let
# Append /32 if necessary
addrs = map (x:
if lib.hasInfix "/" x
then x
else "${x}/32")
addrs_;
# The smallest occurring length is the first we need to start checking, since # The smallest occurring length is the first we need to start checking, since
# any greater cidr length represents a smaller address range which # any greater cidr length represents a smaller address range which
# wouldn't contain all of the original addresses. # wouldn't contain all of the original addresses.
@ -101,15 +108,22 @@
if addrs == [] if addrs == []
then null then null
else libWithNet.net.cidr.make bestLength firstIp; else libWithNet.net.cidr.make bestLength firstIp;
# coercev6 :: [cidr6] -> (cidr6 | null) # coercev6 :: [cidr6 | ipv6] -> (cidr6 | null)
# #
# Returns the smallest cidr network that includes all given addresses # Returns the smallest cidr network that includes all given addresses.
# If no cidr mask is given, /128 is assumed.
# #
# Examples: # Examples:
# #
# > net.cidr.coercev6 ["fd00:dead:cafe::/64" "fd00:fd12:3456:7890::/56"] # > net.cidr.coercev6 ["fd00:dead:cafe::/64" "fd00:fd12:3456:7890::/56"]
# "fd00:c000::/18" # "fd00:c000::/18"
coercev6 = addrs: let coercev6 = addrs_: let
# Append /128 if necessary
addrs = map (x:
if lib.hasInfix "/" x
then x
else "${x}/128")
addrs_;
# The smallest occurring length is the first we need to start checking, since # The smallest occurring length is the first we need to start checking, since
# any greater cidr length represents a smaller address range which # any greater cidr length represents a smaller address range which
# wouldn't contain all of the original addresses. # wouldn't contain all of the original addresses.

View file

@ -193,9 +193,8 @@
via = nodeName; via = nodeName;
keepalive = false; keepalive = false;
}; };
cidrv4 = "${net.cidr.host vmCfg.id cfg.networking.wireguard.cidrv4}/32"; ipv4 = net.cidr.host vmCfg.id cfg.networking.wireguard.cidrv4;
cidrv6 = "${net.cidr.host vmCfg.id cfg.networking.wireguard.cidrv6}/128"; ipv6 = net.cidr.host vmCfg.id cfg.networking.wireguard.cidrv6;
# TODO check error: addresses = ["10.22.22.2/30"];
}; };
}; };
}; };
@ -402,8 +401,8 @@ in {
inherit (cfg.networking) host; inherit (cfg.networking) host;
inherit (cfg.networking.wireguard) openFirewallRules port; inherit (cfg.networking.wireguard) openFirewallRules port;
}; };
cidrv4 = net.cidr.hostCidr 1 cfg.networking.wireguard.cidrv4; ipv4 = net.cidr.host 1 cfg.networking.wireguard.cidrv4;
cidrv6 = net.cidr.hostCidr 1 cfg.networking.wireguard.cidrv6; ipv6 = net.cidr.host 1 cfg.networking.wireguard.cidrv6;
}; };
} }
// extraLib.mergeToplevelConfigs ["disko" "microvm" "systemd"] (mapAttrsToList microvmConfig vms) // extraLib.mergeToplevelConfigs ["disko" "microvm" "systemd"] (mapAttrsToList microvmConfig vms)

View file

@ -86,6 +86,23 @@
# Adds context information to the assertions for this network # Adds context information to the assertions for this network
assertionPrefix = "Wireguard network '${wgName}' on '${nodeName}'"; assertionPrefix = "Wireguard network '${wgName}' on '${nodeName}'";
# Calculates which traffic should be routed to a given server node
# Usually we just want to allow other peers to route traffic
# for our "children" through us, additional to traffic to us of course.
# If a server exposes additional network access (global, lan, ...),
# these can be added aswell. TODO (do that)
serverAllowedIPs = serverNode: let
snCfg = wgCfgOf serverNode;
in
map (net.cidr.make 128) (
# The server accepts traffic to it's own address
snCfg.addresses
# plus traffic for any of its external peers
++ attrValues snCfg.server.externalPeers
# plus traffic for any client that is connected via that server
++ map (n: (wgCfgOf n).addresses) (filter (n: (wgCfgOf n).client.via == serverNode) associatedClientNodes)
);
in { in {
assertions = [ assertions = [
{ {
@ -157,16 +174,13 @@
if isServer if isServer
then then
# Always include all other server nodes. # Always include all other server nodes.
map (serverNode: { map (serverNode: let
wireguardPeerConfig = let snCfg = wgCfgOf serverNode;
snCfg = wgCfgOf serverNode; in {
in { wireguardPeerConfig = {
PublicKey = builtins.readFile (peerPublicKeyPath serverNode); PublicKey = builtins.readFile (peerPublicKeyPath serverNode);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName serverNode}.path; PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName serverNode}.path;
# The allowed ips of a server node are it's own addreses, AllowedIPs = serverAllowedIPs serverNode;
# plus each external peer's addresses,
# plus each client's addresses that is connected via that node.
AllowedIPs = snCfg.addresses;
Endpoint = "${snCfg.server.host}:${toString snCfg.server.port}"; Endpoint = "${snCfg.server.host}:${toString snCfg.server.port}";
}; };
}) })
@ -192,7 +206,7 @@
{ {
PublicKey = builtins.readFile (peerPublicKeyPath clientNode); PublicKey = builtins.readFile (peerPublicKeyPath clientNode);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName clientNode}.path; PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName clientNode}.path;
AllowedIPs = clientCfg.addresses; AllowedIPs = map (net.cidr.make 128) clientCfg.addresses;
} }
// optionalAttrs clientCfg.keepalive { // optionalAttrs clientCfg.keepalive {
PersistentKeepalive = 25; PersistentKeepalive = 25;
@ -207,7 +221,7 @@
PublicKey = builtins.readFile (peerPublicKeyPath wgCfg.client.via); PublicKey = builtins.readFile (peerPublicKeyPath wgCfg.client.via);
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName wgCfg.client.via}.path; PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret nodeName wgCfg.client.via}.path;
# TODO this should be 0.0.0.0 if the client wants to route all traffic # TODO this should be 0.0.0.0 if the client wants to route all traffic
AllowedIPs = (wgCfgOf wgCfg.client.via).addresses; AllowedIPs = serverAllowedIPs wgCfg.client.via;
}; };
} }
]; ];
@ -301,44 +315,23 @@ in {
description = mdDoc "The order priority used when creating systemd netdev and network files."; description = mdDoc "The order priority used when creating systemd netdev and network files.";
}; };
cidrv4 = mkOption { ipv4 = mkOption {
type = type = net.types.ipv4;
if config.client.via != null description = mdDoc "The ipv4 address for this machine.";
then net.types.cidrv4-in nodes.${config.client.via}.config.extra.wireguard.${name}.cidrv4
else net.types.cidrv4;
description = mdDoc ''
The ipv4 host address (with cidr mask) to configure for this interface.
The cidr mask determines this peers allowed address range as configured on other peers.
The mask should usually be fully restricted (/32) when no external clients are configured
and no other node uses this as a via.
'';
}; };
cidrv6 = mkOption { ipv6 = mkOption {
type = type = net.types.ipv6;
if config.client.via != null description = mdDoc "The ipv6 address for this machine.";
then net.types.cidrv6-in nodes.${config.client.via}.config.extra.wireguard.${name}.cidrv6
else net.types.cidrv6;
description = mdDoc ''
The ipv6 host address (with cidr mask) to configure for this interface.
The cidr mask determines this peers allowed address range as configured on other peers.
The mask should usually be fully restricted (/128) when no external clients are configured
and no other node uses this as a via.
'';
}; };
addresses = mkOption { addresses = mkOption {
type = types.listOf ( type = types.listOf net.types.ip;
if config.client.via != null default = [config.ipv4 config.ipv6];
then net.types.cidr-in nodes.${config.client.via}.config.extra.wireguard.${name}.addresses
else net.types.cidr
);
default = [config.cidrv4 config.cidrv6];
description = mdDoc '' description = mdDoc ''
The addresses (with cidr mask) to configure for this interface. The ip addresses (v4 and/or v6) to use for this machine.
The cidr mask determines this peers allowed address range as configured on other peers.
The actual network cidr will automatically be derived from all network participants. The actual network cidr will automatically be derived from all network participants.
By default this will just include {option}`cidrv4` and {option}`cidrv6` as configured. By default this will just include {option}`ipv4` and {option}`ipv6` as configured.
''; '';
}; };
}; };