Add packet-level access policy tests

This commit is contained in:
Stanislas Lange
2026-08-02 16:10:53 +02:00
parent 3274915ac7
commit 5f69ddadd8
6 changed files with 186 additions and 19 deletions
+2 -1
View File
@@ -19,7 +19,8 @@ RUN mkdir -p /dev/net
# Copy test scripts
COPY test/client-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
COPY test/policy-peer-entrypoint.sh /policy-peer-entrypoint.sh
RUN chmod +x /entrypoint.sh /policy-peer-entrypoint.sh
WORKDIR /etc/openvpn
+1 -1
View File
@@ -80,7 +80,7 @@ RUN printf '%s\n' \
'[Service]' \
'Type=oneshot' \
'Environment=HOME=/root' \
'PassEnvironment=AUTH_MODE TLS_SIG TLS_KEY_FILE TLS_VERSION_MIN TLS13_CIPHERSUITES CLIENT_IPV6 VPN_SUBNET_IPV6 ROUTE_INTERNET CLIENT_TO_CLIENT LOCAL_NETWORKS WAIT_TIMEOUT_SIGNAL WAIT_TIMEOUT_CONNECT WAIT_TIMEOUT_REVOKE' \
'PassEnvironment=AUTH_MODE TLS_SIG TLS_KEY_FILE TLS_VERSION_MIN TLS13_CIPHERSUITES CLIENT_IPV6 VPN_SUBNET_IPV6 ROUTE_INTERNET CLIENT_TO_CLIENT LOCAL_NETWORKS POLICY_E2E WAIT_TIMEOUT_SIGNAL WAIT_TIMEOUT_CONNECT WAIT_TIMEOUT_REVOKE' \
'WorkingDirectory=/root' \
'ExecStart=/entrypoint.sh' \
'RemainAfterExit=yes' \
+58 -3
View File
@@ -264,11 +264,66 @@ if [ "${CLIENT_IPV6:-n}" = "y" ]; then
fi
fi
# Test 4: DNS resolution through Unbound in full-tunnel mode.
# Packet-level access policy tests use a second VPN client and a LAN-only host.
if [ -n "${POLICY_E2E:-}" ]; then
echo "Test 4: Checking packet-level access policy..."
wait_for_file /shared/policy-peer-ip "policy peer VPN address"
POLICY_PEER_IP=$(cat /shared/policy-peer-ip)
POLICY_LAN_IP="${POLICY_LAN_IP:-10.55.0.20}"
if [ "$POLICY_E2E" = "allow" ]; then
if ping -c 3 -W 2 "$POLICY_PEER_IP" >/dev/null; then
echo "PASS: Client-to-client packets are allowed"
else
echo "FAIL: Cannot reach allowed VPN peer $POLICY_PEER_IP"
exit 1
fi
if ping -c 3 -W 2 "$POLICY_LAN_IP" >/dev/null; then
echo "PASS: LAN packets and destination-scoped NAT work"
else
echo "FAIL: Cannot reach allowed LAN host $POLICY_LAN_IP"
exit 1
fi
elif [ "$POLICY_E2E" = "deny" ]; then
if ping -c 1 -W 2 "$POLICY_PEER_IP" >/dev/null; then
echo "FAIL: Isolated VPN peer $POLICY_PEER_IP is reachable"
exit 1
fi
echo "PASS: Client-to-client packets are blocked"
if ping -c 1 -W 2 "$POLICY_LAN_IP" >/dev/null; then
echo "FAIL: Unexposed LAN host $POLICY_LAN_IP is reachable"
exit 1
fi
echo "PASS: Unexposed LAN packets are blocked"
else
echo "FAIL: Unknown POLICY_E2E value: $POLICY_E2E"
exit 1
fi
if [ "${ROUTE_INTERNET:-y}" = "y" ]; then
PUBLIC_DNS_OUTPUT=""
for _ in $(seq 1 5); do
PUBLIC_DNS_OUTPUT=$(dig @1.1.1.1 example.com +short +tcp +time=5 +tries=1 2>&1) || true
if grep -qE '^[0-9]+(\.[0-9]+){3}$' <<<"$PUBLIC_DNS_OUTPUT"; then
break
fi
PUBLIC_DNS_OUTPUT=""
sleep 2
done
if [ -n "$PUBLIC_DNS_OUTPUT" ]; then
echo "PASS: Direct internet packets traverse VPN forwarding and NAT"
else
echo "FAIL: Direct public DNS query through the VPN failed"
exit 1
fi
fi
fi
# Test 5: DNS resolution through Unbound in full-tunnel mode.
if [ "${ROUTE_INTERNET:-y}" = "y" ]; then
test_dns_resolution "Test 4"
test_dns_resolution "Test 5"
else
echo "Test 4: SKIP: VPN DNS is disabled in split-tunnel mode"
echo "Test 5: SKIP: VPN DNS is disabled in split-tunnel mode"
fi
echo ""
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
set -e
WAIT_TIMEOUT="${WAIT_TIMEOUT:-120}"
elapsed=0
while [ ! -f /shared/policy-peer.ovpn ]; do
if [ "$elapsed" -ge "$WAIT_TIMEOUT" ]; then
echo "FAIL: Timed out waiting for peer client configuration"
exit 1
fi
echo "Waiting for peer client configuration... (${elapsed}/${WAIT_TIMEOUT}s)"
sleep 2
elapsed=$((elapsed + 2))
done
openvpn --config /shared/policy-peer.ovpn --daemon --log /var/log/openvpn-policy-peer.log
elapsed=0
until ip -4 addr show tun0 2>/dev/null | grep -q 'inet '; do
if [ "$elapsed" -ge "$WAIT_TIMEOUT" ]; then
echo "FAIL: Timed out waiting for peer VPN connection"
cat /var/log/openvpn-policy-peer.log 2>/dev/null || true
exit 1
fi
echo "Waiting for peer VPN connection... (${elapsed}/${WAIT_TIMEOUT}s)"
sleep 2
elapsed=$((elapsed + 2))
done
PEER_IP=$(ip -4 -o addr show tun0 | awk '{print $4}' | cut -d/ -f1)
printf '%s\n' "$PEER_IP" >/shared/policy-peer-ip
echo "Policy peer connected with VPN address $PEER_IP"
exec tail -f /var/log/openvpn-policy-peer.log
+19 -8
View File
@@ -77,6 +77,7 @@ export VPN_GATEWAY
ROUTE_INTERNET="${ROUTE_INTERNET:-y}"
CLIENT_TO_CLIENT="${CLIENT_TO_CLIENT:-n}"
LOCAL_NETWORKS="${LOCAL_NETWORKS:-}"
POLICY_E2E="${POLICY_E2E:-}"
# IPv6 configuration (optional)
# CLIENT_IPV6: y/n to enable IPv6 for VPN clients
@@ -341,6 +342,17 @@ else
exit 1
fi
if [ -n "$POLICY_E2E" ]; then
echo "Creating second VPN client for packet-level policy tests..."
bash /opt/openvpn-install.sh client add policy-peer --cert-days 3650
if [ ! -f /root/policy-peer.ovpn ]; then
echo "FAIL: Policy peer client configuration was not generated"
exit 1
fi
cp /root/policy-peer.ovpn /shared/policy-peer.ovpn
sed -i 's/^remote .*/remote openvpn-server 1194/' /shared/policy-peer.ovpn
fi
# Copy client config to shared volume for initial connectivity tests
cp /root/testclient.ovpn /shared/client.ovpn
sed -i 's/^remote .*/remote openvpn-server 1194/' /shared/client.ovpn
@@ -1049,10 +1061,8 @@ echo "=== Certificate Revocation Tests PASSED ==="
echo ""
echo "=== Testing List Client Certificates ==="
# At this point we have 3 client certificates:
# - testclient (Valid) - the renewed certificate
# - testclient (Revoked) - the old certificate revoked during renewal
# - revoketest (Revoked) - the revoked certificate
# At this point PKI mode has three lifecycle-test certificates, plus the
# optional policy peer used by packet-level access tests.
LIST_OUTPUT="/tmp/list-clients-output.log"
(bash /opt/openvpn-install.sh client list) 2>&1 | tee "$LIST_OUTPUT" || true
@@ -1075,8 +1085,9 @@ fi
# Verify certificate count (varies by auth mode)
if [ "$AUTH_MODE" = "pki" ]; then
# PKI mode: 3 certs (testclient valid, testclient revoked from renewal, revoketest revoked)
if grep -q "Found 3 client certificate(s)" "$LIST_OUTPUT"; then
EXPECTED_CLIENT_COUNT=3
[ -n "$POLICY_E2E" ] && EXPECTED_CLIENT_COUNT=4
if grep -q "Found $EXPECTED_CLIENT_COUNT client certificate(s)" "$LIST_OUTPUT"; then
echo "PASS: List shows correct certificate count"
else
echo "FAIL: List does not show correct certificate count"
@@ -1112,10 +1123,10 @@ fi
# Verify client count in JSON (varies by auth mode)
JSON_CLIENT_COUNT=$(jq '.clients | length' "$LIST_JSON_OUTPUT")
if [ "$AUTH_MODE" = "pki" ]; then
if [ "$JSON_CLIENT_COUNT" -eq 3 ]; then
if [ "$JSON_CLIENT_COUNT" -eq "$EXPECTED_CLIENT_COUNT" ]; then
echo "PASS: Client list JSON has correct count ($JSON_CLIENT_COUNT)"
else
echo "FAIL: Client list JSON has wrong count: $JSON_CLIENT_COUNT (expected 3)"
echo "FAIL: Client list JSON has wrong count: $JSON_CLIENT_COUNT (expected $EXPECTED_CLIENT_COUNT)"
cat "$LIST_JSON_OUTPUT"
exit 1
fi