APIZ guide
Filter API Access By IP And Geo
Use verified Request Origin when an agent should call an API only from trusted networks or geographic locations. APIZ provides two complementary controls:
| Need | Configure it in | Enforcement point |
|---|---|---|
| Accept only known IPv4/IPv6 networks | API Instance Request Origin Access | Before Policy, credential release, or upstream contact |
| Allow or deny countries, continents, regions, cities, timezones, or private-network context | Structured or Scripted Policy | After origin verification and the API Instance IP filter |
The IP restriction is commonly called an IP whitelist or IP allowlist. Geo is Policy context, not a second API Instance allowlist. Both use APIZ's canonical verified origin and never trust a caller-supplied forwarding header by itself.
edge trust -> verified IP + Geo -> API Instance CIDR filter -> Policy -> upstream
deny stops here deny stops here
This restriction applies to every Client Binding for the API Instance, including intentionally public bindings. A Policy may narrow access further, but cannot override an IP denial.
Before You Configure It
- Identify the stable egress addresses of the agent runtime, sandbox platform, NAT gateway, or corporate network that will call APIZ.
- Express individual IPv4 addresses as
/32and individual IPv6 addresses as/128. Use a broader CIDR only when the complete network is trusted. - Confirm that the APIZ deployment has a healthy Edge Trust Profile. APIZ uses only the caller IP established by that trust boundary; it never trusts a caller-supplied forwarding header by itself.
- For Geo rules, confirm that the deployment exposes available Geo context. Geo may come from a verified Cloudflare edge or the operator's bounded MMDB provider. It is approximate authorization context, not proof of a person's physical location.
- Keep a second authorized management session available while changing a production allowlist.
The addresses below are reserved documentation examples. Replace them with your real trusted networks:
203.0.113.10/32
2001:db8:1234::/48
Configure The IP Filter In The Web Console
- Open API Instances and create an instance, or open an existing instance and choose Edit.
- Expand Advanced Settings, then Request Origin Access.
- Enable Restrict trusted source IPs.
- Add one to 64 IPv4 or IPv6 CIDRs under Allowed source CIDRs.
- Review the complete list and save the API Instance.
APIZ canonicalizes network addresses, sorts the list, and removes duplicates.
For example, 203.0.113.99/24 is stored as 203.0.113.0/24. A bare address
without a prefix is rejected rather than guessed.
Connection tests validate APIZ-to-upstream connectivity and do not apply the caller allowlist. Verify the restriction with a real Data Plane request after saving.
Configure The IP Filter With The CLI
Add the allowlist while creating any adapter-backed API Instance by repeating
--allow-source-cidr:
apiz api create \
--adapter github \
--name restricted-github \
--config-json '{}' \
--test-config-json '{"preset":"get_user_info"}' \
--allow-source-cidr 203.0.113.10/32 \
--allow-source-cidr 2001:db8:1234::/48 \
--credential-stdin
Replace the complete allowlist on an existing instance:
apiz api update <api-instance-id> \
--allow-source-cidr 203.0.113.10/32 \
--allow-source-cidr 2001:db8:1234::/48
The update command replaces the list atomically; it does not append to the previous value. Disable filtering and clear every CIDR explicitly:
apiz api update <api-instance-id> --clear-source-cidrs
Do not combine --clear-source-cidrs with --allow-source-cidr.
Add A Geo Rule With Structured Policy
The following Policy allows requests only when verified Geo is available and
the country code is US or SG. Replace those synthetic choices with the
countries required by your own risk model.
Web Console
- Open Policies → Create Policy and choose Structured.
- Select the adapter scope for the API you are protecting, or leave it unscoped only when the same gate should apply across adapters.
- Add
Geo · Availablewith operatorequalsand valuetrue. - Add
Geo · Country codewith operatorinand valuesUS, SG. - Set THEN to
allowwith reasongeo_allowed. - Set OTHERWISE to
denywith reasongeo_not_allowed. - Save and publish the Policy. Review the current testing boundary below before attaching it to traffic.
You can use the same editor for continent, region, city, timezone, Geo provider, or private-network context. Prefer country or continent rules when possible; city-level Geo is less stable and may be unavailable.
CLI
Use this as the definition in a Structured Policy Project:
{
"type": "structured",
"when": {
"conditions": [
{"field": "request_origin.geo.available", "op": "equals", "value": true},
{"field": "request_origin.geo.country_code", "op": "in", "value": ["US", "SG"]}
]
},
"then": {"decision": "allow", "reason": "geo_allowed"},
"otherwise": {"decision": "deny", "reason": "geo_not_allowed"}
}
Publish it using the lifecycle in the Structured Policy tutorial:
apiz -o json policy publish --project ./geo-access > policy-review.json
POLICY_ID=$(jq -r '.candidate.policy_id' policy-review.json)
DRAFT_REVISION=$(jq -r '.candidate.draft_revision' policy-review.json)
POLICY_REVISION=$(jq -r '.candidate.current_published_revision' policy-review.json)
jq '{candidate, changes, evidence, traffic_effect}' policy-review.json
apiz policy publish "$POLICY_ID" --project ./geo-access \
--expected-draft-revision "$DRAFT_REVISION" \
--expected-policy-revision "$POLICY_REVISION" --confirm
apiz policy enable "$POLICY_ID"
Current Testing Boundary
The current public Policy Fixture API does not accept synthetic
request_origin or Geo context; it permits only bounded Client and API Instance
tag overrides. A Geo-dependent fixture therefore fails closed with
policy_context_unavailable instead of establishing readiness. Do not claim a
passing Geo suite or substitute caller-controlled headers.
This implemented limitation conflicts with the active Request Origin contract, which requires synthetic origin and Geo fixture context. Until that gap is resolved, validate Geo Policies on a non-production API Instance. Test evidence is advisory; attaching does not require an override:
apiz api policy add <api-instance-id> \
--policy <policy-id> \
--order 100
Keep Geo gates off production traffic until the observed allow, deny, unavailable-context, and redacted-evidence paths have been reviewed for the exact Published Revision.
If the Policy references Geo but APIZ cannot verify that field, evaluation
denies with policy_context_unavailable; missing Geo never becomes an empty
value that accidentally passes a negative condition.
Verify Allow And Deny
Send the same Temporary Credential from one allowed source and one source outside the list. The allowed request continues through normal Policy and upstream processing. The blocked request returns HTTP 403 with:
code=apiz_forbidden
reason=api_instance_source_ip_not_allowed
The response does not reveal the observed address or configured CIDRs. An
enabled filter also fails closed with request_origin_unavailable when APIZ
cannot establish a trusted caller address.
For Geo, send controlled requests through known test egress locations. Confirm
that an allowed country reaches the next Policy or upstream step, while a
disallowed country returns the configured geo_not_allowed reason. Do not use
a caller-supplied country or forwarding header as a test mechanism.
Inspect Evidence
In the Web Console, open Logs / Audit → Access Logs, select the request, and inspect Request origin and the API Instance filter outcome. Use Audit Logs to see who changed the allowlist.
With the CLI:
apiz access-log list --api-instance <api-instance-id> --since 15m --limit 50
apiz access-log request <request-id>
apiz audit list --api-instance <api-instance-id> --since 24h
Request evidence may show the canonical trusted source IP to authorized Team members, but never copies raw proxy chains or unverified forwarding headers.
Troubleshooting
| Symptom | What to check |
|---|---|
api_instance_source_ip_not_allowed | Confirm the caller's actual egress network and the complete saved CIDR list. |
request_origin_unavailable | Ask the APIZ operator to check Edge Trust Profile readiness; do not add a forwarded header workaround. |
policy_context_unavailable | The Policy referenced trusted origin or Geo data that APIZ could not verify. Check Geo readiness and the selected field. |
geo_not_allowed | The verified Geo context did not match the Policy's allowed values. Inspect the canonical country/region evidence. |
| Connection test succeeds but agent request is denied | Expected: connection tests do not represent a Data Plane caller. Test using the generated agent endpoint. |
| Every address is allowed | Check for 0.0.0.0/0 or ::/0; those are valid but non-restrictive networks. |
| CIDR rejected | Include the prefix and use canonical IPv4 or IPv6 network form; multicast and unspecified-host ranges are unsupported. |
Combine this gate with Structured or Scripted Policy when the decision also depends on adapter action, resource, or tags. Continue with request evidence when a request still behaves unexpectedly.