blob: 20bcd700bb589fad7e8fe5a2beedbf96b55308a3 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
{ lib, hostPkgs, ... }:
{
name = "haproxy";
nodes = {
server =
{ pkgs, ... }:
{
services.haproxy = {
enable = true;
config = ''
defaults
mode http
timeout connect 10s
timeout client 10s
timeout server 10s
log /dev/log local0 debug err
option logasap
option httplog
option httpslog
backend http_server
server httpd [::1]:8000 alpn http/1.1
frontend http
bind :80
bind :443 ssl strict-sni crt /etc/ssl/fullchain.pem alpn h2,http/1.1
bind quic4@:443 ssl strict-sni crt /etc/ssl/fullchain.pem alpn h3 allow-0rtt
http-after-response add-header alt-svc 'h3=":443"; ma=60' if { ssl_fc }
http-request use-service prometheus-exporter if { path /metrics }
use_backend http_server
frontend http-cert-auth
bind :8443 ssl strict-sni crt /etc/ssl/fullchain.pem verify required ca-file /etc/ssl/cacert.crt
bind quic4@:8443 ssl strict-sni crt /etc/ssl/fullchain.pem verify required ca-file /etc/ssl/cacert.crt alpn h3
use_backend http_server
'';
};
services.httpd = {
enable = true;
virtualHosts.localhost = {
documentRoot = pkgs.writeTextDir "index.txt" "We are all good!";
adminAddr = "notme@yourhost.local";
listen = [
{
ip = "::1";
port = 8000;
}
];
};
};
networking.firewall.allowedTCPPorts = [
80
443
8443
];
networking.firewall.allowedUDPPorts = [
443
8443
];
};
client =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.curl ];
};
};
testScript = ''
import subprocess
# Helpers
def cmd(command):
print(f"+{command}")
r = subprocess.run(command, shell=True).returncode
if r != 0:
raise Exception(f"Command {command} failed with exit code {r}")
def openssl(command):
cmd(f"${lib.getExe hostPkgs.openssl} {command}")
# Generate CA.
openssl("req -new -newkey rsa:4096 -nodes -x509 -days 7 -subj '/C=ZZ/ST=Cloud/L=Unspecified/O=NixOS/OU=Tests/CN=CA Certificate' -keyout cacert.key -out cacert.crt")
# Generate and sign Server.
openssl("req -newkey rsa:4096 -nodes -subj '/CN=server/OU=Tests/O=NixOS' -keyout server.key -out server.csr")
openssl("x509 -req -in server.csr -out server.crt -CA cacert.crt -CAkey cacert.key -days 7")
cmd("cat server.crt server.key > fullchain.pem")
# Generate and sign Client.
openssl("req -newkey rsa:4096 -nodes -subj '/CN=client/OU=Tests/O=NixOS' -keyout client.key -out client.csr")
openssl("x509 -req -in client.csr -out client.crt -CA cacert.crt -CAkey cacert.key -days 7")
cmd("cat client.crt client.key > client.pem")
# Start the actual test.
start_all()
server.copy_from_host("fullchain.pem", "/etc/ssl/fullchain.pem")
server.copy_from_host("cacert.crt", "/etc/ssl/cacert.crt")
server.succeed("chmod 0644 /etc/ssl/fullchain.pem /etc/ssl/cacert.crt")
client.copy_from_host("cacert.crt", "/etc/ssl/cacert.crt")
client.copy_from_host("client.pem", "/root/client.pem")
server.wait_for_unit("multi-user.target")
server.wait_for_unit("haproxy.service")
server.wait_for_unit("httpd.service")
assert "We are all good!" in client.succeed("curl -f http://server/index.txt")
assert "haproxy_process_pool_allocated_bytes" in client.succeed("curl -f http://server/metrics")
with subtest("https"):
assert "We are all good!" in client.succeed("curl -f --cacert /etc/ssl/cacert.crt https://server/index.txt")
with subtest("https-cert-auth"):
# Client must succeed in authenticating with the right certificate.
assert "We are all good!" in client.succeed("curl -f --cacert /etc/ssl/cacert.crt --cert-type pem --cert /root/client.pem https://server:8443/index.txt")
# Client must fail without certificate.
client.fail("curl --cacert /etc/ssl/cacert.crt https://server:8443/index.txt")
with subtest("h3"):
assert "We are all good!" in client.succeed("curl -f --http3-only --cacert /etc/ssl/cacert.crt https://server/index.txt")
with subtest("h3-cert-auth"):
# Client must succeed in authenticating with the right certificate.
assert "We are all good!" in client.succeed("curl -f --http3-only --cacert /etc/ssl/cacert.crt --cert-type pem --cert /root/client.pem https://server:8443/index.txt")
# Client must fail without certificate.
client.fail("curl -f --http3-only --cacert /etc/ssl/cacert.crt https://server:8443/index.txt")
with subtest("reload"):
server.succeed("systemctl reload haproxy")
# wait some time to ensure the following request hits the reloaded haproxy
server.sleep(5)
assert "We are all good!" in client.succeed("curl -f http://server/index.txt")
'';
}
|