at master 6.7 kB view raw
1{ 2 system ? builtins.currentSystem, 3 pkgs ? import ../.. { inherit system; }, 4 lib ? pkgs.lib, 5}: 6 7let 8 inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; 9 nodeIP = n: n.networking.primaryIPAddress; 10 dnsZone = 11 nodes: 12 pkgs.writeText "agnos.test.zone" '' 13 $TTL 604800 14 @ IN SOA ns1.agnos.test. root.agnos.test. ( 15 3 ; Serial 16 604800 ; Refresh 17 86400 ; Retry 18 2419200 ; Expire 19 604800 ) ; Negative Cache TTL 20 ; 21 ; name servers - NS records 22 IN NS ns1.agnos.test. 23 24 ; name servers - A records 25 ns1.agnos.test. IN A ${nodeIP nodes.dnsserver} 26 27 agnos-ns.agnos.test. IN A ${nodeIP nodes.server} 28 _acme-challenge.a.agnos.test. IN NS agnos-ns.agnos.test. 29 _acme-challenge.b.agnos.test. IN NS agnos-ns.agnos.test. 30 _acme-challenge.c.agnos.test. IN NS agnos-ns.agnos.test. 31 _acme-challenge.d.agnos.test. IN NS agnos-ns.agnos.test. 32 ''; 33 34 mkTest = 35 { 36 name, 37 extraServerConfig ? { }, 38 checkFirewallClosed ? true, 39 }: 40 makeTest { 41 inherit name; 42 meta = { 43 maintainers = with lib.maintainers; [ justinas ]; 44 }; 45 46 nodes = { 47 # The fake ACME server which will respond to client requests 48 acme = 49 { nodes, pkgs, ... }: 50 { 51 imports = [ ./common/acme/server ]; 52 environment.systemPackages = [ pkgs.netcat ]; 53 networking.nameservers = lib.mkForce [ (nodeIP nodes.dnsserver) ]; 54 }; 55 56 # A fake DNS server which points _acme-challenge subdomains to "server" 57 dnsserver = 58 { nodes, ... }: 59 { 60 networking.firewall.allowedTCPPorts = [ 53 ]; 61 networking.firewall.allowedUDPPorts = [ 53 ]; 62 services.bind = { 63 cacheNetworks = [ "192.168.1.0/24" ]; 64 enable = true; 65 extraOptions = '' 66 dnssec-validation no; 67 ''; 68 zones."agnos.test" = { 69 file = dnsZone nodes; 70 master = true; 71 }; 72 }; 73 }; 74 75 # The server using agnos to request certificates 76 server = 77 { nodes, ... }: 78 { 79 imports = [ extraServerConfig ]; 80 81 networking.extraHosts = '' 82 ${nodeIP nodes.acme} acme.test 83 ''; 84 security.agnos = { 85 enable = true; 86 generateKeys.enable = true; 87 persistent = false; 88 server = "https://acme.test/dir"; 89 serverCa = ./common/acme/server/ca.cert.pem; 90 temporarilyOpenFirewall = true; 91 92 settings.accounts = [ 93 { 94 email = "webmaster@agnos.test"; 95 # account with an existing private key 96 private_key_path = "${./common/acme/server/acme.test.key.pem}"; 97 98 certificates = [ 99 { 100 domains = [ "a.agnos.test" ]; 101 # Absolute paths 102 fullchain_output_file = "/tmp/a.agnos.test.crt"; 103 key_output_file = "/tmp/a.agnos.test.key"; 104 } 105 106 { 107 domains = [ 108 "b.agnos.test" 109 "*.b.agnos.test" 110 ]; 111 # Relative paths 112 fullchain_output_file = "b.agnos.test.crt"; 113 key_output_file = "b.agnos.test.key"; 114 } 115 ]; 116 } 117 118 { 119 email = "webmaster2@agnos.test"; 120 # account with a missing private key, should get generated 121 private_key_path = "webmaster2.key"; 122 123 certificates = [ 124 { 125 domains = [ "c.agnos.test" ]; 126 # Absolute paths 127 fullchain_output_file = "/tmp/c.agnos.test.crt"; 128 key_output_file = "/tmp/c.agnos.test.key"; 129 } 130 131 { 132 domains = [ 133 "d.agnos.test" 134 "*.d.agnos.test" 135 ]; 136 # Relative paths 137 fullchain_output_file = "d.agnos.test.crt"; 138 key_output_file = "d.agnos.test.key"; 139 } 140 ]; 141 } 142 ]; 143 }; 144 }; 145 }; 146 147 testScript = '' 148 def check_firewall_closed(caller): 149 """ 150 Check that TCP port 53 is closed again. 151 152 Since we do not set `networking.firewall.rejectPackets`, 153 "timed out" indicates a closed port, 154 while "connection refused" (after agnos has shut down) indicates an open port. 155 """ 156 157 out = caller.fail("nc -v -z -w 1 server 53 2>&1") 158 assert "Connection timed out" in out 159 160 start_all() 161 acme.wait_for_unit('pebble.service') 162 server.wait_for_unit('default.target') 163 164 # Test that agnos.timer is scheduled 165 server.succeed("systemctl status agnos.timer") 166 server.succeed('systemctl start agnos.service') 167 168 expected_perms = "640 agnos agnos" 169 outputs = [ 170 "/tmp/a.agnos.test.crt", 171 "/tmp/a.agnos.test.key", 172 "/var/lib/agnos/b.agnos.test.crt", 173 "/var/lib/agnos/b.agnos.test.key", 174 "/var/lib/agnos/webmaster2.key", 175 "/tmp/c.agnos.test.crt", 176 "/tmp/c.agnos.test.key", 177 "/var/lib/agnos/d.agnos.test.crt", 178 "/var/lib/agnos/d.agnos.test.key", 179 ] 180 for o in outputs: 181 out = server.succeed(f"stat -c '%a %U %G' {o}").strip() 182 assert out == expected_perms, \ 183 f"Expected mode/owner/group to be '{expected_perms}', but it was '{out}'" 184 185 ${lib.optionalString checkFirewallClosed "check_firewall_closed(acme)"} 186 ''; 187 }; 188in 189{ 190 iptables = mkTest { 191 name = "iptables"; 192 }; 193 194 nftables = mkTest { 195 name = "nftables"; 196 extraServerConfig = { 197 networking.nftables.enable = true; 198 }; 199 }; 200 201 no-firewall = mkTest { 202 name = "no-firewall"; 203 extraServerConfig = { 204 networking.firewall.enable = lib.mkForce false; 205 security.agnos.temporarilyOpenFirewall = lib.mkForce false; 206 }; 207 checkFirewallClosed = false; 208 }; 209}