Athena

Virgin Keys and Lock-In

How Athena learns caller IPs, when a key locks in, and how to promote or reset it.

Athena's lock-while-learning key type is called virgin_mode. It is designed for cases where you know a key will eventually come from a small set of hosts, but you do not want to hardcode that whitelist before first use.

This is the Athena feature most people mean when they ask about when a key "locks". The key is not disabled; it transitions from learning mode into normal whitelist enforcement.

State transitions

What happens during learning

While a key is both virgin_mode = true and virgin_resolved = false, Athena's enforce_ip_policy path does this on every successful auth:

  1. writes or updates the caller IP in api_key_ip_seen
  2. increments virgin_request_count
  3. checks whether either lock-in threshold has been reached
  4. if a threshold is hit, promotes seen IPs and marks the key resolved
  5. allows the current request

That means unresolved virgin keys:

  • still respect global and per-key blacklists
  • do not yet apply global or per-key whitelist denials
  • collect the observation data that later becomes the whitelist

When does the key lock in?

A virgin key locks in when either of these becomes true:

FieldMeaning
virgin_until_n_requestslock after this many successful authentications
max_whitelist_ipslock after this many distinct seen IPs

Important details from the implementation:

  • virgin_until_n_requests = 0 disables the request-count threshold.
  • max_whitelist_ips = 0 disables the distinct-IP threshold and also means "no cap" when promoting seen IPs.
  • At least one of those values must be positive when virgin_mode is enabled.
  • Athena uses whichever threshold is hit first.

Promotion behavior

When lock-in happens automatically, Athena:

  1. reads the earliest-seen rows from api_key_ip_seen
  2. inserts them into api_key_ip_whitelist
  3. uses max_whitelist_ips as the promotion cap when it is positive
  4. marks the key virgin_resolved = true
  5. sets locked_in = true on the seen-IP rows

This is why a key that learned from three hosts can later reject a fourth host even though it worked during the learning window.

Constraints

POST /admin/api-keys rejects invalid virgin configurations:

  • You cannot combine virgin_mode with an initial ip_whitelist.
  • You cannot combine virgin_mode with an initial ip_blacklist.
  • You must set at least one positive lock-in threshold.

Full create example

curl -X POST "http://localhost:4052/admin/api-keys" \
  -H "X-Athena-Admin-Key: $ATHENA_KEY_12" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "bootstrap-worker",
    "client_name": "analytics",
    "rights": ["gateway.query"],
    "virgin_mode": true,
    "virgin_until_n_requests": 20,
    "max_whitelist_ips": 3
  }'

Manual promote and reset

Promote immediately

Use this when you want to lock in before the threshold is reached.

curl -X POST "http://localhost:4052/admin/api-keys/$API_KEY_ID/virgin/promote" \
  -H "X-Athena-Admin-Key: $ATHENA_KEY_12"

Athena copies the earliest-seen IPs into the whitelist, respecting max_whitelist_ips, then marks the key resolved.

Reset learning state

Use this when a deployment changes and the key needs to relearn.

curl -X POST "http://localhost:4052/admin/api-keys/$API_KEY_ID/virgin/reset" \
  -H "X-Athena-Admin-Key: $ATHENA_KEY_12" \
  -H "Content-Type: application/json" \
  -d '{
    "clear_seen": true
  }'

If clear_seen is false, Athena preserves the seen rows but clears their locked_in flags. If it is true, the observation history is removed.

Inspecting what the key learned

curl "http://localhost:4052/admin/api-keys/$API_KEY_ID/ip-seen?limit=100" \
  -H "X-Athena-Admin-Key: $ATHENA_KEY_12"

The response includes hit_count, first_seen_at, last_seen_at, and locked_in, which makes it easy to see exactly why a key locked when it did.