Files
fips/testing/firewall/generate-configs.sh
Johnathan Corgan 33a2063672 Add firewall integration suite covering fips0 default-deny baseline
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.
2026-05-03 21:06:09 +00:00

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"