Metadata-Version: 2.4
Name: terok-shield
Version: 0.7.1
Summary: nftables-based egress firewalling for Podman containers
License-Expression: Apache-2.0
License-File: LICENSE
License-File: LICENSES/Apache-2.0.txt
Keywords: podman,containers,firewall,nftables,security
Author: Jiri Vyskocil
Author-email: jiri@vyskocil.com
Maintainer: Jiri Vyskocil
Maintainer-email: jiri@vyskocil.com
Requires-Python: >=3.12,<4.0
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: System :: Networking :: Firewalls
Classifier: Typing :: Typed
Requires-Dist: PyYAML (>=6.0)
Requires-Dist: pydantic (>=2.0)
Requires-Dist: terok-util (>=0.2.0,<0.3.0)
Project-URL: Changelog, https://github.com/terok-ai/terok-shield/blob/master/CHANGELOG.md
Project-URL: Documentation, https://terok-ai.github.io/terok-shield/
Project-URL: Homepage, https://terok-ai.github.io/terok-shield/
Project-URL: Issues, https://github.com/terok-ai/terok-shield/issues
Project-URL: Repository, https://github.com/terok-ai/terok-shield
Project-URL: Security, https://github.com/terok-ai/terok-shield/security/policy
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://terok-ai.github.io/terok/terok-logo-w.svg">
    <img src="https://terok-ai.github.io/terok/terok-logo-b.svg" alt="terok-shield" width="120">
  </picture>
</p>

# terok-shield

[![PyPI](https://img.shields.io/pypi/v/terok-shield)](https://pypi.org/project/terok-shield/)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![REUSE status](https://api.reuse.software/badge/github.com/terok-ai/terok-shield)](https://api.reuse.software/info/github.com/terok-ai/terok-shield)
[![codecov](https://codecov.io/gh/terok-ai/terok-shield/branch/master/graph/badge.svg?token=D74Q7lvnIF)](https://codecov.io/gh/terok-ai/terok-shield)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=terok-ai_terok-shield&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=terok-ai_terok-shield)

Default-deny egress firewall 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 and a per-packet audit entry.

<p align="center">
  <img src="https://terok-ai.github.io/terok/img/architecture.svg" alt="terok ecosystem — terok-shield is the security boundary at the bottom of the stack">
</p>

## Where it sits in the stack

terok-shield is the firewall layer of the terok ecosystem.
The hardened-Podman runtime
([terok-sandbox](https://github.com/terok-ai/terok-sandbox)) installs
the OCI hooks at setup time; the operator-in-the-loop verdict
service ([terok-clearance](https://github.com/terok-ai/terok-clearance))
mutates the live ruleset on Allow / Deny decisions.  The shield
itself is independent of all of these — it works on any rootless
Podman container, with or without the rest of terok.

## Features

- **Default-deny egress** with curated allowlists (domains and IPs)
- **Dynamic DNS allowlisting** — per-container dnsmasq with
  `--nftset` auto-populates allow sets on every DNS resolution,
  handling IP rotation at runtime; falls back to static pre-start
  resolution via `dig` or `getent` when 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

## Requirements

- Linux with nftables (`nft` binary) — tested on Fedora 43,
  Debian 12 and 13, and Ubuntu 24.04, 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

## Installation

```bash
pip install terok-shield
```

## Quick start

### 1. Choose your allowlists

terok-shield ships with several bundled profiles
(see [Allowlist Profiles](https://terok-ai.github.io/terok-shield/guide/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 in `~/.config/terok/shield/profiles` with one domain or IP per line:

e.g. `~/.config/terok/shield/profiles/my-project.txt`

```
api.example.com
cdn.example.com
203.0.113.10
```

### 2. Start a container with the shield

```bash
terok-shield run my-container -- alpine:latest sh
```

This 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:

```bash
terok-shield run my-container --profiles dev-standard my-project -- alpine:latest sh
```

### 3. Allow a domain at runtime

```bash
terok-shield allow my-container example.com
# Allowed example.com -> <resolved-ip> for my-container

terok-shield deny my-container example.com   # revoke later
```

## License

Apache-2.0 — see [LICENSES/Apache-2.0.txt](LICENSES/Apache-2.0.txt).

