python312Packages.dissect-extfs: 3.11 -> 3.12
[NixPkgs.git] / nixos / tests / stunnel.nix
blobf8cfa0414761d6ca0141e70a033a4ae00a5550bd
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" "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   '';
55 in {
56   basicServer = makeTest {
57     name = "basicServer";
59     nodes = {
60       client = { };
61       server = {
62         imports = [ makeCert serverCommon stunnelCommon ];
63         environment.etc."webroot/index.html".text = "well met";
64       };
65     };
67     testScript = ''
68       start_all()
70       ${copyCert "server" "client" "/authorized-server-cert.crt"}
72       server.wait_for_unit("simple-webserver")
73       server.wait_for_unit("stunnel")
75       client.succeed("curl --fail --cacert /authorized-server-cert.crt https://server/ > out")
76       client.succeed('[[ "$(< out)" == "well met" ]]')
77     '';
78   };
80   serverAndClient = makeTest {
81     name = "serverAndClient";
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     };
112     testScript = ''
113       start_all()
115       ${copyCert "server" "client" "/authorized-server-cert.crt"}
117       server.wait_for_unit("simple-webserver")
118       server.wait_for_unit("stunnel")
120       # In case stunnel came up before we got the server's cert copied over
121       client.succeed("systemctl reload-or-restart stunnel")
123       client.succeed("curl --fail http://localhost/ > out")
124       client.succeed('[[ "$(< out)" == "hello there" ]]')
126       client.succeed("curl --fail http://localhost:81/ > out")
127       client.succeed('[[ "$(< out)" == "hello there" ]]')
129       client.fail("curl --fail http://localhost:82/ > out")
130       client.succeed('[[ "$(< out)" == "" ]]')
131     '';
132   };
134   mutualAuth = makeTest {
135     name = "mutualAuth";
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     };
160     testScript = ''
161       start_all()
163       ${copyCert "server" "client" "/authorized-server-cert.crt"}
164       ${copyCert "client" "server" "/authorized-client-certs.crt"}
165       ${copyCert "server" "wrongclient" "/authorized-server-cert.crt"}
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")
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   };