DEV Community

Multigrid
Multigrid

Posted on • Originally published at multigrid.ai

Allowlisting a Model Provider's IP Ranges Through a Firewall

“Allow outbound 443 to anywhere” is the rule everyone starts with and nobody defends in an audit. Narrowing it to a specific provider is straightforward for some vendors and impossible for others, and the difference is entirely whether they publish a range and commit to it.

Who publishes what

Anthropic publishes fixed IP addresses for both directions and states that they will not change without notice. On its IP addresses documentation page it lists inbound IPv4 of 160.79.104.0/23 and inbound IPv6 of 2607:6bc0::/48 — those are the addresses your requests to the Claude API reach — and an outbound IPv4 range of 160.79.104.0/21, used when Anthropic’s own services call out to you, for instance for MCP connector or web fetch tool calls. The page also lists phased-out addresses to remove from existing rules, which is a good reason to read it rather than copy from an old runbook.

Those CIDRs are what Anthropic publishes at the time of writing. This page is exactly the kind that goes stale silently — read the vendor page itself before pasting anything into a firewall, and treat this paragraph as a pointer to it, not as a substitute.

AWS publishes ip-ranges.json, with each prefix carrying ip_prefix, region, service and network_border_group. Two caveats AWS states directly and that matter here: it publishes ranges “for services that customers commonly use to perform egress filtering” and not for all services, and its own egress-filtering guidance is to allow the AMAZON list — which is a very wide allow, because it is effectively all of AWS. AWS also warns that you may need multiple security groups per Region to hold the resulting rules.

Azure publishes service tags, downloadable as a weekly JSON file and queryable with az network list-service-tags --location eastus. Microsoft states that new IP addresses added to a service tag are not used in Azure for at least a week, which gives you a real window to pick up a change before it breaks anything — the most operator-friendly commitment of the three. Where the platform supports it, referencing the service tag by name in an NSG rule is better than materialising the CIDRs at all.

Several providers publish nothing. If a vendor sits behind a large CDN, its addresses are shared with a substantial fraction of the internet, and pinning them gives you a rule that is both wide and fragile. Skip to the hostname approach below.

Turning a published list into a rule

Do not paste. Fetch, filter, and write, so that regenerating the rule is a command rather than an afternoon:

curl -sS -O https://ip-ranges.amazonaws.com/ip-ranges.json

# every prefix for one service in one Region
jq -r '.prefixes[]
       | select(.region=="us-east-1" and .service=="AMAZON")
       | .ip_prefix' ip-ranges.json | sort -u
Enter fullscreen mode Exit fullscreen mode

Then apply the result. The important discipline is that the applying step is idempotent and diff-able — you want to be able to see what changed between two runs, because that difference is the thing that will break you.

aws ec2 authorize-security-group-egress \
  --group-id sg-0egress \
  --ip-permissions 'IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=160.79.104.0/23,Description="anthropic api"}]'
Enter fullscreen mode Exit fullscreen mode

Watch the rule count. AWS’s default is 60 inbound and 60 outbound rules per security group, enforced separately for IPv4 and IPv6, and the quota for rules per security group multiplied by security groups per network interface cannot exceed 1,000. A provider list of any size will exhaust that quickly if you enumerate it as individual rules.

Prefix lists beat pasted CIDRs

A customer-managed prefix list is a named set of CIDRs that you reference from a security group rule or a route table. It solves the rule-count problem and, more importantly, it makes an update one operation instead of many. AWS documents prefix lists as versioned — up to 1,000 stored versions, with the oldest dropped as new ones are added — which means a bad update is a rollback rather than a reconstruction.

aws ec2 create-managed-prefix-list \
  --prefix-list-name anthropic-api \
  --address-family IPv4 \
  --max-entries 20 \
  --entries Cidr=160.79.104.0/23,Description="claude api inbound range"

aws ec2 authorize-security-group-egress \
  --group-id sg-0egress \
  --ip-permissions 'IpProtocol=tcp,FromPort=443,ToPort=443,PrefixListIds=[{PrefixListId=pl-0abc123}]'
Enter fullscreen mode Exit fullscreen mode

One sizing detail that catches people: AWS states that when a prefix list is referenced in a resource, the list’s maximum number of entries counts against that resource’s quota — so a prefix list created with --max-entries 100 consumes 100 security group rules even if it holds two. Size max-entries to a realistic ceiling, not a generous one.

When there is no list to pin

If the provider publishes nothing, an IP allowlist is the wrong control and forcing one produces an outage on a day nobody changed anything. The alternative is to filter on the name. AWS Network Firewall can match the TLS SNI of an outbound connection against a domain list, and a forward proxy such as Squid can do the same with an explicit destination allowlist. Either way the rule reads “only these hostnames”, which is what the security requirement actually said before somebody translated it into addresses.

The honest trade-off: SNI is unauthenticated and a determined insider can forge it, so an SNI rule is a control against accident and misconfiguration rather than against a motivated attacker. For most teams that is the threat model anyway — the thing you are preventing is a dependency quietly calling an endpoint nobody reviewed, not espionage. Say that out loud in the design document rather than letting the control be mistaken for something stronger.

Whichever mechanism you use, pin it to a specific egress point. If the workload leaves through a NAT gateway, the firewall belongs on that path and the gateway’s Elastic IP is your stable identity to the outside — see setting up a NAT gateway for outbound calls.

The rule rots, and how you find out

Every allowlist built from a published list is a copy, and a copy goes stale silently in the worst possible way: it keeps working until the provider adds capacity on a new range, and then a fraction of your requests start failing while the rest succeed. That partial failure is much harder to diagnose than a total one, because it looks like flakiness rather than configuration.

  1. Re-fetch the source list on a schedule — daily is not excessive — and diff it against what your prefix list holds. AWS offers SNS notifications for changes to ip-ranges.json; Azure’s file is weekly with a week’s notice built in.
  2. Alert on the diff rather than applying it blindly. An unexpected widening of a provider range is worth a human glance.
  3. Instrument the failure mode you expect: a connection timeout to the provider that correlates with a subset of resolved addresses is the signature of a stale allowlist, and it is worth a distinct alarm from a general provider outage.
  4. Keep the rule’s provenance in its description field. Six months later, “where did this CIDR come from” is a real question and the answer should be in the rule.

The number of egress rules you maintain scales with the number of providers you call directly, and each one has its own publication policy, its own change cadence and its own failure signature. Routing model traffic through a single component collapses that to one destination for the firewall to reason about — which is the architectural reason a gateway like Multigrid is easier to allowlist than five vendors, quite apart from anything else it does.

Related

Top comments (0)