1{ runTest, pkgs, ... }:
2
3let
4 mkSpec =
5 {
6 host,
7 service ? null,
8 action,
9 }:
10 {
11 inherit action;
12 authority = {
13 file = {
14 group = "nginx";
15 owner = "nginx";
16 path = "/var/ssl/${host}-ca.pem";
17 };
18 label = "www_ca";
19 profile = "three-month";
20 remote = "localhost:8888";
21 };
22 certificate = {
23 group = "nginx";
24 owner = "nginx";
25 path = "/var/ssl/${host}-cert.pem";
26 };
27 private_key = {
28 group = "nginx";
29 mode = "0600";
30 owner = "nginx";
31 path = "/var/ssl/${host}-key.pem";
32 };
33 request = {
34 CN = host;
35 hosts = [
36 host
37 "www.${host}"
38 ];
39 key = {
40 algo = "rsa";
41 size = 2048;
42 };
43 names = [
44 {
45 C = "US";
46 L = "San Francisco";
47 O = "Example, LLC";
48 ST = "CA";
49 }
50 ];
51 };
52 inherit service;
53 };
54
55 mkCertmgrTest =
56 {
57 svcManager,
58 specs,
59 testScript,
60 }:
61 runTest {
62 name = "certmgr-" + svcManager;
63 nodes = {
64 machine =
65 {
66 config,
67 lib,
68 pkgs,
69 ...
70 }:
71 {
72 networking.firewall.allowedTCPPorts = with config.services; [
73 cfssl.port
74 certmgr.metricsPort
75 ];
76 networking.extraHosts = "127.0.0.1 imp.example.org decl.example.org";
77
78 services.cfssl.enable = true;
79 systemd.services.cfssl.after = [
80 "cfssl-init.service"
81 "networking.target"
82 ];
83
84 systemd.tmpfiles.rules = [ "d /var/ssl 777 root root" ];
85
86 systemd.services.cfssl-init = {
87 description = "Initialize the cfssl CA";
88 wantedBy = [ "multi-user.target" ];
89 serviceConfig = {
90 User = "cfssl";
91 Type = "oneshot";
92 WorkingDirectory = config.services.cfssl.dataDir;
93 };
94 script = ''
95 ${pkgs.cfssl}/bin/cfssl genkey -initca ${
96 pkgs.writeText "ca.json" (
97 builtins.toJSON {
98 hosts = [ "ca.example.com" ];
99 key = {
100 algo = "rsa";
101 size = 4096;
102 };
103 names = [
104 {
105 C = "US";
106 L = "San Francisco";
107 O = "Internet Widgets, LLC";
108 OU = "Certificate Authority";
109 ST = "California";
110 }
111 ];
112 }
113 )
114 } | ${pkgs.cfssl}/bin/cfssljson -bare ca
115 '';
116 };
117
118 services.nginx = {
119 enable = true;
120 virtualHosts = lib.mkMerge (
121 map
122 (host: {
123 ${host} = {
124 sslCertificate = "/var/ssl/${host}-cert.pem";
125 sslCertificateKey = "/var/ssl/${host}-key.pem";
126 extraConfig = ''
127 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
128 '';
129 onlySSL = true;
130 serverName = host;
131 root = pkgs.writeTextDir "index.html" "It works!";
132 };
133 })
134 [
135 "imp.example.org"
136 "decl.example.org"
137 ]
138 );
139 };
140
141 systemd.services.nginx.wantedBy = lib.mkForce [ ];
142
143 systemd.services.certmgr.after = [ "cfssl.service" ];
144 services.certmgr = {
145 enable = true;
146 inherit svcManager;
147 inherit specs;
148 };
149
150 };
151 };
152 inherit testScript;
153 };
154in
155{
156 systemd = mkCertmgrTest {
157 svcManager = "systemd";
158 specs = {
159 decl = mkSpec {
160 host = "decl.example.org";
161 service = "nginx";
162 action = "restart";
163 };
164 imp = toString (
165 pkgs.writeText "test.json" (
166 builtins.toJSON (mkSpec {
167 host = "imp.example.org";
168 service = "nginx";
169 action = "restart";
170 })
171 )
172 );
173 };
174 testScript = ''
175 machine.wait_for_unit("cfssl.service")
176 machine.wait_until_succeeds("ls /var/ssl/decl.example.org-ca.pem")
177 machine.wait_until_succeeds("ls /var/ssl/decl.example.org-key.pem")
178 machine.wait_until_succeeds("ls /var/ssl/decl.example.org-cert.pem")
179 machine.wait_until_succeeds("ls /var/ssl/imp.example.org-ca.pem")
180 machine.wait_until_succeeds("ls /var/ssl/imp.example.org-key.pem")
181 machine.wait_until_succeeds("ls /var/ssl/imp.example.org-cert.pem")
182 machine.wait_for_unit("nginx.service")
183 assert 1 < int(machine.succeed('journalctl -u nginx | grep "Starting Nginx" | wc -l'))
184 machine.succeed("curl --cacert /var/ssl/imp.example.org-ca.pem https://imp.example.org")
185 machine.succeed(
186 "curl --cacert /var/ssl/decl.example.org-ca.pem https://decl.example.org"
187 )
188 '';
189 };
190
191 command = mkCertmgrTest {
192 svcManager = "command";
193 specs = {
194 test = mkSpec {
195 host = "command.example.org";
196 action = "touch /tmp/command.executed";
197 };
198 };
199 testScript = ''
200 machine.wait_for_unit("cfssl.service")
201 machine.wait_until_succeeds("stat /tmp/command.executed")
202 '';
203 };
204
205}