nixos/preload: init
[NixPkgs.git] / nixos / tests / stunnel.nix
blob07fba435d4df6fa734e919414769b0d8bf5968ef
1 { system ? builtins.currentSystem, config ? { }
2 , pkgs ? import ../.. { inherit system config; } }:
4 with import ../lib/testing-python.nix { inherit system pkgs; };
5 with pkgs.lib;
7 let
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" ];
23       unitConfig.DefaultDependencies = false;
24       script = ''
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
28     '';
29     };
30   };
31   serverCommon = { pkgs, ... }: {
32     networking.firewall.allowedTCPPorts = [ 443 ];
33     services.stunnel.servers.https = {
34       accept = "443";
35       connect = 80;
36       cert = "/test-key-and-cert.pem";
37     };
38     systemd.services.simple-webserver = {
39       wantedBy = [ "multi-user.target" ];
40       script = ''
41         cd /etc/webroot
42         ${pkgs.python3}/bin/python -m http.server 80
43       '';
44     };
45   };
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))
51   '';
53 in {
54   basicServer = makeTest {
55     name = "basicServer";
57     nodes = {
58       client = { };
59       server = {
60         imports = [ makeCert serverCommon stunnelCommon ];
61         environment.etc."webroot/index.html".text = "well met";
62       };
63     };
65     testScript = ''
66       start_all()
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" ]]')
75     '';
76   };
78   serverAndClient = makeTest {
79     name = "serverAndClient";
81     nodes = {
82       client = {
83         imports = [ stunnelCommon ];
84         services.stunnel.clients = {
85           httpsClient = {
86             accept = "80";
87             connect = "server:443";
88             CAFile = "/authorized-server-cert.crt";
89           };
90           httpsClientWithHostVerify = {
91             accept = "81";
92             connect = "server:443";
93             CAFile = "/authorized-server-cert.crt";
94             verifyHostname = "server";
95           };
96           httpsClientWithHostVerifyFail = {
97             accept = "82";
98             connect = "server:443";
99             CAFile = "/authorized-server-cert.crt";
100             verifyHostname = "wronghostname";
101           };
102         };
103       };
104       server = {
105         imports = [ makeCert serverCommon stunnelCommon ];
106         environment.etc."webroot/index.html".text = "hello there";
107       };
108     };
110     testScript = ''
111       start_all()
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)" == "" ]]')
129     '';
130   };
132   mutualAuth = makeTest {
133     name = "mutualAuth";
135     nodes = rec {
136       client = {
137         imports = [ makeCert stunnelCommon ];
138         services.stunnel.clients.authenticated-https = {
139           accept = "80";
140           connect = "server:443";
141           verifyPeer = true;
142           CAFile = "/authorized-server-cert.crt";
143           cert = "/test-cert.pem";
144           key = "/test-key.pem";
145         };
146       };
147       wrongclient = client;
148       server = {
149         imports = [ makeCert serverCommon stunnelCommon ];
150         services.stunnel.servers.https = {
151           CAFile = "/authorized-client-certs.crt";
152           verifyPeer = true;
153         };
154         environment.etc."webroot/index.html".text = "secret handshake";
155       };
156     };
158     testScript = ''
159       start_all()
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)" == "" ]]')
177     '';
178   };