Skip to content

config

config

Shield configuration types, enums, and mode protocol.

Defines the vocabulary shared across the entire codebase: what a shield configuration looks like, what modes and states exist, and what contract a mode backend must satisfy.

DnsTier

Bases: Enum

DNS resolution tier for egress control.

Determines how domain-based allowlists are enforced:

Per-container dnsmasq with --nftset auto-populates nft

allow sets on every DNS query. Handles IP rotation.

DIG: Static resolution at pre-start via dig (current fallback). GETENT: Single-IP resolution via getent hosts (minimal fallback).

ShieldMode

Bases: Enum

Operating mode for the shield firewall.

Currently only HOOK is supported. Future modes (e.g. bridge) will add members here.

ShieldState

Bases: Enum

Per-container shield state, derived from the live nft ruleset.

UP: Normal enforcing mode (deny-all). DOWN: Bypass mode with private-range protection (RFC 1918 + RFC 4193). DOWN_ALL: Bypass mode without private-range protection. INACTIVE: No ruleset found (container stopped or unshielded). ERROR: Ruleset present but unrecognised.

ShieldConfig(state_dir, mode=ShieldMode.HOOK, default_profiles=('dev-standard',), loopback_ports=(), audit_enabled=True, profiles_dir=None, interactive=False) dataclass

Per-container shield configuration.

The library is a pure function of its inputs. Given a ShieldConfig with state_dir, it writes to that directory and nowhere else. No env-var reading, no config-file parsing.

AuditFileConfig

Bases: BaseModel

Audit section of config.yml.

ShieldFileConfig

Bases: BaseModel

Validated schema for config.yml.

Loaded by the CLI at startup. extra="forbid" rejects unknown keys so typos (e.g. mod: hook) produce a clear error instead of being silently ignored.

ShieldModeBackend

Bases: Protocol

Strategy protocol for shield mode implementations.

Each concrete backend (e.g. HookMode) provides the full lifecycle: per-container firewalling, live allow/deny, bypass, and preview.

pre_start(container, profiles)

Prepare for container start; return extra podman args.

Source code in src/terok_shield/common/config.py
def pre_start(self, container: str, profiles: list[str]) -> list[str]:
    """Prepare for container start; return extra podman args."""
    ...

allow_ip(container, ip)

Live-allow an IP for a running container.

Source code in src/terok_shield/common/config.py
def allow_ip(self, container: str, ip: str) -> None:
    """Live-allow an IP for a running container."""
    ...

allow_domain(domain)

Live-allow a domain (update dnsmasq config if active).

Source code in src/terok_shield/common/config.py
def allow_domain(self, domain: str) -> None:
    """Live-allow a domain (update dnsmasq config if active)."""
    ...

deny_ip(container, ip)

Live-deny an IP for a running container.

Source code in src/terok_shield/common/config.py
def deny_ip(self, container: str, ip: str) -> None:
    """Live-deny an IP for a running container."""
    ...

deny_domain(domain)

Live-deny a domain (remove from dnsmasq config if active).

Source code in src/terok_shield/common/config.py
def deny_domain(self, domain: str) -> None:
    """Live-deny a domain (remove from dnsmasq config if active)."""
    ...

list_rules(container)

Return the current nft rules for a running container.

Source code in src/terok_shield/common/config.py
def list_rules(self, container: str) -> str:
    """Return the current nft rules for a running container."""
    ...

shield_down(container, *, allow_all=False)

Switch a container to bypass mode.

Source code in src/terok_shield/common/config.py
def shield_down(self, container: str, *, allow_all: bool = False) -> None:
    """Switch a container to bypass mode."""
    ...

shield_up(container)

Restore normal deny-all mode for a container.

Source code in src/terok_shield/common/config.py
def shield_up(self, container: str) -> None:
    """Restore normal deny-all mode for a container."""
    ...

shield_state(container)

Query a container's shield state from the live ruleset.

Source code in src/terok_shield/common/config.py
def shield_state(self, container: str) -> ShieldState:
    """Query a container's shield state from the live ruleset."""
    ...

preview(*, down=False, allow_all=False)

Generate the ruleset without applying it.

Source code in src/terok_shield/common/config.py
def preview(self, *, down: bool = False, allow_all: bool = False) -> str:
    """Generate the ruleset without applying it."""
    ...

detect_dns_tier(has, dnsmasq_nftset_ok=lambda: True)

Detect the best available DNS resolution tier.

Probes for executables in priority order: dnsmasq (with nftset support) > dig > getent.

Parameters:

Name Type Description Default
has Callable[[str], bool]

Returns True if the named executable exists on PATH.

required
dnsmasq_nftset_ok Callable[[], bool]

Returns True if installed dnsmasq supports --nftset. Defaults to lambda: True (skip probe); production callers should pass a real capability check.

lambda: True
Source code in src/terok_shield/common/config.py
def detect_dns_tier(
    has: Callable[[str], bool],
    dnsmasq_nftset_ok: Callable[[], bool] = lambda: True,
) -> DnsTier:
    """Detect the best available DNS resolution tier.

    Probes for executables in priority order: dnsmasq (with nftset
    support) > dig > getent.

    Args:
        has: Returns True if the named executable exists on PATH.
        dnsmasq_nftset_ok: Returns True if installed dnsmasq supports
            ``--nftset``.  Defaults to ``lambda: True`` (skip probe);
            production callers should pass a real capability check.
    """
    if has("dnsmasq") and dnsmasq_nftset_ok():
        return DnsTier.DNSMASQ
    if has("dig"):
        return DnsTier.DIG
    return DnsTier.GETENT