Keep tcpdump privileged for private nonprod evidence

This commit is contained in:
2026-10-07 16:58:31 +08:00
parent 46c8d92c19
commit 2146f79dbc
2 changed files with 17 additions and 2 deletions
+4 -2
View File
@@ -80,6 +80,8 @@ esac
# "any" includes both provider SIP and the local Asterisk ExternalMedia RTP.
# Reducing it to the default-route NIC silently omits loopback media.
if [[ -z "$evidence_dir" ]]; then
# Debian's tcpdump AppArmor profile denies writes under hidden home dirs.
# Use this root-only system path unless another capture-approved path is known.
evidence_dir="/var/lib/sip-go-agent/evidence/$call_id"
fi
install -d -m 0700 "$evidence_dir"
@@ -104,7 +106,7 @@ command -v python3 >/dev/null || { echo 'python3 unavailable for SIP evidence su
# A successful one-packet probe or a timeout after opening the capture proves
# that the binary can open a raw capture socket; permission errors fail closed.
probe_status=0
timeout 2s "$tcpdump_bin" -i "$interface" -nn -c 1 -w /dev/null >/dev/null 2>"$evidence_dir/tcpdump-preflight.log" || probe_status=$?
timeout 2s "$tcpdump_bin" -Z root -i "$interface" -nn -c 1 -w /dev/null >/dev/null 2>"$evidence_dir/tcpdump-preflight.log" || probe_status=$?
if [[ "$probe_status" != 0 && "$probe_status" != 124 ]]; then
echo "tcpdump CAP_NET_RAW preflight failed: status=$probe_status" >&2
exit 1
@@ -331,7 +333,7 @@ trap cleanup EXIT
asterisk_cli "pjsip set logger on" >"$evidence_dir/pjsip-logger-on.txt" 2>&1 || { echo 'cannot enable PJSIP logger; fail-closed' >&2; exit 1; }
logger_enabled=1
"$tcpdump_bin" -i "$interface" -nn -s0 -U -w "$evidence_dir/capture.pcap" \
"$tcpdump_bin" -Z root -i "$interface" -nn -s0 -U -w "$evidence_dir/capture.pcap" \
"udp port $sip_port or (udp portrange $rtp_start-$rtp_end)" >"$evidence_dir/tcpdump.log" 2>&1 &
capture_pid=$!
sleep 1
+13
View File
@@ -11,6 +11,19 @@ import (
"time"
)
func TestNonprodCaptureKeepsWriteAccessToPrivateEvidence(t *testing.T) {
script, err := os.ReadFile("../../deploys/test/nonprod-call-evidence.sh")
if err != nil {
t.Fatal(err)
}
// Debian tcpdump drops to its unprivileged account by default. Both
// capture invocations must retain root to write inside the root-only
// evidence directory; otherwise the preflight succeeds but capture fails.
if count := strings.Count(string(script), `"$tcpdump_bin" -Z root -i "$interface"`); count != 2 {
t.Fatalf("preflight and live capture must both retain write access: found %d root-owned invocations", count)
}
}
func TestNonprodCallEvidenceFailsBeforeDialWithoutRequiredGates(t *testing.T) {
cases := []struct {
name, hour, environment, enabled, active, ari, endpoint, want string