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