Skip to content

feat(docker): enforce pinned Linux egress allowlists - #48

Merged
senamakel merged 15 commits into
epic/7328-security-busfrom
tinybox-live-allowlist-7328
Oct 23, 2026
Merged

senamakel merged 15 commits into
epic/7328-security-busfrom
tinybox-live-allowlist-7328

Conversation

@senamakel

@senamakel senamakel commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds opt-in Linux Docker allowlist enforcement using resolver-pinned host/IP/port plans. The native controller verifies a local rootful Linux Engine, installs per-box default-drop IPv4/IPv6 firewall chains before container start, pins container name resolution, and cleans owned firewall/network resources during destroy. Unknown, remote, Docker Desktop, and unsupported hosts continue to refuse allowlists.

Adds a hosted Linux connectivity proof for allowed TCP destinations, denied destinations and ports, DNS bypass attempts, IPv6, published ports, and default-Denied policy. Firewall-mutating coverage runs only on the disposable GitHub-hosted runner; it was not run on the shared host.

Updates Tokio to 1.53.3, which fixes inherited advisory RUSTSEC-2026-0386. The one existing AsyncFd use retains an explicit deprecation allowance because the workspace forbids unsafe code and passes an owned file descriptor.

This is a partial TinyBox#27 implementation. macOS and Windows enforcement and remaining backend/platform gaps are still open.

Refs tinyhumansai#27
Part of tinyhumansai/openhuman#7328

Validation

  • cargo fmt --all -- --check
  • cargo test -p tinybox-docker --locked (137 unit tests; live tests return early without the opt-in)
  • cargo test -p tinybox-host --locked (124 unit tests)
  • cargo check -p tinybox-docker --locked
  • cargo check -p tinybox-host --locked
  • cargo clippy -p tinybox-docker --all-targets --all-features -- -D warnings
  • cargo clippy -p tinybox-host --all-targets --all-features -- -D warnings
  • Local llvm-cov: tinybox-docker sandbox/mod.rs 91.7%; tinybox-host local/mod.rs 94.1%

The docker-network-live CI job runs live_network_policy_controls_host_listener_connectivity with live Docker required.

senamakel and others added 15 commits October 23, 2026 21:55
Add a recording egress controller and a test asserting that the allowlist
controller prepares the network before the container starts and cleans up
after destroy, verifying the docker argv carries the prepared network,
host mappings and dns settings.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The egress planner now normalizes resolved addresses, collapsing IPv4-mapped
IPv6 answers to IPv4 and rejecting IPv6 link-local targets that cannot carry an
interface scope, so pinned destinations are safe to install as firewall rules.
A new egress_enforcement module consumes the pinned plan, and the docs no longer
claim that allowlists are unavailable in DockerSandbox.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a HostExecutionLocation enum and an execution_location method on the
Host trait so security-sensitive controllers can require explicit local
machine attestation instead of inferring locality from a host's
registration name. Local hosts report Local, the SSH host reports Remote,
and custom hosts default to Unknown until they can attest otherwise.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
When a prepared egress network is supplied, the container now joins that
network and resolves approved hostnames through static host mappings
instead of Docker's embedded resolver, with DNS pointed at loopback so
unapproved lookups cannot reach an upstream resolver. The previous
network flags are still used when no allowlist network is present.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The Docker sandbox now accepts an optional egress controller that validates
the host and prepares filtering before a workload starts, and a host wrapper
rewrites docker invocations so they run through the controller. Allowlist
network policies are refused when no controller is installed, since the
default sandbox cannot enforce them.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The failed create attempt was moved into the map at three call sites, which
prevented the value from being used afterwards. Cloning it keeps the attempt
available for the surrounding error handling.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Extend the live Docker test suite with a focused test that proves egress, allowlist, and default-denied connectivity against a controlled host listener, and add a CI job that runs it with the live Docker opt-in enforced. The new `TINYBOX_REQUIRE_LIVE_DOCKER` gate makes the test fail loudly when the opt-in is missing instead of silently skipping.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace redundant closures with direct function references and collapse a nested conditional into a let-chain when checking retained create attempts. Add a clippy allow for the long Sandbox impl, with no change in behaviour.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace the parsed string address with an explicit IpAddr::V4 value in the recording egress controller so the test fixture no longer relies on parse and unwrap.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Hostnames with a trailing dot, such as the fully qualified form of a
domain, were not matched against the allowlist because normalization kept
the dot. Trimming trailing dots makes those names resolve to the same
entry as their dotless equivalents.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests asserting that LocalHost reports a local execution location and that the Docker ControllerHost forwards host capabilities, rejects unsupported file transfers and forwards, and passes docker commands through to the inner host.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a test that exercises reading and writing workspace files through the
local host and verifies that forwarding returns the requested address
unchanged.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The workspace file test now checks the forwarded address through the
accessor and verifies the forward is direct, rather than comparing the
returned value directly.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the lockfile to pull in tokio 1.53.3 and move the transitive
windows-sys dependency from 0.52.0 to 0.61.2.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The deprecated AsyncFd constructor is kept because the workspace forbids unsafe code, and the owned file moves directly into AsyncFd so its descriptor stays valid for the AsyncFd lifetime. An allow attribute suppresses the resulting warning.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel
senamakel merged commit 8e2abef into epic/7328-security-bus Oct 23, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant