1 { system ? builtins.currentSystem, config ? { }
2 , pkgs ? import ../.. { inherit system config; } }:
4 with import ../lib/testing-python.nix { inherit system pkgs; };
13 users.groups.stunnel = { };
14 users.users.stunnel = {
19 makeCert = { config, pkgs, ... }: {
20 systemd.services.create-test-cert = {
21 wantedBy = [ "sysinit.target" ];
22 before = [ "sysinit.target" ];
23 unitConfig.DefaultDependencies = false;
25 ${pkgs.openssl}/bin/openssl req -batch -x509 -newkey rsa -nodes -out /test-cert.pem -keyout /test-key.pem -subj /CN=${config.networking.hostName}
26 ( umask 077; cat /test-key.pem /test-cert.pem > /test-key-and-cert.pem )
27 chown stunnel /test-key.pem /test-key-and-cert.pem
31 serverCommon = { pkgs, ... }: {
32 networking.firewall.allowedTCPPorts = [ 443 ];
33 services.stunnel.servers.https = {
36 cert = "/test-key-and-cert.pem";
38 systemd.services.simple-webserver = {
39 wantedBy = [ "multi-user.target" ];
42 ${pkgs.python3}/bin/python -m http.server 80
46 copyCert = src: dest: filename: ''
47 from shlex import quote
48 ${src}.wait_for_file("/test-key-and-cert.pem")
49 server_cert = ${src}.succeed("cat /test-cert.pem")
50 ${dest}.succeed("echo %s > ${filename}" % quote(server_cert))
54 basicServer = makeTest {
60 imports = [ makeCert serverCommon stunnelCommon ];
61 environment.etc."webroot/index.html".text = "well met";
68 ${copyCert "server" "client" "/authorized-server-cert.crt"}
70 server.wait_for_unit("simple-webserver")
71 server.wait_for_unit("stunnel")
73 client.succeed("curl --fail --cacert /authorized-server-cert.crt https://server/ > out")
74 client.succeed('[[ "$(< out)" == "well met" ]]')
78 serverAndClient = makeTest {
79 name = "serverAndClient";
83 imports = [ stunnelCommon ];
84 services.stunnel.clients = {
87 connect = "server:443";
88 CAFile = "/authorized-server-cert.crt";
90 httpsClientWithHostVerify = {
92 connect = "server:443";
93 CAFile = "/authorized-server-cert.crt";
94 verifyHostname = "server";
96 httpsClientWithHostVerifyFail = {
98 connect = "server:443";
99 CAFile = "/authorized-server-cert.crt";
100 verifyHostname = "wronghostname";
105 imports = [ makeCert serverCommon stunnelCommon ];
106 environment.etc."webroot/index.html".text = "hello there";
113 ${copyCert "server" "client" "/authorized-server-cert.crt"}
115 server.wait_for_unit("simple-webserver")
116 server.wait_for_unit("stunnel")
118 # In case stunnel came up before we got the server's cert copied over
119 client.succeed("systemctl reload-or-restart stunnel")
121 client.succeed("curl --fail http://localhost/ > out")
122 client.succeed('[[ "$(< out)" == "hello there" ]]')
124 client.succeed("curl --fail http://localhost:81/ > out")
125 client.succeed('[[ "$(< out)" == "hello there" ]]')
127 client.fail("curl --fail http://localhost:82/ > out")
128 client.succeed('[[ "$(< out)" == "" ]]')
132 mutualAuth = makeTest {
137 imports = [ makeCert stunnelCommon ];
138 services.stunnel.clients.authenticated-https = {
140 connect = "server:443";
142 CAFile = "/authorized-server-cert.crt";
143 cert = "/test-cert.pem";
144 key = "/test-key.pem";
147 wrongclient = client;
149 imports = [ makeCert serverCommon stunnelCommon ];
150 services.stunnel.servers.https = {
151 CAFile = "/authorized-client-certs.crt";
154 environment.etc."webroot/index.html".text = "secret handshake";
161 ${copyCert "server" "client" "/authorized-server-cert.crt"}
162 ${copyCert "client" "server" "/authorized-client-certs.crt"}
163 ${copyCert "server" "wrongclient" "/authorized-server-cert.crt"}
165 # In case stunnel came up before we got the cross-certs in place
166 client.succeed("systemctl reload-or-restart stunnel")
167 server.succeed("systemctl reload-or-restart stunnel")
168 wrongclient.succeed("systemctl reload-or-restart stunnel")
170 server.wait_for_unit("simple-webserver")
171 client.fail("curl --fail --insecure https://server/ > out")
172 client.succeed('[[ "$(< out)" == "" ]]')
173 client.succeed("curl --fail http://localhost/ > out")
174 client.succeed('[[ "$(< out)" == "secret handshake" ]]')
175 wrongclient.fail("curl --fail http://localhost/ > out")
176 wrongclient.succeed('[[ "$(< out)" == "" ]]')