at 25.11-pre 5.8 kB view raw
1{ 2 system ? builtins.currentSystem, 3 config ? { }, 4 pkgs ? import ../.. { inherit system config; }, 5}: 6 7with import ../lib/testing-python.nix { inherit system pkgs; }; 8with pkgs.lib; 9 10let 11 stunnelCommon = { 12 services.stunnel = { 13 enable = true; 14 user = "stunnel"; 15 }; 16 users.groups.stunnel = { }; 17 users.users.stunnel = { 18 isSystemUser = true; 19 group = "stunnel"; 20 }; 21 }; 22 makeCert = 23 { config, pkgs, ... }: 24 { 25 systemd.services.create-test-cert = { 26 wantedBy = [ "sysinit.target" ]; 27 before = [ 28 "sysinit.target" 29 "shutdown.target" 30 ]; 31 conflicts = [ "shutdown.target" ]; 32 unitConfig.DefaultDependencies = false; 33 serviceConfig.Type = "oneshot"; 34 script = '' 35 ${pkgs.openssl}/bin/openssl req -batch -x509 -newkey rsa -nodes -out /test-cert.pem -keyout /test-key.pem -subj /CN=${config.networking.hostName} 36 ( umask 077; cat /test-key.pem /test-cert.pem > /test-key-and-cert.pem ) 37 chown stunnel /test-key.pem /test-key-and-cert.pem 38 ''; 39 }; 40 }; 41 serverCommon = 42 { pkgs, ... }: 43 { 44 networking.firewall.allowedTCPPorts = [ 443 ]; 45 services.stunnel.servers.https = { 46 accept = "443"; 47 connect = 80; 48 cert = "/test-key-and-cert.pem"; 49 }; 50 systemd.services.simple-webserver = { 51 wantedBy = [ "multi-user.target" ]; 52 script = '' 53 cd /etc/webroot 54 ${pkgs.python3}/bin/python -m http.server 80 55 ''; 56 }; 57 }; 58 copyCert = src: dest: filename: '' 59 from shlex import quote 60 ${src}.wait_for_file("/test-key-and-cert.pem") 61 server_cert = ${src}.succeed("cat /test-cert.pem") 62 ${dest}.succeed("echo %s > ${filename}" % quote(server_cert)) 63 ''; 64 65in 66{ 67 basicServer = makeTest { 68 name = "basicServer"; 69 70 nodes = { 71 client = { }; 72 server = { 73 imports = [ 74 makeCert 75 serverCommon 76 stunnelCommon 77 ]; 78 environment.etc."webroot/index.html".text = "well met"; 79 }; 80 }; 81 82 testScript = '' 83 start_all() 84 85 ${copyCert "server" "client" "/authorized-server-cert.crt"} 86 87 server.wait_for_unit("simple-webserver") 88 server.wait_for_unit("stunnel") 89 90 client.succeed("curl --fail --cacert /authorized-server-cert.crt https://server/ > out") 91 client.succeed('[[ "$(< out)" == "well met" ]]') 92 ''; 93 }; 94 95 serverAndClient = makeTest { 96 name = "serverAndClient"; 97 98 nodes = { 99 client = { 100 imports = [ stunnelCommon ]; 101 services.stunnel.clients = { 102 httpsClient = { 103 accept = "80"; 104 connect = "server:443"; 105 CAFile = "/authorized-server-cert.crt"; 106 }; 107 httpsClientWithHostVerify = { 108 accept = "81"; 109 connect = "server:443"; 110 CAFile = "/authorized-server-cert.crt"; 111 verifyHostname = "server"; 112 }; 113 httpsClientWithHostVerifyFail = { 114 accept = "82"; 115 connect = "server:443"; 116 CAFile = "/authorized-server-cert.crt"; 117 verifyHostname = "wronghostname"; 118 }; 119 }; 120 }; 121 server = { 122 imports = [ 123 makeCert 124 serverCommon 125 stunnelCommon 126 ]; 127 environment.etc."webroot/index.html".text = "hello there"; 128 }; 129 }; 130 131 testScript = '' 132 start_all() 133 134 ${copyCert "server" "client" "/authorized-server-cert.crt"} 135 136 server.wait_for_unit("simple-webserver") 137 server.wait_for_unit("stunnel") 138 139 # In case stunnel came up before we got the server's cert copied over 140 client.succeed("systemctl reload-or-restart stunnel") 141 142 client.succeed("curl --fail http://localhost/ > out") 143 client.succeed('[[ "$(< out)" == "hello there" ]]') 144 145 client.succeed("curl --fail http://localhost:81/ > out") 146 client.succeed('[[ "$(< out)" == "hello there" ]]') 147 148 client.fail("curl --fail http://localhost:82/ > out") 149 client.succeed('[[ "$(< out)" == "" ]]') 150 ''; 151 }; 152 153 mutualAuth = makeTest { 154 name = "mutualAuth"; 155 156 nodes = rec { 157 client = { 158 imports = [ 159 makeCert 160 stunnelCommon 161 ]; 162 services.stunnel.clients.authenticated-https = { 163 accept = "80"; 164 connect = "server:443"; 165 verifyPeer = true; 166 CAFile = "/authorized-server-cert.crt"; 167 cert = "/test-cert.pem"; 168 key = "/test-key.pem"; 169 }; 170 }; 171 wrongclient = client; 172 server = { 173 imports = [ 174 makeCert 175 serverCommon 176 stunnelCommon 177 ]; 178 services.stunnel.servers.https = { 179 CAFile = "/authorized-client-certs.crt"; 180 verifyPeer = true; 181 }; 182 environment.etc."webroot/index.html".text = "secret handshake"; 183 }; 184 }; 185 186 testScript = '' 187 start_all() 188 189 ${copyCert "server" "client" "/authorized-server-cert.crt"} 190 ${copyCert "client" "server" "/authorized-client-certs.crt"} 191 ${copyCert "server" "wrongclient" "/authorized-server-cert.crt"} 192 193 # In case stunnel came up before we got the cross-certs in place 194 client.succeed("systemctl reload-or-restart stunnel") 195 server.succeed("systemctl reload-or-restart stunnel") 196 wrongclient.succeed("systemctl reload-or-restart stunnel") 197 198 server.wait_for_unit("simple-webserver") 199 client.fail("curl --fail --insecure https://server/ > out") 200 client.succeed('[[ "$(< out)" == "" ]]') 201 client.succeed("curl --fail http://localhost/ > out") 202 client.succeed('[[ "$(< out)" == "secret handshake" ]]') 203 wrongclient.fail("curl --fail http://localhost/ > out") 204 wrongclient.succeed('[[ "$(< out)" == "" ]]') 205 ''; 206 }; 207}