1{ pkgs, ... }:
2{
3 name = "ghostunnel";
4 nodes = {
5 backend =
6 { pkgs, ... }:
7 {
8 services.nginx.enable = true;
9 services.nginx.virtualHosts."backend".root = pkgs.runCommand "webroot" { } ''
10 mkdir $out
11 echo hi >$out/hi.txt
12 '';
13 networking.firewall.allowedTCPPorts = [ 80 ];
14 };
15 service =
16 { ... }:
17 {
18 services.ghostunnel.enable = true;
19 services.ghostunnel.servers."plain-old" = {
20 listen = "0.0.0.0:443";
21 cert = "/root/service-cert.pem";
22 key = "/root/service-key.pem";
23 disableAuthentication = true;
24 target = "backend:80";
25 unsafeTarget = true;
26 };
27 services.ghostunnel.servers."client-cert" = {
28 listen = "0.0.0.0:1443";
29 cert = "/root/service-cert.pem";
30 key = "/root/service-key.pem";
31 cacert = "/root/ca.pem";
32 target = "backend:80";
33 allowCN = [ "client" ];
34 unsafeTarget = true;
35 };
36 networking.firewall.allowedTCPPorts = [
37 443
38 1443
39 ];
40 };
41 client =
42 { pkgs, ... }:
43 {
44 environment.systemPackages = [
45 pkgs.curl
46 ];
47 };
48 };
49
50 testScript = ''
51
52 # prepare certificates
53
54 def cmd(command):
55 print(f"+{command}")
56 r = os.system(command)
57 if r != 0:
58 raise Exception(f"Command {command} failed with exit code {r}")
59
60 # Create CA
61 cmd("${pkgs.openssl}/bin/openssl genrsa -out ca-key.pem 4096")
62 cmd("${pkgs.openssl}/bin/openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -subj '/C=NL/ST=Zuid-Holland/L=The Hague/O=Stevige Balken en Planken B.V./OU=OpSec/CN=Certificate Authority' -out ca.pem")
63
64 # Create service
65 cmd("${pkgs.openssl}/bin/openssl genrsa -out service-key.pem 4096")
66 cmd("${pkgs.openssl}/bin/openssl req -subj '/CN=service' -sha256 -new -key service-key.pem -out service.csr")
67 cmd("echo subjectAltName = DNS:service,IP:127.0.0.1 >> extfile.cnf")
68 cmd("echo extendedKeyUsage = serverAuth >> extfile.cnf")
69 cmd("${pkgs.openssl}/bin/openssl x509 -req -days 365 -sha256 -in service.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out service-cert.pem -extfile extfile.cnf")
70
71 # Create client
72 cmd("${pkgs.openssl}/bin/openssl genrsa -out client-key.pem 4096")
73 cmd("${pkgs.openssl}/bin/openssl req -subj '/CN=client' -new -key client-key.pem -out client.csr")
74 cmd("echo extendedKeyUsage = clientAuth > extfile-client.cnf")
75 cmd("${pkgs.openssl}/bin/openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile extfile-client.cnf")
76
77 cmd("ls -al")
78
79 start_all()
80
81 # Configuration
82 service.copy_from_host("ca.pem", "/root/ca.pem")
83 service.copy_from_host("service-cert.pem", "/root/service-cert.pem")
84 service.copy_from_host("service-key.pem", "/root/service-key.pem")
85 client.copy_from_host("ca.pem", "/root/ca.pem")
86 client.copy_from_host("service-cert.pem", "/root/service-cert.pem")
87 client.copy_from_host("client-cert.pem", "/root/client-cert.pem")
88 client.copy_from_host("client-key.pem", "/root/client-key.pem")
89
90 backend.wait_for_unit("nginx.service")
91 service.wait_for_unit("multi-user.target")
92 service.wait_for_unit("multi-user.target")
93 client.wait_for_unit("multi-user.target")
94
95 # Check assumptions before the real test
96 client.succeed("bash -c 'diff <(curl -v --no-progress-meter http://backend/hi.txt) <(echo hi)'")
97
98 # Plain old simple TLS can connect, ignoring cert
99 client.succeed("bash -c 'diff <(curl -v --no-progress-meter --insecure https://service/hi.txt) <(echo hi)'")
100
101 # Plain old simple TLS provides correct signature with its cert
102 client.succeed("bash -c 'diff <(curl -v --no-progress-meter --cacert /root/ca.pem https://service/hi.txt) <(echo hi)'")
103
104 # Client can authenticate with certificate
105 client.succeed("bash -c 'diff <(curl -v --no-progress-meter --cert /root/client-cert.pem --key /root/client-key.pem --cacert /root/ca.pem https://service:1443/hi.txt) <(echo hi)'")
106
107 # Client must authenticate with certificate
108 client.fail("bash -c 'diff <(curl -v --no-progress-meter --cacert /root/ca.pem https://service:1443/hi.txt) <(echo hi)'")
109 '';
110
111 meta.maintainers = with pkgs.lib.maintainers; [
112 roberth
113 ];
114}