#!/usr/bin/env bash # Enforce deny-all egress for a Docker/Compose project using DOCKER-USER chain. # Usage: COMPOSE_PROJECT=stella ./compose-egress-guard.sh # Optional env: ALLOW_RFC1918=true to allow east-west traffic inside 10/172/192 ranges. set -euo pipefail PROJECT=${COMPOSE_PROJECT:-stella} ALLOW_RFC1918=${ALLOW_RFC1918:-true} NETWORK=${COMPOSE_NETWORK:-${PROJECT}_default} chain=STELLAOPS_SEALED_${PROJECT^^} ipset_name=${PROJECT}_cidrs insert_accept() { local dest=$1 iptables -C DOCKER-USER -d "$dest" -j ACCEPT 2>/dev/null || iptables -I DOCKER-USER -d "$dest" -j ACCEPT } # 1) Ensure DOCKER-USER exists iptables -nL DOCKER-USER >/dev/null 2>&1 || iptables -N DOCKER-USER # 2) Create dedicated chain per project for clarity iptables -nL "$chain" >/dev/null 2>&1 || iptables -N "$chain" # 2b) Populate ipset with compose network CIDRs (if available) if command -v ipset >/dev/null; then ipset list "$ipset_name" >/dev/null 2>&1 || ipset create "$ipset_name" hash:net -exist cidrs=$(docker network inspect "$NETWORK" -f '{{range .IPAM.Config}}{{.Subnet}} {{end}}') for cidr in $cidrs; do ipset add "$ipset_name" "$cidr" 2>/dev/null || true done fi # 3) Allow loopback and optional RFC1918 intra-cluster ranges, then drop everything else insert_accept 127.0.0.0/8 if [[ "$ALLOW_RFC1918" == "true" ]]; then insert_accept 10.0.0.0/8 insert_accept 172.16.0.0/12 insert_accept 192.168.0.0/16 fi iptables -C "$chain" -j DROP 2>/dev/null || iptables -A "$chain" -j DROP # 4) Hook chain into DOCKER-USER for containers in this project network iptables -C DOCKER-USER -m addrtype --src-type LOCAL -j RETURN 2>/dev/null || true if command -v ipset >/dev/null && ipset list "$ipset_name" >/dev/null 2>&1; then iptables -C DOCKER-USER -m set --match-set "$ipset_name" dst -j "$chain" 2>/dev/null || iptables -I DOCKER-USER -m set --match-set "$ipset_name" dst -j "$chain" else # Fallback: match by destination subnet from docker inspect (first subnet only) first_cidr=$(docker network inspect "$NETWORK" -f '{{(index .IPAM.Config 0).Subnet}}') iptables -C DOCKER-USER -d "$first_cidr" -j "$chain" 2>/dev/null || iptables -I DOCKER-USER -d "$first_cidr" -j "$chain" fi echo "Applied compose egress guard via DOCKER-USER -> $chain" >&2 iptables -vnL "$chain"