projects/guix·blob master · refs

326 lines · 10.6 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2022 muradm <[email protected]>
3;;; Copyright © 2025 Danny Milosavljevic <[email protected]>
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (gnu tests security)
21 #:use-module (guix gexp)
22 #:use-module (gnu packages admin)
23 #:use-module (gnu packages linux)
24 #:use-module (gnu services)
25 #:use-module (gnu services base)
26 #:use-module (gnu services opensnitch)
27 #:use-module (gnu services security)
28 #:use-module (gnu services ssh)
29 #:use-module (gnu system)
30 #:use-module (gnu system vm)
31 #:use-module (gnu tests)
32 #:export (%test-fail2ban-basic
33 %test-fail2ban-extension
34 %test-fail2ban-simple
35 %test-opensnitch))
36
37
38;;;
39;;; fail2ban tests
40;;;
41
42(define-syntax-rule (fail2ban-test test-name test-os tests-more ...)
43 (lambda ()
44 (define os
45 (marionette-operating-system
46 test-os
47 #:imported-modules '((gnu services herd))))
48
49 (define vm
50 (virtual-machine
51 (operating-system os)
52 (port-forwardings '())))
53
54 (define test
55 (with-imported-modules '((gnu build marionette)
56 (guix build utils))
57 #~(begin
58 (use-modules (srfi srfi-64)
59 (gnu build marionette))
60
61 (define marionette (make-marionette (list #$vm)))
62
63 (test-runner-current (system-test-runner #$output))
64 (test-begin test-name)
65
66 (test-assert "fail2ban running"
67 (marionette-eval
68 '(begin
69 (use-modules (gnu services herd))
70 (start-service 'fail2ban))
71 marionette))
72
73 (test-assert "fail2ban socket ready"
74 (wait-for-unix-socket
75 "/var/run/fail2ban/fail2ban.sock" marionette))
76
77 (test-assert "fail2ban running after restart"
78 (marionette-eval
79 '(begin
80 (use-modules (gnu services herd))
81 (restart-service 'fail2ban))
82 marionette))
83
84 (test-assert "fail2ban socket ready after restart"
85 (wait-for-unix-socket
86 "/var/run/fail2ban/fail2ban.sock" marionette))
87
88 (test-assert "fail2ban pid ready"
89 (marionette-eval
90 '(file-exists? "/var/run/fail2ban/fail2ban.pid")
91 marionette))
92
93 (test-assert "fail2ban log file"
94 (marionette-eval
95 '(file-exists? "/var/log/fail2ban.log")
96 marionette))
97
98 tests-more ...
99
100 (test-end))))
101
102 (gexp->derivation test-name test)))
103
104;; The /var/log/secure file that is monitored by fail2ban has to be present
105;; before the service starts. This limitation is discussed here:
106;; https://github.com/fail2ban/fail2ban/issues/1593.
107(define %auth-log-activation-service
108 (simple-service 'create-authlog-file
109 activation-service-type
110 #~(begin
111 (call-with-output-file "/var/log/secure"
112 (lambda (port)
113 (display "" port))))))
114
115(define run-fail2ban-basic-test
116 (fail2ban-test
117 "fail2ban-basic-test"
118
119 (simple-operating-system
120 (service fail2ban-service-type))))
121
122(define %test-fail2ban-basic
123 (system-test
124 (name "fail2ban-basic")
125 (description "Test basic fail2ban running capability.")
126 (value (run-fail2ban-basic-test))))
127
128(define %fail2ban-server-cmd
129 (program-file
130 "fail2ban-server-cmd"
131 #~(begin
132 (let ((cmd #$(file-append fail2ban "/bin/fail2ban-server")))
133 (apply execl cmd cmd `("-p" "/var/run/fail2ban/fail2ban.pid"
134 "-s" "/var/run/fail2ban/fail2ban.sock"
135 ,@(cdr (program-arguments))))))))
136
137(define run-fail2ban-simple-test
138 (fail2ban-test
139 "fail2ban-simple-test"
140
141 (simple-operating-system
142 %auth-log-activation-service
143 (service fail2ban-service-type
144 (fail2ban-configuration
145 (jails (list (fail2ban-jail-configuration
146 (name "sshd")))))))
147
148 (test-equal "fail2ban sshd jail running status output"
149 '("Status for the jail: sshd"
150 "|- Filter"
151 "| |- Currently failed:\t0"
152 "| |- Total failed:\t0"
153 "| `- File list:\t/var/log/secure"
154 "`- Actions"
155 " |- Currently banned:\t0"
156 " |- Total banned:\t0"
157 " `- Banned IP list:\t"
158 "")
159 (marionette-eval
160 '(begin
161 (use-modules (ice-9 rdelim) (ice-9 popen) (rnrs io ports))
162 (let ((call-command
163 (lambda (cmd)
164 (let* ((err-cons (pipe))
165 (port (with-error-to-port (cdr err-cons)
166 (lambda () (open-input-pipe cmd))))
167 (_ (setvbuf (car err-cons) 'block
168 (* 1024 1024 16)))
169 (result (read-delimited "" port)))
170 (close-port (cdr err-cons))
171 (values result (read-delimited "" (car err-cons)))))))
172 (string-split
173 (call-command
174 (string-join (list #$%fail2ban-server-cmd "status" "sshd") " "))
175 #\newline)))
176 marionette))
177
178 (test-equal "fail2ban sshd jail running exit code"
179 0
180 (marionette-eval
181 '(status:exit-val (system* #$%fail2ban-server-cmd "status" "sshd"))
182 marionette))))
183
184(define %test-fail2ban-simple
185 (system-test
186 (name "fail2ban-simple")
187 (description "Test simple fail2ban running capability.")
188 (value (run-fail2ban-simple-test))))
189
190(define run-fail2ban-extension-test
191 (fail2ban-test
192 "fail2ban-extension-test"
193
194 (simple-operating-system
195 %auth-log-activation-service
196 (service (fail2ban-jail-service openssh-service-type
197 (fail2ban-jail-configuration
198 (name "sshd")
199 (enabled? #t)))
200 (openssh-configuration))
201 (service static-networking-service-type
202 (list %qemu-static-networking)))
203
204 (test-equal "fail2ban sshd jail running status output"
205 '("Status for the jail: sshd"
206 "|- Filter"
207 "| |- Currently failed:\t0"
208 "| |- Total failed:\t0"
209 "| `- File list:\t/var/log/secure"
210 "`- Actions"
211 " |- Currently banned:\t0"
212 " |- Total banned:\t0"
213 " `- Banned IP list:\t"
214 "")
215 (marionette-eval
216 '(begin
217 (use-modules (ice-9 rdelim) (ice-9 popen) (rnrs io ports))
218 (let ((call-command
219 (lambda (cmd)
220 (let* ((err-cons (pipe))
221 (port (with-error-to-port (cdr err-cons)
222 (lambda () (open-input-pipe cmd))))
223 (_ (setvbuf (car err-cons) 'block
224 (* 1024 1024 16)))
225 (result (read-delimited "" port)))
226 (close-port (cdr err-cons))
227 (values result (read-delimited "" (car err-cons)))))))
228 (string-split
229 (call-command
230 (string-join (list #$%fail2ban-server-cmd "status" "sshd") " "))
231 #\newline)))
232 marionette))
233
234 (test-equal "fail2ban sshd jail running exit code"
235 0
236 (marionette-eval
237 '(status:exit-val (system* #$%fail2ban-server-cmd "status" "sshd"))
238 marionette))))
239
240(define %test-fail2ban-extension
241 (system-test
242 (name "fail2ban-extension")
243 (description "Test extension fail2ban running capability.")
244 (value (run-fail2ban-extension-test))))
245
246
247;;;
248;;; OpenSnitch tests
249;;;
250
251(define (run-opensnitch-test)
252 (define os
253 (marionette-operating-system
254 (simple-operating-system
255 (service opensnitch-service-type)
256 (service static-networking-service-type
257 (list %qemu-static-networking)))
258 #:imported-modules '((gnu services herd))))
259
260 (define vm
261 (virtual-machine
262 (operating-system os)
263 (port-forwardings '())))
264
265 (define test
266 (with-imported-modules '((gnu build marionette)
267 (guix build utils))
268 #~(begin
269 (use-modules (srfi srfi-64)
270 (gnu build marionette))
271
272 (define marionette (make-marionette (list #$vm)))
273
274 (test-runner-current (system-test-runner #$output))
275 (test-begin "opensnitch")
276
277 (test-assert "opensnitch running"
278 (marionette-eval
279 '(begin
280 (use-modules (gnu services herd))
281 (start-service 'opensnitch))
282 marionette))
283
284 (test-assert "opensnitch log file"
285 (marionette-eval
286 '(file-exists? "/var/log/opensnitchd.log")
287 marionette))
288
289 (test-assert "opensnitch rules directory"
290 (marionette-eval
291 '(file-exists? "/etc/opensnitchd/rules")
292 marionette))
293
294 (test-assert "opensnitch process running"
295 (marionette-eval
296 `(zero? (system* ,#$(file-append procps "/bin/pgrep")
297 "-x" "opensnitchd"))
298 marionette))
299
300 (test-assert "opensnitch running after restart"
301 (marionette-eval
302 '(begin
303 (use-modules (gnu services herd))
304 (restart-service 'opensnitch))
305 marionette))
306
307 (test-assert "opensnitch process running after restart"
308 (marionette-eval
309 `(let loop ((tries 0))
310 (if (zero? (system* ,#$(file-append procps "/bin/pgrep")
311 "-x" "opensnitchd"))
312 #t
313 (if (< tries 30)
314 (begin (sleep 1) (loop (+ tries 1)))
315 #f)))
316 marionette))
317
318 (test-end))))
319
320 (gexp->derivation "opensnitch-test" test))
321
322(define %test-opensnitch
323 (system-test
324 (name "opensnitch")
325 (description "Test OpenSnitch application firewall daemon.")
326 (value (run-opensnitch-test))))