hitecture
Three system identities are required:
dev-user: The human operator. This UID retains normal desktop functionality with unrestricted egress.
egress-relay: The proxy daemon. This UID runs the inspection gateway and requires full internet access to forward agent traffic.
ai-sandbox: The agent identity. All agent processes run under this UID. Network access is restricted to loopback and local DNS.
2. Kernel Enforcement with nftables
The boundary is enforced using nftables, the modern Linux packet filtering framework. The ruleset must be applied to the output hook to control traffic originating from local processes.
File: /etc/nftables.d/99-agentguard-egress.nft
table inet agentguard_egress {
chain output_policy {
type filter hook output priority filter; policy accept;
# Allow loopback traffic for local proxy communication
oif "lo" accept
# Preserve operator desktop functionality
meta skuid 1000 accept
# Allow proxy daemon full internet access
meta skuid 988 accept
# Sandbox UID: DNS to local resolver only
meta skuid 987 udp dport 53 ip daddr 127.0.0.0/8 accept
meta skuid 987 tcp dport 53 ip daddr 127.0.0.0/8 accept
# Drop all other egress from sandbox
meta skuid 987 drop
}
}
Rationale:
inet Family: Using inet ensures the rules apply to both IPv4 and IPv6, preventing bypass via IPv6.
meta skuid: Matching on the socket UID ensures the policy applies to the process identity, not just the network interface.
- Loopback Acceptance: The agent must reach the proxy via
127.0.0.1. The oif "lo" rule permits this.
- DNS Restriction: DNS resolution is allowed only to the loopback address. This forces the agent to use the local resolver, which can be configured to forward queries through the proxy or block external resolution.
- Explicit Drop: The final rule drops all traffic from the sandbox UID that does not match previous accept rules.
3. Execution Wrapper
Operators should not manually invoke sudo to run agents. A wrapper script standardizes the execution environment, injects proxy configuration, and ensures the CA trust bundle is available.
File: /usr/local/bin/sandbox-exec
#!/usr/bin/env bash
set -euo pipefail
# Configuration
SANDBOX_UID=987
PROXY_ADDR="127.0.0.1:9090"
CA_BUNDLE="/etc/agentguard/trust-bundle.pem"
SANDBOX_HOME="/var/lib/ai-sandbox"
if [[ $# -eq 0 ]]; then
echo "Usage: sandbox-exec <command> [args...]" >&2
exit 1
fi
# Drop into sandbox identity with controlled environment
exec sudo -u ai-sandbox -- \
env \
HOME="${SANDBOX_HOME}" \
HTTPS_PROXY="http://${PROXY_ADDR}" \
HTTP_PROXY="http://${PROXY_ADDR}" \
NO_PROXY="localhost,127.0.0.0/8" \
NODE_EXTRA_CA_CERTS="${CA_BUNDLE}" \
SSL_CERT_FILE="${CA_BUNDLE}" \
REQUESTS_CA_BUNDLE="${CA_BUNDLE}" \
CURL_CA_BUNDLE="${CA_BUNDLE}" \
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
"$@"
Rationale:
- Scoped Execution: The wrapper uses
sudo -u ai-sandbox to switch identity. This is safer than running the agent as root and dropping privileges.
- Environment Injection: Proxy variables are injected directly into the execution environment. This ensures the agent cannot bypass the proxy by unsetting variables in its own shell.
- CA Bundle Injection: TLS interception requires the agent to trust the proxy's certificate authority. The wrapper points all common TLS libraries to the combined trust bundle.
- Path Restriction: The
PATH is explicitly set to prevent the agent from accessing unexpected binaries.
4. Sudoers Configuration
To allow the operator to run the wrapper without a password prompt, a scoped sudoers entry is required. This entry must restrict execution to the wrapper script only.
File: /etc/sudoers.d/50-agentguard
dev-user ALL=(ai-sandbox) NOPASSWD: /usr/local/bin/sandbox-exec *
Rationale:
- Least Privilege: The operator can only execute
sandbox-exec as ai-sandbox. Direct execution of arbitrary commands as ai-sandbox is denied.
- Wildcard Usage: The
* allows arguments to be passed to the wrapper, enabling flexible command execution.
5. CA Trust Bundle Management
If the proxy performs TLS interception, the agent must trust the proxy's CA. The trust bundle must be generated by concatenating the proxy's CA certificate with the system root certificates.
Best Practice: Automate bundle generation and distribution. Use a configuration management tool or a post-install hook to ensure the bundle is updated whenever the proxy CA rotates. The wrapper reads the bundle by path, so updates to the file are picked up automatically by subsequent executions.
Pitfall Guide
-
Proxy UID Contamination
- Explanation: Running the proxy daemon as the operator UID or the sandbox UID.
- Impact: If the proxy shares the operator UID, the firewall cannot distinguish proxy traffic from operator traffic, potentially blocking proxy egress or allowing agent egress. If the proxy shares the sandbox UID, the agent inherits proxy internet access.
- Fix: Always assign a dedicated UID to the proxy daemon.
-
DNS Leakage via External Resolvers
- Explanation: Allowing the sandbox UID to resolve DNS via external servers.
- Impact: The agent can resolve hostnames and potentially exfiltrate data via DNS queries.
- Fix: Restrict DNS traffic to the loopback interface. Configure the local resolver to forward queries through the proxy or block external resolution.
-
Stale CA Trust Bundle
- Explanation: The proxy CA rotates, but the trust bundle is not updated.
- Impact: TLS verification fails, causing HTTPS requests to error. This is often misdiagnosed as a network connectivity issue.
- Fix: Implement automated bundle refresh. Monitor proxy CA rotation events and trigger bundle regeneration.
-
Sudoers Over-Privilege
- Explanation: Granting the operator unrestricted
sudo -u ai-sandbox access.
- Impact: The operator can bypass the wrapper and execute arbitrary commands as the sandbox UID, potentially altering the environment or disabling controls.
- Fix: Scope sudoers entries to the wrapper script only. Use
NOPASSWD with caution and restrict the command path.
-
IPv6 Bypass
- Explanation: Applying
nftables rules only to the ip family.
- Impact: The agent can establish IPv6 connections, bypassing the IPv4 rules.
- Fix: Use the
inet family in nftables to cover both IPv4 and IPv6. Verify rules with nft list ruleset.
-
Wrapper Bypass via Subprocesses
- Explanation: The agent spawns a subprocess that does not inherit the wrapper's environment.
- Impact: The subprocess may run as the operator UID or bypass proxy settings.
- Fix: Ensure the wrapper sets
HOME and other environment variables to prevent the agent from detecting the sandbox. Use sudo -u to enforce identity at the kernel level.
-
Rollback Neglect
- Explanation: Failing to design a teardown procedure.
- Impact: Operators may be unable to remove the containment model, leading to system instability or security debt.
- Fix: Document and script the rollback procedure. Include steps to disable
nftables rules, remove sudoers entries, and delete system users.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Single Dev Workstation | Tri-UID + nftables | Low overhead, high security, easy to manage. | Minimal |
| CI/CD Pipeline | Container Isolation | Ephemeral environments, scalable, native isolation. | Infrastructure cost |
| Multi-Tenant Server | User Namespaces + cgroups | Stronger isolation, resource limits, auditability. | Complexity |
| Legacy System | iptables + wrapper | Compatibility with older kernels. | Maintenance burden |
Configuration Template
nftables Ruleset:
table inet agentguard_egress {
chain output_policy {
type filter hook output priority filter; policy accept;
oif "lo" accept
meta skuid 1000 accept
meta skuid 988 accept
meta skuid 987 udp dport 53 ip daddr 127.0.0.0/8 accept
meta skuid 987 tcp dport 53 ip daddr 127.0.0.0/8 accept
meta skuid 987 drop
}
}
Sudoers Entry:
dev-user ALL=(ai-sandbox) NOPASSWD: /usr/local/bin/sandbox-exec *
Quick Start Guide
-
Create Identities:
sudo useradd --system ai-sandbox
sudo useradd --system egress-relay
-
Deploy Firewall Rules:
sudo cp 99-agentguard-egress.nft /etc/nftables.d/
sudo nft -f /etc/nftables.d/99-agentguard-egress.nft
-
Install Wrapper:
sudo chmod +x /usr/local/bin/sandbox-exec
-
Apply Sudoers:
echo "dev-user ALL=(ai-sandbox) NOPASSWD: /usr/local/bin/sandbox-exec *" | sudo tee /etc/sudoers.d/50-agentguard
sudo chmod 440 /etc/sudoers.d/50-agentguard
-
Verify Containment:
# Test operator access
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/
# Test sandbox block
sudo -u ai-sandbox curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://example.com/
# Test wrapper end-to-end
sandbox-exec curl -s -o /dev/null -w '%{http_code}\n' https://example.com/
This architecture provides a robust, kernel-enforced boundary for AI agent containment. By decoupling identities and leveraging nftables, you ensure that all agent traffic is routed through the inspection proxy, mitigating the risk of data exfiltration and unauthorized access. Regular verification and automated rollback procedures are essential to maintain the integrity of the containment model.