AWS Network Firewall: Egress Filtering for Coding-Agent Sandboxes

0 views

Your coding-agent sandbox just curl’d an attacker-controlled URL from a poisoned README, uploaded the monorepo tarball, and still passed unit tests. Open NAT gateways are the default for “make npm install work” — and the default blast radius when a tool is jailbroken. AWS Network Firewall is the unfair advantage for agent sandboxes: managed Suricata inspection on the egress path, domain allowlists, and centralized deny rules without rewriting every task definition. Pair with PrivateLink for Bedrock so model calls never need the internet, and CodeArtifact so packages never need npmjs.org — this post is the egress filter layer.

⚡ TL;DR: Route sandbox subnet egress through Network Firewall with deny-by-default + allowlist for git forges, CodeArtifact, and approved APIs. Keep Bedrock on PrivateLink (no NAT). Log matches to S3/CloudWatch; alert on blocked C2-shaped traffic. Related: Fargate Spot sandboxes, WAF rate-limits, SCPs, Secrets Manager.

Why sandbox egress is different from app egress

App backends usually need a predictable set of SaaS APIs. Coding-agent sandboxes:

  1. Clone arbitrary customer repos (git over HTTPS/SSH)
  2. Install packages (npm/pip/maven — ideally mirrored)
  3. Call model/tool APIs inside your VPC
  4. Are prompt-injection targets — they will try surprise destinations

Security groups alone cannot filter by domain. NACLs are too coarse. Network Firewall inspects L3–L7 on the path from sandbox subnets to the internet (or to other VPCs).

Control Domain allowlist TLS SNI / HTTP host Central policy Agent fit
Security groups ❌ ❌ Per-ENI Baseline only
NAT + SG ❌ ❌ Weak Default footgun
Network Firewall ✅ ✅ Suricata ✅ Sandbox egress
PrivateLink only N/A N/A Per-service Prefer for AWS APIs
Squid on EC2 ✅ DIY ✅ DIY Ops heavy Legacy

Reference architecture for agent sandboxes

  • Sandbox subnets (Fargate Spot / CodeBuild / Batch): no IGW route; 0.0.0.0/0 → Firewall endpoint
  • Firewall subnets: Network Firewall endpoints
  • Egress subnets: NAT Gateway only after Firewall allow
  • AWS APIs: Interface VPC endpoints / PrivateLink — never hairpin through Firewall to the public AWS endpoint if you can avoid it
typescript
// ✅ CDK: firewall policy allowlist for coding-agent sandboxes
import * as networkfirewall from "aws-cdk-lib/aws-networkfirewall";

const allowDomains = new networkfirewall.CfnRuleGroup(this, "AgentAllowDomains", {
  ruleGroupName: "coding-agent-egress-allow",
  type: "STATEFUL",
  capacity: 100,
  ruleGroup: {
    rulesSource: {
      rulesSourceList: {
        generatedRulesType: "ALLOWLIST",
        targetTypes: ["HTTP_HOST", "TLS_SNI"],
        targets: [
          ".github.com",
          ".githubusercontent.com",
          ".gitlab.com",
          // ✅ prefer CodeArtifact endpoint over public registries
          `codeartifact.${region}.amazonaws.com`,
        ],
      },
    },
  },
});

const denySuspicious = new networkfirewall.CfnRuleGroup(this, "AgentDenySuricata", {
  ruleGroupName: "coding-agent-egress-deny",
  type: "STATEFUL",
  capacity: 50,
  ruleGroup: {
    rulesSource: {
      // ❌ block raw IP HTTPS often used in exfil; tune carefully for git SSH if needed
      rulesString: `
drop tls $HOME_NET any -> $EXTERNAL_NET any (msg:"agent drop non-SNI tls"; tls.sni; sid:1001; rev:1;)
`,
    },
  },
});

const policy = new networkfirewall.CfnFirewallPolicy(this, "AgentFwPolicy", {
  firewallPolicyName: "coding-agent-sandbox",
  firewallPolicy: {
    statelessDefaultActions: ["aws:forward_to_sfe"],
    statelessFragmentDefaultActions: ["aws:forward_to_sfe"],
    statefulRuleGroupReferences: [
      { resourceArn: allowDomains.attrRuleGroupArn, priority: 10 },
      { resourceArn: denySuspicious.attrRuleGroupArn, priority: 20 },
    ],
    statefulDefaultActions: ["aws:drop_established", "aws:alert_established"],
  },
});
bash
# ✅ verify sandbox cannot hit random egress (from inside task)
curl -sS -o /dev/null -w "%{http_code}\n" https://evil.example --max-time 5
# expect hang/fail — Firewall drop

