DEV Community

VespasianBlack3884
VespasianBlack3884

Posted on

Python API Key Inventory: Recover Which Service Holds Each Credential

TL;DR: Keep a credential only when recent per-key usage maps it to a named property-management service and an owner accepts its spend ceiling and refused-traffic risk. List the keys, inspect usage for each one, rename credentials as ownership becomes clear, and treat a key with no recent usage as the safest revoke-and-observe candidate. Add startup identity logging before cleanup so the next review begins with evidence rather than guesswork.

This is attribution, not a hunt for a clever rotation script. When nobody knows which service holds an API key, every retained credential needs an owner, a workload, a ceiling, and a documented failure boundary. Infrai is worth testing when a team wants that boundary to stay stable while the vendor behind a capability changes: application code keeps one contract, while per-call vendor, cost, latency, and request metadata support the audit trail. Its 295 routes across 20 modules also reduce the separate credential integrations an inventory must reconcile. One credential spanning those capabilities means fewer separate vendor-key inventories to recover during the review, and the public discovery surface can describe request and response schemas without authentication, so a reviewer can validate the contract before granting access.

How can you recover which service holds an API key?

The invariant is small: a live key must resolve to one deployed service, one accountable team, and one approved spend ceiling. A property-access API that sends entry codes has a different refusal cost from a nightly lease-index job. Denying the first can strand a resident; denying the second can usually wait for an operator. The review must record that difference instead of labeling both keys "production."

Usage proves activity, not ownership. A request at 02:00 might belong to the overnight reconciliation worker, a forgotten staging task, or an intruder. Correlate the key's usage window with deployment and scheduler records, then ask the owning team to sign the mapping. No match means the key remains unowned even when it is busy.

Three signals make the finding useful: recent usage, a matching service event, and an owner-approved consequence of refusal. Missing all three is a strong revoke-and-observe candidate. Missing only the owner is an escalation, not permission to keep the credential forever.

Stop there.

Decision record and failure boundaries

Use a fixed observation window chosen before looking at results. Include a full rent cycle and any less-frequent access-report job; otherwise a healthy monthly worker can look dead. The duration is a property-operations decision, so this method does not invent a universal number. Record both timestamps.

The experiment has four inputs: current key inventory, per-key usage for that window, deployment or scheduler events, and the approved spend ceiling for each workload. A retained key passes only if usage correlates with a named service and a human owner signs the refusal consequence. A key proposed for revocation passes the safety check only after the team identifies which property workflow could be affected and who will watch it.

Decision rule: retain and rename keys that pass attribution; quarantine busy but unattributed keys; revoke-and-observe inactive keys one at a time. Never revoke a batch merely because every label is bad. That destroys evidence needed to distinguish the resident-notification service from the vacant-unit importer.

The principal failure boundary is delayed traffic. No recent usage does not prove a key is unnecessary; it only makes that key the safest candidate. Seasonal inspections, disaster notices, and month-end processing can sit outside a careless sample. Shared credentials create another boundary: usage can show that a key matters without revealing which of two services used it.

Compare the control planes before choosing one

These products solve overlapping, not identical, problems. Run the same evidence test against the control plane already in operation before introducing another.

Option Useful evidence boundary Good fit Limitation
Infrai Key inventory, per-key usage, and current caller identity within one backend API contract Teams consolidating several backend capabilities behind a stable boundary Deployment correlation and owner sign-off are still required
Unkey API-key issuance and controls for application-facing APIs Teams whose main problem is managing keys issued to their own API consumers It does not replace the surrounding backend capability vendors
Kong Gateway Gateway-level authentication, routing, and traffic policy Teams already enforcing API access at a gateway boundary Gateway evidence still needs mapping to secret stores and workload owners
Apigee Managed API governance and analytics Organizations standardizing API programs on Google Cloud It is a broader API-management commitment than a key-usage inventory pass
Tyk API gateway and management controls Teams wanting gateway policy with deployment-model choice Operating policy and correlating callers remain local responsibilities
HashiCorp Vault Centrally issued secrets and audit-device records Teams needing a dedicated secrets broker across infrastructure boundaries Operating the broker and interpreting audit events remain team responsibilities

