IP Whitelists, Blacklists, and Precedence
The exact order Athena uses when global rules, per-key rules, and lock-in state overlap.
Athena supports both per-key and global IP rules. The runtime model is stored in
ApiKeyIpPolicy, api_key_ip_whitelist, api_key_ip_blacklist,
api_key_ip_global_whitelist, and api_key_ip_global_blacklist.
Precedence order
The authoritative order is documented in enforce_ip_policy:
In plain English:
- Global blacklists win first.
- Per-key blacklists win next.
- Unresolved
virgin_modekeys learn and return early. - Global whitelists apply before per-key whitelists.
- If no whitelist exists at a level, Athena keeps evaluating the next rule set.
Global vs per-key rules
| Rule type | Scope | Admin route |
|---|---|---|
api_key_ip_global_whitelist | entire deployment or one client_name | /admin/ip-global-whitelist |
api_key_ip_global_blacklist | entire deployment or one client_name | /admin/ip-global-blacklist |
api_key_ip_whitelist | one API key | /admin/api-keys/{id}/ip-whitelist |
api_key_ip_blacklist | one API key | /admin/api-keys/{id}/ip-blacklist |
Global rules can have client_name = NULL, which makes them apply everywhere,
or a specific client name, which narrows them to one logical client.
What counts as an IP rule
parse_cidr_list accepts:
- IPv4 addresses like
203.0.113.10 - IPv6 addresses like
2001:db8::10 - CIDR blocks like
203.0.113.0/24or2001:db8::/32
Bare IPs are normalized to host-only networks:
- IPv4 ->
/32 - IPv6 ->
/128
How Athena finds the client IP
extract_client_ip resolves the caller in this order:
X-Real-IP- first hop of
X-Forwarded-For, but only whenATHENA_RATE_LIMIT_TRUST_X_FORWARDED_FORor the corresponding config value enables trust - direct peer address from the socket
If any whitelist, blacklist, or virgin_mode rule is in play and Athena cannot
resolve the client IP, the request is rejected with Client IP required.
Per-key policy examples
Add whitelist entries
curl -X POST "http://localhost:4052/admin/api-keys/$API_KEY_ID/ip-whitelist" \
-H "X-Athena-Admin-Key: $ATHENA_KEY_12" \
-H "Content-Type: application/json" \
-d '{
"addrs": ["203.0.113.10", "203.0.113.0/24"],
"label": "office"
}'Add blacklist entries
curl -X POST "http://localhost:4052/admin/api-keys/$API_KEY_ID/ip-blacklist" \
-H "X-Athena-Admin-Key: $ATHENA_KEY_12" \
-H "Content-Type: application/json" \
-d '{
"addrs": ["198.51.100.0/24"],
"label": "blocked-range"
}'Inspect the resolved key policy
curl "http://localhost:4052/admin/api-keys/$API_KEY_ID/ip-policy" \
-H "X-Athena-Admin-Key: $ATHENA_KEY_12"Global policy examples
Whitelist one client's deployment CIDR
curl -X POST "http://localhost:4052/admin/ip-global-whitelist" \
-H "X-Athena-Admin-Key: $ATHENA_KEY_12" \
-H "Content-Type: application/json" \
-d '{
"addr": "10.42.0.0/16",
"client_name": "analytics",
"label": "analytics cluster"
}'Blacklist a bad source everywhere
curl -X POST "http://localhost:4052/admin/ip-global-blacklist" \
-H "X-Athena-Admin-Key: $ATHENA_KEY_12" \
-H "Content-Type: application/json" \
-d '{
"addr": "198.51.100.77",
"label": "abuse source"
}'Operational notes
- IP policy caches are short-lived, around 2 seconds, and admin mutations call
invalidate_ip_policyorinvalidate_global_ip_rulesso changes apply quickly. api_key_ip_seenis not an allowlist by itself. It is observation data used byvirgin_mode.- A blacklist can still reject traffic while a key is in virgin learning mode.