diff --git a/configurers/networkd.nix b/configurers/networkd.nix index 29f4e5f..cda8011 100644 --- a/configurers/networkd.nix +++ b/configurers/networkd.nix @@ -31,7 +31,7 @@ with getKeyProviderFuncs keyProviders inputs intermediateConfig localPeerName; wireguardConfig = { PrivateKeyFile = getPrivKeyFile; ListenPort = subnetConnection.listenPort; - }; + } // (if getPrivKeyFile != null then {} else {privateKey = getPrivKey;}); wireguardPeers = forEachAttrToList subnetConnection.peerConnections (remotePeerName: peerConnection: { wireguardPeerConfig = { Endpoint = "${peerConnection.endpoint.ip}:${builtins.toString peerConnection.endpoint.port}"; diff --git a/configurers/static.nix b/configurers/static.nix index 56d2557..3e72477 100644 --- a/configurers/static.nix +++ b/configurers/static.nix @@ -26,7 +26,8 @@ with getKeyProviderFuncs keyProviders inputs intermediateConfig localPeerName; { ips = subnetConnection.ipAddresses; listenPort = subnetConnection.listenPort; - privateKeyFile = getPrivKeyFile; + privateKeyFile = getPrivKeyFile; + privateKey = getPrivKey; peers = forEachAttrToList subnetConnection.peerConnections (remotePeerName: peerConnection: { name = remotePeerName; diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..0d4b04a --- /dev/null +++ b/flake.lock @@ -0,0 +1,25 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1692463654, + "narHash": "sha256-F8hZmsQINI+S6UROM4jyxAMbQLtzE44pI8Nk6NtMdao=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ca3c9ac9f4cdd4bea19f592b32bb59b74ab7d783", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 545be6b..5a1a736 100644 --- a/flake.nix +++ b/flake.nix @@ -23,6 +23,7 @@ in { # import our test null = import ./tests/null.nix checkArgs; + simple = import ./tests/simple.nix checkArgs; }); }; } diff --git a/key-providers/acl.nix b/key-providers/acl.nix index 6e16f38..1872235 100644 --- a/key-providers/acl.nix +++ b/key-providers/acl.nix @@ -10,5 +10,6 @@ with builtins; { getPeerPubKey = remotePeerName: attrByPath [remotePeerName "publicKey"] null intermediateConfig.peers; getPrivKeyFile = attrByPath [localPeerName "privateKeyFile"] null intermediateConfig.peers; + getPrivKey = attrByPath [localPeerName "privateKey"] null intermediateConfig.peers; getSubnetPSKFile = subnetName: attrByPath [subnetName "presharedKeyFile"] null intermediateConfig.subnets; } \ No newline at end of file diff --git a/key-providers/agenix-rekey.nix b/key-providers/agenix-rekey.nix index 7acc383..29e74b6 100644 --- a/key-providers/agenix-rekey.nix +++ b/key-providers/agenix-rekey.nix @@ -35,5 +35,6 @@ with builtins; }; getPeerPubKey = remotePeerName: builtins.readFile (config.wirenix.secretsDir + /wirenix-peer-${remotePeerName}.pub); getPrivKeyFile = config.age.secrets."wirenix-peer-${localPeerName}".path; + getPrivKey = null; getSubnetPSKFile = subnetName: config.age.secrets."wirenix-subnet-${subnetName}".path; } \ No newline at end of file diff --git a/lib.nix b/lib.nix index 46d238a..182c4cc 100644 --- a/lib.nix +++ b/lib.nix @@ -116,11 +116,13 @@ rec { let keyProviders = map (x: x inputs intermediateConfig peerName) keyProvidersUninitialized; in - { + rec { getPeerPubKey = otherPeerName: findFirst (x: x != null) (throw ("Wirenix: Could not find public key for " + otherPeerName)) (map (provider: provider.getPeerPubKey otherPeerName) keyProviders); - getPrivKeyFile = findFirst (x: x != null) (throw ("Wirenix: Could not find private key file for " + peerName)) + getPrivKeyFile = findFirst (x: x != null) (if getPrivKey == null then throw ("Wirenix: Could not find private key file for " + peerName) else null) (map (provider: provider.getPrivKeyFile) keyProviders); + getPrivKey = findFirst (x: x != null) (null) + (map (provider: provider.getPrivKey) keyProviders); getSubnetPSKFile = subnetName: findFirst (x: x != null) (null) (map (provider: provider.getSubnetPSKFile subnetName) keyProviders); getProviderConfig = foldl' (x: y: x // y) {} (map (provider: if provider ? config then provider.config else {}) keyProviders); diff --git a/parsers/v1.nix b/parsers/v1.nix index db73edf..668732a 100644 --- a/parsers/v1.nix +++ b/parsers/v1.nix @@ -17,6 +17,7 @@ let // mergeIf acl_peer "extraArgs" // mergeIf acl_peer "publicKey" // mergeIf acl_peer "privateKeyFile" + // mergeIf acl_peer "privateKey" // (if acl_peer ? groups then {groups = map groupFromName acl_peer.groups;} else {groups = {};}); /** parseGroup :: acl_group -> ic_group */ diff --git a/tests/acls/simple.nix b/tests/acls/simple.nix new file mode 100644 index 0000000..dea9af1 --- /dev/null +++ b/tests/acls/simple.nix @@ -0,0 +1,58 @@ +{ + version = "v1"; + subnets = [ + { + name = "simple"; + endpoints = [ + { + # No match mean match any + port = 51820; + } + ]; + } + ]; + groups = [ + # groups field is expected, but can be empty + ]; + peers = [ + { + name = "peer1"; + subnets = { + simple = { + listenPort = 51820; + # empty ipAddresses will auto generate an IPv6 address + }; + }; + publicKey = "kdyzqV8cBQtDYeW6R1vUug0Oe+KaytHHDS7JoCp/kTE="; + privateKey = "MIELhEc0I7BseAanhk/+LlY/+Yf7GK232vKWITExnEI="; # path is relative to the machine + endpoints = [ + { + # no match can be any + ip = "192.168.1.2"; + } + ]; + } + { + name = "peer2"; + subnets = { + simple = { + listenPort = 51820; + }; + }; + publicKey = "ztdAXTspQEZUNpxUbUdAhhRWbiL3YYWKSK0ZGdcsMHE="; + privateKey = "yG4mJiduoAvzhUJMslRbZwOp1gowSfC+wgY8B/Mul1M="; + endpoints = [ + { + # no match can be any + ip = "192.168.1.3"; + } + ]; + } + ]; + connections = [ + { + a = [{type= "subnet"; rule = "is"; value = "simple";}]; + b = [{type= "subnet"; rule = "is"; value = "simple";}]; + } + ]; +} \ No newline at end of file diff --git a/tests/keys/testKey1 b/tests/keys/testKey1 new file mode 100644 index 0000000..394449c --- /dev/null +++ b/tests/keys/testKey1 @@ -0,0 +1 @@ +MIELhEc0I7BseAanhk/+LlY/+Yf7GK232vKWITExnEI= \ No newline at end of file diff --git a/tests/keys/testKey2 b/tests/keys/testKey2 new file mode 100644 index 0000000..3cc7d1f --- /dev/null +++ b/tests/keys/testKey2 @@ -0,0 +1 @@ +yG4mJiduoAvzhUJMslRbZwOp1gowSfC+wgY8B/Mul1M= \ No newline at end of file diff --git a/tests/keys/testKey3 b/tests/keys/testKey3 new file mode 100644 index 0000000..803572c --- /dev/null +++ b/tests/keys/testKey3 @@ -0,0 +1 @@ +mAk4v/O2y3mFwQqsZow52iwOlcfR3wPtd9cVBwS+vVg= \ No newline at end of file diff --git a/tests/keys/testKey4 b/tests/keys/testKey4 new file mode 100644 index 0000000..5b8cd8d --- /dev/null +++ b/tests/keys/testKey4 @@ -0,0 +1 @@ +aKOVgooO5npcsTrDb2lKXEiOH+XhJTs3/GHICplKmHE= \ No newline at end of file diff --git a/tests/keys/testKey5 b/tests/keys/testKey5 new file mode 100644 index 0000000..a68d299 --- /dev/null +++ b/tests/keys/testKey5 @@ -0,0 +1 @@ +aPMW0ePlRmh3HZ075ArvUHIotrGTGE+nRvqKPtwXClc= \ No newline at end of file diff --git a/tests/keys/testKey6 b/tests/keys/testKey6 new file mode 100644 index 0000000..ec44c3e --- /dev/null +++ b/tests/keys/testKey6 @@ -0,0 +1 @@ +IDpYI54t9nGxmj84KUpRaFUnzaD74LVm1y38rGeIVVg= \ No newline at end of file diff --git a/tests/null.nix b/tests/null.nix index 766d3c4..b954345 100644 --- a/tests/null.nix +++ b/tests/null.nix @@ -13,8 +13,6 @@ # This is the test code that will check if our service is running correctly: testScript = '' start_all() - # wait for our service to start - node1.wait_for_unit("hello-world-server") output = node1.succeed("echo Hello world") # Check if our webserver returns the expected result assert "Hello world" in output, f"'{output}' does not contain 'Hello world'" diff --git a/tests/simple.nix b/tests/simple.nix new file mode 100644 index 0000000..3f6b818 --- /dev/null +++ b/tests/simple.nix @@ -0,0 +1,63 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +let + sharedConfig = { + wirenix = { + enable = true; + keyProviders = ["acl"]; + aclConfig = import ./acls/simple.nix; + }; + }; +in +(import ./lib.nix) +{ + name = "Null test, should always pass"; + nodes = { + # `self` here is set by using specialArgs in `lib.nix` + node1 = { self, pkgs, ... }: sharedConfig // { + imports = [ self.nixosModules.default ]; + wirenix = { + enable = true; + keyProviders = ["acl"]; + peerName = "peer1"; + aclConfig = import ./acls/simple.nix; + }; + networking.interfaces.eth1.ipv4.addresses = [ + { + address = "192.168.1.2"; + prefixLength = 24; + } + ]; + environment.systemPackages = [ pkgs.curl ]; + }; + + node2 = { self, pkgs, ... }: sharedConfig // { + imports = [ self.nixosModules.default ]; + wirenix = { + enable = true; + keyProviders = ["acl"]; + peerName = "peer2"; + aclConfig = import ./acls/simple.nix; + }; + networking.interfaces.eth1.ipv4.addresses = [ + { + address = "192.168.1.3"; + prefixLength = 24; + } + ]; + environment.systemPackages = [ pkgs.curl ]; + }; + }; + # This is the test code that will check if our service is running correctly: + testScript = '' + start_all() + node1.wait_for_unit("wireguard-simple") + node2.wait_for_unit("wireguard-simple") + output = node1.succeed("ping -c 1 peer2.simple") + # Check if our webserver returns the expected result + assert "Hello world" in output, f"'{output}' does not contain 'Hello world'" + ''; +} \ No newline at end of file diff --git a/wire.nix b/wire.nix index 7b9cfa7..bc029ea 100644 --- a/wire.nix +++ b/wire.nix @@ -30,6 +30,8 @@ let in { options = { + age = {}; + sops = {}; wirenix = { enable = mkEnableOption "wirenix"; peerName = mkOption {