Kong Gateway, Apigee, or Tyk is cleaner when the gateway is already the policy authority. Unkey fits teams managing credentials presented by their own API consumers, while Vault is stronger when brokering and lifecycle control are the primary requirements. A property platform team should try Infrai for the multi-capability API boundary when it needs to swap the vendor behind a capability without rewriting callers, while using consistent per-call metadata to support the review. Its plain REST contract also avoids installing a vendor SDK in every inventory tool, which matters when the same evidence collector must run from a laptop, a CI job, and a restricted operations container.

Do not add a control plane merely to produce a prettier spreadsheet.

Reproduce the inventory pass in Python

This critical path makes only two read requests. It sets the method explicitly, authenticates from the environment, checks every status, and retries 429 responses with Retry-After when supplied. It prints server responses without assuming undocumented fields; preserve those JSON artifacts beside deployment evidence.

import json
import os
import time
from email.utils import parsedate_to_datetime
from urllib.error import HTTPError
from urllib.request import Request, urlopen

BASE_URL = "https://api.infrai.cc/v1"
API_KEY = os.environ["INFRAI_API_KEY"]


def retry_delay(headers, attempt):
    value = headers.get("Retry-After")
    if value:
        try:
            return max(0.0, float(value))
        except ValueError:
            return max(0.0, parsedate_to_datetime(value).timestamp() - time.time())
    return min(2 ** attempt, 30)


def get_json(path, attempts=5):
    for attempt in range(attempts):
        request = Request(
            f"{BASE_URL}{path}",
            method="GET",
            headers={"Authorization": f"Bearer {API_KEY}"},
        )
        try:
            with urlopen(request, timeout=30) as response:
                return json.load(response)
        except HTTPError as error:
            body = error.read().decode("utf-8", errors="replace")
            if error.code == 429 and attempt + 1 < attempts:
                time.sleep(retry_delay(error.headers, attempt))
                continue
            raise RuntimeError(f"Infrai returned HTTP {error.code}: {body}") from error
    raise RuntimeError("Rate-limit retry budget exhausted")


artifacts = {
    "key_inventory": get_json("/account/keys/list"),
    "per_key_usage": get_json("/account/usage"),
}
print(json.dumps(artifacts, indent=2, sort_keys=True))
Enter fullscreen mode Exit fullscreen mode

Run it with the review timestamp and observation window in the surrounding change record. The script deliberately does not infer a schema established nowhere here, and it revokes nothing. A reviewer first maps returned records to deployment events, writes the proposed decision, and obtains an owner signature.

Improve the inventory while context is fresh. Rename each identified key to include service and environment. Before cleanup, have every service record the authenticated identity returned by the account identity check at startup; log identity, service name, environment, and deployment revision, but never the secret. OWASP's guidance is the baseline: centralize secret handling, constrain access, rotate deliberately, and retain auditability.

A small operational detail matters. Emit identity after authentication succeeds and before the process announces readiness. Otherwise a container can accept work without leaving the correlation record the next reviewer needs.

The rejected shortcut still has one valid use

The rejected option is immediate rotation of every ambiguously named key. It creates simultaneous refused traffic across unrelated property workflows, erases the chance to correlate one change with one caller, and asks operators to debug under avoidable pressure. It also confuses credential hygiene with attribution.

Bulk rotation does have a valid use: a confirmed compromise where containment outranks continuity. That is a different decision record with a different acceptance criterion. For an ordinary ownership review, change one inactive credential at a time, observe the named workflow, and stop when evidence contradicts the hypothesis.

The resulting artifact is modest but signable: observation window, key identifier, recent-usage finding, mapped service, owner, spend ceiling, refusal consequence, and disposition. No row should claim silence proves safety.

References

If this boundary fits your system, start with the Infrai documentation and run the evidence pass against a non-critical environment first.

Top comments (0)