Skip to content

Commit 0d4d222

Browse files
authored
test: add e2e tests for certificate revocation (#1345)
## Summary - Add end-to-end tests for certificate revocation functionality - Test that a revoked client certificate cannot connect to the VPN - Test that a new certificate can be created with the same name as a revoked one (validating the fix from #1185) - Test that the new certificate can successfully connect ## Test Flow 1. **Initial connectivity tests** - existing tests pass 2. **Certificate revocation test**: - Create a new client `revoketest` - Connect with the certificate (verifies it works) - Disconnect the client - Revoke the certificate via the install script - Try to reconnect with revoked cert (verifies connection is rejected) 3. **Reuse revoked name test**: - Create a new certificate with the same name `revoketest` - Verify both revoked and valid entries exist in `index.txt` - Connect with the new certificate (verifies it works) ## Changes | File | Changes | |------|---------| | `test/server-entrypoint.sh` | Start OpenVPN in background, add revocation test orchestration | | `test/client-entrypoint.sh` | Add revocation test phases with signal file coordination | | `docker-compose.yml` | Remove read-only restriction on shared volume for client | | `Makefile` | Increase timeout from 60 to 180 iterations | | `.github/workflows/docker-test.yml` | Increase timeouts, fix shared volume |
1 parent 690414a commit 0d4d222

File tree

5 files changed

+488
-10
lines changed

5 files changed

+488
-10
lines changed

.github/workflows/docker-test.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ permissions:
1717
jobs:
1818
docker-test:
1919
runs-on: ubuntu-latest
20-
timeout-minutes: 15
20+
timeout-minutes: 20
2121
strategy:
2222
fail-fast: false
2323
matrix:
@@ -134,11 +134,12 @@ jobs:
134134
--device=/dev/net/tun:/dev/net/tun \
135135
--network vpn-test \
136136
--ip 172.28.0.20 \
137-
-v shared-config:/shared:ro \
137+
-v shared-config:/shared \
138138
openvpn-client &
139139
140140
# Wait for tests to complete (look for success message)
141-
for i in {1..60}; do
141+
# Extended timeout for revocation e2e tests
142+
for i in {1..180}; do
142143
if docker logs openvpn-client 2>&1 | grep -q "ALL TESTS PASSED"
143144
then
144145
echo "Tests passed!"
@@ -149,7 +150,7 @@ jobs:
149150
docker logs openvpn-client
150151
exit 1
151152
fi
152-
echo "Waiting for tests... ($i/60)"
153+
echo "Waiting for tests... ($i/180)"
153154
sleep 2
154155
done
155156

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Run the full test suite
44
test: test-build test-up
55
@echo "Waiting for tests to complete..."
6-
@for i in $$(seq 1 60); do \
6+
@for i in $$(seq 1 180); do \
77
if docker logs openvpn-client 2>&1 | grep -q "ALL TESTS PASSED"; then \
88
echo "✓ Tests passed!"; \
99
$(MAKE) test-down; \
@@ -15,7 +15,7 @@ test: test-build test-up
1515
$(MAKE) test-down; \
1616
exit 1; \
1717
fi; \
18-
echo "Waiting... ($$i/60)"; \
18+
echo "Waiting... ($$i/180)"; \
1919
sleep 2; \
2020
done; \
2121
echo "Timeout waiting for tests"; \

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ services:
3636
devices:
3737
- /dev/net/tun:/dev/net/tun
3838
volumes:
39-
- shared-config:/shared:ro
39+
- shared-config:/shared
4040
networks:
4141
vpn-test:
4242
ipv4_address: 172.28.0.20

test/client-entrypoint.sh

Lines changed: 256 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,265 @@ else
103103
exit 1
104104
fi
105105

106+
echo ""
107+
echo "=== Initial connectivity tests PASSED ==="
108+
109+
# Signal server that initial tests passed
110+
touch /shared/initial-tests-passed
111+
112+
# =====================================================
113+
# Certificate Revocation E2E Tests
114+
# =====================================================
115+
echo ""
116+
echo "=== Starting Certificate Revocation E2E Tests ==="
117+
118+
REVOKE_CLIENT="revoketest"
119+
120+
# Wait for revoke test client config
121+
echo "Waiting for revoke test client config..."
122+
MAX_WAIT=120
123+
WAITED=0
124+
while [ ! -f /shared/revoke-client-config-ready ] && [ $WAITED -lt $MAX_WAIT ]; do
125+
sleep 2
126+
WAITED=$((WAITED + 2))
127+
echo "Waiting for revoke test config... ($WAITED/$MAX_WAIT seconds)"
128+
done
129+
130+
if [ ! -f /shared/revoke-client-config-ready ]; then
131+
echo "FAIL: Revoke test client config not ready in time"
132+
exit 1
133+
fi
134+
135+
if [ ! -f "/shared/$REVOKE_CLIENT.ovpn" ]; then
136+
echo "FAIL: Revoke test client config file not found"
137+
exit 1
138+
fi
139+
140+
echo "Revoke test client config found!"
141+
142+
# Disconnect current VPN (testclient) before connecting with revoke test client
143+
echo "Disconnecting current VPN connection..."
144+
pkill openvpn || true
145+
sleep 2
146+
147+
# Connect with revoke test client
148+
echo "Connecting with '$REVOKE_CLIENT' certificate..."
149+
openvpn --config "/shared/$REVOKE_CLIENT.ovpn" --daemon --log /var/log/openvpn-revoke.log
150+
151+
# Wait for connection
152+
echo "Waiting for VPN connection with revoke test client..."
153+
MAX_WAIT=60
154+
WAITED=0
155+
while ! ip addr show tun0 2>/dev/null | grep -q "inet " && [ $WAITED -lt $MAX_WAIT ]; do
156+
sleep 2
157+
WAITED=$((WAITED + 2))
158+
echo "Waiting for tun0... ($WAITED/$MAX_WAIT seconds)"
159+
if [ -f /var/log/openvpn-revoke.log ]; then
160+
tail -3 /var/log/openvpn-revoke.log
161+
fi
162+
done
163+
164+
if ! ip addr show tun0 2>/dev/null | grep -q "inet "; then
165+
echo "FAIL: VPN connection with revoke test client failed"
166+
cat /var/log/openvpn-revoke.log || true
167+
exit 1
168+
fi
169+
170+
echo "PASS: Connected with '$REVOKE_CLIENT' certificate"
171+
ip addr show tun0
172+
173+
# Verify connectivity
174+
if ping -c 2 10.8.0.1 >/dev/null 2>&1; then
175+
echo "PASS: Can ping VPN gateway with revoke test client"
176+
else
177+
echo "FAIL: Cannot ping VPN gateway with revoke test client"
178+
exit 1
179+
fi
180+
181+
# Signal server that we're connected with revoke test client
182+
touch /shared/revoke-client-connected
183+
184+
# Wait for server to signal us to disconnect
185+
echo "Waiting for server to signal disconnect..."
186+
MAX_WAIT=60
187+
WAITED=0
188+
while [ ! -f /shared/revoke-client-disconnect ] && [ $WAITED -lt $MAX_WAIT ]; do
189+
sleep 2
190+
WAITED=$((WAITED + 2))
191+
done
192+
193+
if [ ! -f /shared/revoke-client-disconnect ]; then
194+
echo "FAIL: Server did not signal disconnect"
195+
exit 1
196+
fi
197+
198+
# Disconnect
199+
echo "Disconnecting revoke test client..."
200+
pkill openvpn || true
201+
202+
# Wait for openvpn to fully exit and tun0 to be released
203+
WAITED=0
204+
MAX_WAIT_DISCONNECT=10
205+
while (pgrep openvpn >/dev/null || ip addr show tun0 2>/dev/null | grep -q "inet ") && [ $WAITED -lt $MAX_WAIT_DISCONNECT ]; do
206+
sleep 1
207+
WAITED=$((WAITED + 1))
208+
done
209+
210+
# Verify disconnected
211+
if ip addr show tun0 2>/dev/null | grep -q "inet "; then
212+
echo "FAIL: tun0 still has IP after disconnect"
213+
exit 1
214+
fi
215+
echo "PASS: Disconnected successfully"
216+
217+
# Signal server that we're disconnected
218+
touch /shared/revoke-client-disconnected
219+
220+
# Wait for server to revoke the certificate and signal us to reconnect
221+
echo "Waiting for server to revoke certificate and signal reconnect..."
222+
MAX_WAIT=60
223+
WAITED=0
224+
while [ ! -f /shared/revoke-try-reconnect ] && [ $WAITED -lt $MAX_WAIT ]; do
225+
sleep 2
226+
WAITED=$((WAITED + 2))
227+
done
228+
229+
if [ ! -f /shared/revoke-try-reconnect ]; then
230+
echo "FAIL: Server did not signal to try reconnect"
231+
exit 1
232+
fi
233+
234+
# Try to reconnect with the now-revoked certificate (should fail)
235+
echo "Attempting to reconnect with revoked certificate (should fail)..."
236+
rm -f /var/log/openvpn-revoke-fail.log
237+
openvpn --config "/shared/$REVOKE_CLIENT.ovpn" --daemon --log /var/log/openvpn-revoke-fail.log
238+
239+
# Wait and check if connection fails
240+
# The connection should fail due to certificate being revoked
241+
echo "Waiting to verify connection is rejected..."
242+
CONNECT_FAILED=false
243+
MAX_WAIT=30
244+
WAITED=0
245+
while [ $WAITED -lt $MAX_WAIT ]; do
246+
sleep 2
247+
WAITED=$((WAITED + 2))
248+
249+
# Check if tun0 came up (would mean revocation didn't work)
250+
if ip addr show tun0 2>/dev/null | grep -q "inet "; then
251+
echo "FAIL: Connection succeeded with revoked certificate!"
252+
cat /var/log/openvpn-revoke-fail.log || true
253+
exit 1
254+
fi
255+
256+
# Check for certificate verification failure in log
257+
if [ -f /var/log/openvpn-revoke-fail.log ]; then
258+
if grep -qi "certificate verify failed\|TLS Error\|AUTH_FAILED\|certificate revoked" /var/log/openvpn-revoke-fail.log; then
259+
echo "Connection correctly rejected (certificate revoked)"
260+
CONNECT_FAILED=true
261+
break
262+
fi
263+
fi
264+
265+
echo "Checking connection status... ($WAITED/$MAX_WAIT seconds)"
266+
if [ -f /var/log/openvpn-revoke-fail.log ]; then
267+
tail -3 /var/log/openvpn-revoke-fail.log
268+
fi
269+
done
270+
271+
# Kill any remaining openvpn process
272+
pkill openvpn 2>/dev/null || true
273+
sleep 1
274+
275+
# Even if we didn't see explicit error, verify tun0 is not up
276+
if ip addr show tun0 2>/dev/null | grep -q "inet "; then
277+
echo "FAIL: tun0 interface exists - revoked cert may have connected"
278+
exit 1
279+
fi
280+
281+
if [ "$CONNECT_FAILED" = true ]; then
282+
echo "PASS: Connection with revoked certificate was correctly rejected"
283+
else
284+
echo "PASS: Connection with revoked certificate did not succeed (no tun0)"
285+
echo "OpenVPN log:"
286+
cat /var/log/openvpn-revoke-fail.log || true
287+
fi
288+
289+
# Signal server that reconnect with revoked cert failed
290+
touch /shared/revoke-reconnect-failed
291+
292+
# =====================================================
293+
# Test connecting with new certificate (same name)
294+
# =====================================================
295+
echo ""
296+
echo "=== Testing connection with recreated certificate ==="
297+
298+
# Wait for server to create new cert and signal us
299+
echo "Waiting for new client config with same name..."
300+
MAX_WAIT=120
301+
WAITED=0
302+
while [ ! -f /shared/new-client-config-ready ] && [ $WAITED -lt $MAX_WAIT ]; do
303+
sleep 2
304+
WAITED=$((WAITED + 2))
305+
echo "Waiting for new config... ($WAITED/$MAX_WAIT seconds)"
306+
done
307+
308+
if [ ! -f /shared/new-client-config-ready ]; then
309+
echo "FAIL: New client config not ready in time"
310+
exit 1
311+
fi
312+
313+
if [ ! -f "/shared/$REVOKE_CLIENT-new.ovpn" ]; then
314+
echo "FAIL: New client config file not found"
315+
exit 1
316+
fi
317+
318+
echo "New client config found!"
319+
320+
# Connect with the new certificate
321+
echo "Connecting with new '$REVOKE_CLIENT' certificate..."
322+
rm -f /var/log/openvpn-new.log
323+
openvpn --config "/shared/$REVOKE_CLIENT-new.ovpn" --daemon --log /var/log/openvpn-new.log
324+
325+
# Wait for connection
326+
echo "Waiting for VPN connection with new certificate..."
327+
MAX_WAIT=60
328+
WAITED=0
329+
while ! ip addr show tun0 2>/dev/null | grep -q "inet " && [ $WAITED -lt $MAX_WAIT ]; do
330+
sleep 2
331+
WAITED=$((WAITED + 2))
332+
echo "Waiting for tun0... ($WAITED/$MAX_WAIT seconds)"
333+
if [ -f /var/log/openvpn-new.log ]; then
334+
tail -3 /var/log/openvpn-new.log
335+
fi
336+
done
337+
338+
if ! ip addr show tun0 2>/dev/null | grep -q "inet "; then
339+
echo "FAIL: VPN connection with new certificate failed"
340+
cat /var/log/openvpn-new.log || true
341+
exit 1
342+
fi
343+
344+
echo "PASS: Connected with new '$REVOKE_CLIENT' certificate"
345+
ip addr show tun0
346+
347+
# Verify connectivity
348+
if ping -c 2 10.8.0.1 >/dev/null 2>&1; then
349+
echo "PASS: Can ping VPN gateway with new certificate"
350+
else
351+
echo "FAIL: Cannot ping VPN gateway with new certificate"
352+
exit 1
353+
fi
354+
355+
# Signal server that we connected with new cert
356+
touch /shared/new-client-connected
357+
358+
echo ""
359+
echo "=== Certificate Revocation E2E Tests PASSED ==="
360+
106361
echo ""
107362
echo "=========================================="
108363
echo " ALL TESTS PASSED!"
109364
echo "=========================================="
110365

111366
# Keep container running for debugging if needed
112-
exec tail -f /var/log/openvpn.log
367+
exec tail -f /var/log/openvpn-new.log 2>/dev/null || tail -f /var/log/openvpn.log 2>/dev/null || sleep infinity

0 commit comments

Comments
 (0)