mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
End-to-end exercise the v0.3.0 nftables firewall baseline so the
security claim — "services on fips0 are not exposed by default" — is
validated in CI rather than by operator opt-in. The packaging postinst
state is pinned by the deb-install matrix; this suite pins the actual
ruleset behavior.
testing/firewall/ — new directory mirroring the acl-allowlist
precedent (kept in its own directory, not extending testing/static):
docker-compose.yml (52 lines): two FIPS containers on bridge
172.32.0.0/24, peered over UDP/2121. node-b mounts
packaging/common/fips.nft RO at /etc/fips/fips.nft and a generated
drop-in services.nft at /etc/fips/fips.d/.
test.sh (247 lines): four-case asserter
(a) curl from node-a to node-b:8000 → DROP (port not allowlisted;
terminal counter drop fires)
(b) curl from node-b to node-a:8000 → 200 OK (reply traverses
node-b's ct state established,related accept)
(c) ping6 a→b → success (icmpv6 echo-request accept)
(d) nc -z a→b:22 → success (drop-in tcp dport 22 accept honored
via include "/etc/fips/fips.d/*.nft")
Plus drop-counter check after case (a) confirms the dropped
connection actually hit the chain's terminal counter drop.
generate-configs.sh (111 lines): mirrors acl-allowlist generator,
produces the drop-in services.nft + fips configs.
README.md (111 lines): how to run, expected output, design notes.
.gitignore: ignores generated-configs/.
testing/ci-local.sh: FIREWALL_SUITES=(firewall) array + run_firewall
runner; dispatch in run_integration and run_suite mirroring
run_acl_allowlist.
.github/workflows/ci.yml: matrix row {suite: firewall, type:
firewall} + 3 steps gated on matrix.type == 'firewall' between
acl-allowlist and gateway. Reuses fips-linux artifact + fips-test:
latest image.
Activation note: the unified test image does not run systemd, so
test.sh invokes the fips-firewall.service ExecStart
(/usr/sbin/nft -f /etc/fips/fips.nft) directly. The systemd-unit
enablement path is covered by the deb-install matrix; this suite
exercises what the unit configures, not how it gets started.
112 lines
2.7 KiB
Bash
Executable File
112 lines
2.7 KiB
Bash
Executable File
#!/bin/bash
|
|
# Generate fixtures for the firewall integration test.
|
|
#
|
|
# Two FIPS nodes (a, b). node-b mounts the production fips.nft baseline
|
|
# plus a single drop-in (.nft) under /etc/fips/fips.d/ that allows TCP
|
|
# port 22 inbound — the test asserts this is honored. node-a is a
|
|
# probe-only node with no firewall.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
GENERATED_DIR="$SCRIPT_DIR/generated-configs"
|
|
|
|
# Deterministic test identities (mirrors the acl-allowlist style).
|
|
NPUB_A="npub1sjlh2c3x9w7kjsqg2ay080n2lff2uvt325vpan33ke34rn8l5jcqawh57m"
|
|
KEY_A="0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
|
|
|
|
NPUB_B="npub1tdwa4vjrjl33pcjdpf2t4p027nl86xrx24g4d3avg4vwvayr3g8qhd84le"
|
|
KEY_B="b102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fb0"
|
|
|
|
write_file() {
|
|
local path="$1"
|
|
mkdir -p "$(dirname "$path")"
|
|
cat > "$path"
|
|
}
|
|
|
|
write_hosts_file() {
|
|
local node="$1"
|
|
write_file "$GENERATED_DIR/$node/hosts" <<EOF
|
|
node-a $NPUB_A
|
|
node-b $NPUB_B
|
|
EOF
|
|
}
|
|
|
|
echo "Generating firewall fixtures..."
|
|
rm -rf "$GENERATED_DIR"
|
|
|
|
# ── node-a ────────────────────────────────────────────────────────────
|
|
write_file "$GENERATED_DIR/node-a/fips.yaml" <<EOF
|
|
node:
|
|
identity:
|
|
persistent: true
|
|
|
|
tun:
|
|
enabled: true
|
|
name: fips0
|
|
mtu: 1280
|
|
|
|
dns:
|
|
enabled: true
|
|
|
|
transports:
|
|
udp:
|
|
bind_addr: "0.0.0.0:2121"
|
|
|
|
peers:
|
|
- npub: "$NPUB_B"
|
|
alias: "node-b"
|
|
addresses:
|
|
- transport: udp
|
|
addr: "172.32.0.11:2121"
|
|
connect_policy: auto_connect
|
|
EOF
|
|
|
|
write_file "$GENERATED_DIR/node-a/fips.key" <<EOF
|
|
$KEY_A
|
|
EOF
|
|
|
|
# ── node-b ────────────────────────────────────────────────────────────
|
|
write_file "$GENERATED_DIR/node-b/fips.yaml" <<EOF
|
|
node:
|
|
identity:
|
|
persistent: true
|
|
|
|
tun:
|
|
enabled: true
|
|
name: fips0
|
|
mtu: 1280
|
|
|
|
dns:
|
|
enabled: true
|
|
|
|
transports:
|
|
udp:
|
|
bind_addr: "0.0.0.0:2121"
|
|
|
|
peers:
|
|
- npub: "$NPUB_A"
|
|
alias: "node-a"
|
|
addresses:
|
|
- transport: udp
|
|
addr: "172.32.0.10:2121"
|
|
connect_policy: auto_connect
|
|
EOF
|
|
|
|
write_file "$GENERATED_DIR/node-b/fips.key" <<EOF
|
|
$KEY_B
|
|
EOF
|
|
|
|
# ── node-b drop-in: allow inbound TCP/22 (Case d) ─────────────────────
|
|
# The simplest possible operator-supplied allowance, matching the
|
|
# fips.nft header example. The test asserts this rule unblocks an
|
|
# otherwise-DROP'd TCP/22 SYN.
|
|
write_file "$GENERATED_DIR/node-b/fips.d/services.nft" <<'EOF'
|
|
tcp dport 22 accept
|
|
EOF
|
|
|
|
write_hosts_file node-a
|
|
write_hosts_file node-b
|
|
|
|
echo "Firewall fixtures written to $GENERATED_DIR"
|