# ✅ approved forge still works
git ls-remote https://github.com/org/repo.git HEAD

Package installs without opening the world

Deny-by-default breaks npm install against the public registry — that is the point. Mirror packages through CodeArtifact and allow only the CodeArtifact domain / VPC endpoint. Same pattern for pip (CodeArtifact PyPI upstream) and Maven.

json
// ✅ .npmrc in sandbox image
{
  "registry": "https://ORG-DOMAIN-ACCOUNT.d.codeartifact.REGION.amazonaws.com/npm/agent-store/",
  "//ORG-DOMAIN-ACCOUNT.d.codeartifact.REGION.amazonaws.com/npm/agent-store/:_authToken": "${CODEARTIFACT_AUTH_TOKEN}"
}

❌ Baking registry.npmjs.org into the allowlist “just for one package” recreates the exfil path via typosquatting and postinstall scripts.

Bedrock, secrets, and north-south vs east-west

  • Model calls: PrivateLink Bedrock — remove Bedrock from NAT entirely
  • Secrets: fetch via VPC endpoint to Secrets Manager, never from public
  • Public agent HTTP APIs still need WAF on the north-south edge — Firewall is primarily sandbox egress (southbound)

Complement with SCPs that deny ec2:CreateInternetGateway attachments in agent OUs so teams cannot bypass the Firewall VPC.

Logging and response

Enable Firewall alert/flow logs to CloudWatch or S3. Pipe high-severity drops into CloudWatch Logs Insights queries tagged by tenant_id / turn_id (add custom dimensions via flow log enrichment or sidecar). On sudden allowlist miss storms after a prompt change, flip an AppConfig kill switch for the offending tool.

Signal Meaning Action
Spike TLS SNI drops Injection / bad dependency Quarantine tenant; review tool IO (Guardrails)
CodeArtifact 403 + no Firewall drop IAM/token issue Fix auth, not allowlist
All git failing Over-tight allowlist Add forge domains carefully
NAT bytes ↑ Firewall bytes ↓ Route table bypass Fix subnet routes

Production checklist

  • [ ] Sandbox 0.0.0.0/0 points at Firewall endpoints, not straight to NAT
  • [ ] Stateful default = drop established; explicit ALLOWLIST for forges + mirrors
  • [ ] Bedrock/Secrets/STS/ECR via PrivateLink / VPC endpoints
  • [ ] CodeArtifact (or other private mirror) required for package installs
  • [ ] Alert + flow logs retained; Insights queries for deny storms
  • [ ] SCPs prevent IGW/NAT shortcuts in agent accounts
  • [ ] Document break-glass allowlist change with dual control
  • [ ] Fargate Spot / CodeBuild task ENIs only in sandbox subnets

FAQ

Q: Is Network Firewall overkill vs squashing security groups?
A: SGs cannot see evil.example. Once agents execute untrusted code/docs, you need domain-aware egress.

Q: What about SSH git on port 22?
A: Prefer HTTPS git with PATs from Secrets Manager, or allowlist forge IPs carefully — raw any:22 recreates exfil.

Q: Does this replace WAF?
A: No. WAF protects public entrypoints; Firewall constrains what sandboxes can call out to.

Network Firewall turns coding-agent sandboxes from “NAT and pray” into deny-by-default egress with an allowlist you can audit. Mirror packages, PrivateLink your AWS APIs, and treat every surprise SNI drop as a security signal — not a connectivity ticket.

Rollout pattern that does not brick CI overnight

Do not flip deny-by-default on day one across every tenant. Stage it:

  1. Alert-only stateful rules for two weeks — measure which SNIs sandboxes actually need
  2. Publish a per-team allowlist proposal from Firewall logs (forges, mirrors, internal APIs)
  3. Enforce on a canary OU / AppConfig-flagged tenants
  4. Expand OU-wide under SCPs that forbid route-table bypasses
bash
# ✅ sample Insights-style filter over Firewall alert logs (adjust fields to your schema)
fields @timestamp, event.event_timestamp, event.src_ip, event.dest_ip, event.alert.signature
| filter event.alert.action = "blocked"
| stats count() by event.alert.signature
| sort count desc

Teams that “need the whole internet for browsershots” should run those tools in a separate VPC with a different risk tier — not punch holes in the coding-agent sandbox Firewall. Keep clone/test/apply fleets boring and locked down; isolate high-egress research agents where you can afford the blast radius.

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.