1 import ./make-test-python.nix ({ pkgs, lib, ... }: let
3 # We'll need to be able to trade cert files between nodes via scp.
4 inherit (import ./ssh-keys.nix pkgs)
5 snakeOilPrivateKey snakeOilPublicKey;
7 makeNebulaNode = { config, ... }: name: extraConfig: lib.mkMerge [
9 # Expose nebula for doing cert signing.
10 environment.systemPackages = [ pkgs.nebula ];
11 users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
12 services.openssh.enable = true;
14 services.nebula.networks.smoke = {
15 # Note that these paths won't exist when the machine is first booted.
16 ca = "/etc/nebula/ca.crt";
17 cert = "/etc/nebula/${name}.crt";
18 key = "/etc/nebula/${name}.key";
19 listen = { host = "0.0.0.0"; port = 4242; };
31 lighthouse = { ... } @ args:
32 makeNebulaNode args "lighthouse" {
33 networking.interfaces.eth1.ipv4.addresses = [{
34 address = "192.168.1.1";
38 services.nebula.networks.smoke = {
41 outbound = [ { port = "any"; proto = "any"; host = "any"; } ];
42 inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
47 node2 = { ... } @ args:
48 makeNebulaNode args "node2" {
49 networking.interfaces.eth1.ipv4.addresses = [{
50 address = "192.168.1.2";
54 services.nebula.networks.smoke = {
55 staticHostMap = { "10.0.100.1" = [ "192.168.1.1:4242" ]; };
57 lighthouses = [ "10.0.100.1" ];
59 outbound = [ { port = "any"; proto = "any"; host = "any"; } ];
60 inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
65 node3 = { ... } @ args:
66 makeNebulaNode args "node3" {
67 networking.interfaces.eth1.ipv4.addresses = [{
68 address = "192.168.1.3";
72 services.nebula.networks.smoke = {
73 staticHostMap = { "10.0.100.1" = [ "192.168.1.1:4242" ]; };
75 lighthouses = [ "10.0.100.1" ];
77 outbound = [ { port = "any"; proto = "any"; host = "any"; } ];
78 inbound = [ { port = "any"; proto = "any"; host = "lighthouse"; } ];
83 node4 = { ... } @ args:
84 makeNebulaNode args "node4" {
85 networking.interfaces.eth1.ipv4.addresses = [{
86 address = "192.168.1.4";
90 services.nebula.networks.smoke = {
92 staticHostMap = { "10.0.100.1" = [ "192.168.1.1:4242" ]; };
94 lighthouses = [ "10.0.100.1" ];
96 outbound = [ { port = "any"; proto = "any"; host = "lighthouse"; } ];
97 inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
102 node5 = { ... } @ args:
103 makeNebulaNode args "node5" {
104 networking.interfaces.eth1.ipv4.addresses = [{
105 address = "192.168.1.5";
109 services.nebula.networks.smoke = {
111 staticHostMap = { "10.0.100.1" = [ "192.168.1.1:4242" ]; };
112 isLighthouse = false;
113 lighthouses = [ "10.0.100.1" ];
115 outbound = [ { port = "any"; proto = "any"; host = "lighthouse"; } ];
116 inbound = [ { port = "any"; proto = "any"; host = "any"; } ];
125 setUpPrivateKey = name: ''
127 "mkdir -p /root/.ssh",
128 "chown 700 /root/.ssh",
129 "cat '${snakeOilPrivateKey}' > /root/.ssh/id_snakeoil",
130 "chown 600 /root/.ssh/id_snakeoil",
134 # From what I can tell, StrictHostKeyChecking=no is necessary for ssh to work between machines.
135 sshOpts = "-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oIdentityFile=/root/.ssh/id_snakeoil";
137 restartAndCheckNebula = name: ip: ''
138 ${name}.systemctl("restart nebula@smoke.service")
139 ${name}.succeed("ping -c5 ${ip}")
142 # Create a keypair on the client node, then use the public key to sign a cert on the lighthouse.
143 signKeysFor = name: ip: ''
144 lighthouse.wait_for_unit("sshd.service")
145 ${name}.wait_for_unit("sshd.service")
147 "mkdir -p /etc/nebula",
148 "nebula-cert keygen -out-key /etc/nebula/${name}.key -out-pub /etc/nebula/${name}.pub",
149 "scp ${sshOpts} /etc/nebula/${name}.pub 192.168.1.1:/tmp/${name}.pub",
152 'nebula-cert sign -ca-crt /etc/nebula/ca.crt -ca-key /etc/nebula/ca.key -name "${name}" -groups "${name}" -ip "${ip}" -in-pub /tmp/${name}.pub -out-crt /tmp/${name}.crt',
155 "scp ${sshOpts} 192.168.1.1:/tmp/${name}.crt /etc/nebula/${name}.crt",
156 "scp ${sshOpts} 192.168.1.1:/etc/nebula/ca.crt /etc/nebula/ca.crt",
163 # Create the certificate and sign the lighthouse's keys.
164 ${setUpPrivateKey "lighthouse"}
166 "mkdir -p /etc/nebula",
167 'nebula-cert ca -name "Smoke Test" -out-crt /etc/nebula/ca.crt -out-key /etc/nebula/ca.key',
168 'nebula-cert sign -ca-crt /etc/nebula/ca.crt -ca-key /etc/nebula/ca.key -name "lighthouse" -groups "lighthouse" -ip "10.0.100.1/24" -out-crt /etc/nebula/lighthouse.crt -out-key /etc/nebula/lighthouse.key',
171 # Reboot the lighthouse and verify that the nebula service comes up on boot.
172 # Since rebooting takes a while, we'll just restart the service on the other nodes.
173 lighthouse.shutdown()
175 lighthouse.wait_for_unit("nebula@smoke.service")
176 lighthouse.succeed("ping -c5 10.0.100.1")
178 # Create keys for node2's nebula service and test that it comes up.
179 ${setUpPrivateKey "node2"}
180 ${signKeysFor "node2" "10.0.100.2/24"}
181 ${restartAndCheckNebula "node2" "10.0.100.2"}
183 # Create keys for node3's nebula service and test that it comes up.
184 ${setUpPrivateKey "node3"}
185 ${signKeysFor "node3" "10.0.100.3/24"}
186 ${restartAndCheckNebula "node3" "10.0.100.3"}
188 # Create keys for node4's nebula service and test that it comes up.
189 ${setUpPrivateKey "node4"}
190 ${signKeysFor "node4" "10.0.100.4/24"}
191 ${restartAndCheckNebula "node4" "10.0.100.4"}
193 # Create keys for node4's nebula service and test that it does not come up.
194 ${setUpPrivateKey "node5"}
195 ${signKeysFor "node5" "10.0.100.5/24"}
196 node5.fail("systemctl status nebula@smoke.service")
197 node5.fail("ping -c5 10.0.100.5")
199 # The lighthouse can ping node2 and node3 but not node5
200 lighthouse.succeed("ping -c3 10.0.100.2")
201 lighthouse.succeed("ping -c3 10.0.100.3")
202 lighthouse.fail("ping -c3 10.0.100.5")
204 # node2 can ping the lighthouse, but not node3 because of its inbound firewall
205 node2.succeed("ping -c3 10.0.100.1")
206 node2.fail("ping -c3 10.0.100.3")
208 # node3 can ping the lighthouse and node2
209 node3.succeed("ping -c3 10.0.100.1")
210 node3.succeed("ping -c3 10.0.100.2")
212 # node4 can ping the lighthouse but not node2 or node3
213 node4.succeed("ping -c3 10.0.100.1")
214 node4.fail("ping -c3 10.0.100.2")
215 node4.fail("ping -c3 10.0.100.3")
217 # node2 can ping node3 now that node3 pinged it first
218 node2.succeed("ping -c3 10.0.100.3")
219 # node4 can ping node2 if node2 pings it first
220 node2.succeed("ping -c3 10.0.100.4")
221 node4.succeed("ping -c3 10.0.100.2")