nftables-based egress firewalling for rootless Podman containers.
terok-shield enforces default-deny outbound network filtering on Podman containers using nftables. Containers can only reach explicitly allowed destinations — everything else is rejected with an ICMP error.
- Default-deny egress with curated allowlists (domains and IPs)
- Dynamic DNS allowlisting — per-container dnsmasq with
--nftsetauto-populates allow sets on every DNS resolution, handling IP rotation at runtime; falls back to static pre-start resolution viadigorgetentwhen dnsmasq is unavailable - Live allow/deny at runtime for individual containers
- Per-container isolation — each container gets its own state bundle, hooks, and audit log
- Connection audit logging (JSON-lines lifecycle logs + kernel-level per-packet nftables logs)
- Fail-closed: hook failure prevents the container from starting
- Linux with nftables (
nftbinary)- Tested on Fedora 43, Debian 12 and 13, and Ubuntu 24.04, probably also works on other modern Linux distros.
- Podman (rootless, recommended > 5.6.0, untested < 4.3.1)
- Python 3.12+
dnsmasq(recommended) for dynamic DNS-based egress control;dig(dnsutils/bind-utils) as fallback
pip install terok-shieldterok-shield ships with several bundled profiles (see Allowlist Profiles):
| Profile | Domains |
|---|---|
base |
DNS roots, NTP, OCSP, OS package repos |
dev-standard |
GitHub, Docker Hub, PyPI, npm, crates.io, Go |
dev-python |
Conda, Read the Docs, Python docs |
dev-node |
Yarn, jsDelivr, unpkg |
nvidia-hpc |
CUDA, NGC, NVIDIA drivers |
The default profile is dev-standard. To add a custom allowlist, create a
.txt file with one domain or IP per line:
mkdir -p ~/.config/terok/shield/profiles
cat > ~/.config/terok/shield/profiles/my-project.txt << 'EOF'
api.example.com
cdn.example.com
203.0.113.10
EOFterok-shield run my-container -- alpine:latest shThis resolves DNS, installs OCI hooks, and launches the container with a
default-deny firewall — only destinations in the dev-standard profile are
reachable. To use custom profiles:
terok-shield run my-container --profiles dev-standard my-project -- alpine:latest shterok-shield allow my-container example.com
# Allowed example.com -> <resolved-ip> for my-container
terok-shield deny my-container example.com # revoke later- User Guide — getting started, allowlist profiles, firewall modes, CLI reference
- Developer Guide — contributing, security model, architecture
Apache-2.0 — see LICENSES/Apache-2.0.txt.