IP restrictions
IP restrictions let you limit which client IPs can use an API key. When enabled, verification rejects requests from IPs outside the allowed CIDR ranges. Keys without IP restrictions are unrestricted.
Prerequisites
A running Talos server. See the quickstart to start one locally.
Configure client IP source
By default, Talos uses the TCP remote address (REMOTE_ADDR) to determine client IP. If your server runs behind a reverse proxy
or CDN, configure the correct header in your Talos config:
serve:
http:
client_ip_source: CLIENT_IP_SOURCE_CF_CONNECTING_IP
Supported values:
CLIENT_IP_SOURCE_UNSPECIFIEDorCLIENT_IP_SOURCE_REMOTE_ADDR— TCP remote address (default)CLIENT_IP_SOURCE_CF_CONNECTING_IP— CloudflareCLIENT_IP_SOURCE_X_FORWARDED_FOR— Standard proxy headerCLIENT_IP_SOURCE_X_REAL_IP— NginxCLIENT_IP_SOURCE_TRUE_CLIENT_IP— Cloudflare Enterprise
This is a global setting — all IP restriction checks use the same source. Set it once to match your infrastructure topology.
Issue a key with IP restrictions
Add the ip_restriction field when creating a key. The allowed_cidrs array accepts both individual IPs (with /32 or /128
suffix) and CIDR ranges:
- CLI
- curl
RESPONSE=$(talos keys issue "restricted-key" \
--actor service_payments \
--allowed-cidrs "127.0.0.1/32,10.0.0.0/8" \
--format json \
-e "$TALOS_URL" 2>/dev/null)
echo "$RESPONSE" | jq .
export API_SECRET=$(echo "$RESPONSE" | jq -er '.secret')
export KEY_ID=$(echo "$RESPONSE" | jq -er '.issued_api_key.key_id')
RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/issuedApiKeys" \
-H "Content-Type: application/json" \
-d '{
"name": "restricted-key",
"actor_id": "service_payments",
"ip_restriction": {
"allowed_cidrs": ["127.0.0.1/32", "10.0.0.0/8"]
}
}')
echo "$RESPONSE" | jq .
export API_SECRET=$(echo "$RESPONSE" | jq -er '.secret')
export KEY_ID=$(echo "$RESPONSE" | jq -er '.issued_api_key.key_id')
For the complete request field reference, see the IssueAPIKey API reference.
Verify from an allowed IP
When the client IP is within an allowed CIDR range, verification succeeds:
- CLI
- curl
talos keys verify "$API_SECRET" -e "$TALOS_URL"
VERIFY_RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/apiKeys:verify" \
-H "Content-Type: application/json" \
-d "{\"credential\": \"$API_SECRET\"}")
echo "$VERIFY_RESPONSE" | jq .
The response includes the key metadata with is_active: true.
Verification from a disallowed IP
When the client IP is outside all allowed CIDR ranges, verification returns VERIFICATION_ERROR_IP_NOT_ALLOWED. The response does
not reveal which CIDRs are configured.
For the full list of verification error codes, see the error codes reference.
Update IP restrictions on an existing key
Use PATCH to add, change, or remove IP restrictions on an existing key:
- CLI
- curl
talos keys issued update "$KEY_ID" \
--allowed-cidrs "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" \
-e "$TALOS_URL"
UPDATE_RESPONSE=$(curl -s -X PATCH "$TALOS_URL/v2alpha1/admin/issuedApiKeys/$KEY_ID" \
-H "Content-Type: application/json" \
-d '{
"ip_restriction": {
"allowed_cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
}
}')
echo "$UPDATE_RESPONSE" | jq .
To remove all IP restrictions (making the key unrestricted), set allowed_cidrs to an empty array:
- CLI
- curl
talos keys issued update "$KEY_ID" \
--allowed-cidrs "" \
-e "$TALOS_URL"
UNRESTRICT_RESPONSE=$(curl -s -X PATCH "$TALOS_URL/v2alpha1/admin/issuedApiKeys/$KEY_ID" \
-H "Content-Type: application/json" \
-d '{
"ip_restriction": {
"allowed_cidrs": []
}
}')
echo "$UNRESTRICT_RESPONSE" | jq .
For the complete update field reference, see the UpdateIssuedAPIKey API reference.
Import keys with IP restrictions
You can also set IP restrictions when importing external keys:
- CLI
- curl
talos keys imported import "imported-restricted" \
--raw-key "sk_live_example_key_for_import_test" \
--actor "user_restrict" \
--allowed-cidrs "203.0.113.0/24" \
-e "$TALOS_URL"
IMPORT_RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/importedApiKeys" \
-H "Content-Type: application/json" \
-d '{
"name": "imported-restricted",
"raw_key": "sk_live_example_key_for_import_test",
"actor_id": "user_restrict",
"ip_restriction": {
"allowed_cidrs": ["203.0.113.0/24"]
}
}')
echo "$IMPORT_RESPONSE" | jq .
For the complete import field reference, see the ImportAPIKey API reference.
Behavior notes
- Allowlist model: Only listed CIDRs are permitted. An empty
allowed_cidrsarray means the key is unrestricted (all IPs allowed). - Cache TTL: IP restriction changes take effect after the cache TTL expires. See cache configuration for TTL settings.
- Fail-closed: If client IP resolution fails, the request is denied.
- IPv4 and IPv6: Both address families are supported. Use
/32for single IPv4 addresses and/128for single IPv6 addresses. - Derived tokens: IP restrictions apply to the underlying API key, not to derived tokens (JWTs/macaroons). Token verification checks the key's IP restrictions at derivation time.
