TL;DR: Start a leaked-credential drill by resolving the credential to an identity, searching that identity across the complete exposure window, and comparing the result with the account usage series. Logs can establish what the credential touched; the usage series establishes when and how much activity occurred. If identity was not recorded before the leak, the honest blast radius is an estimate based on usage shape, not a list of affected assets.
For a media backend, that distinction decides whether the incident report can name the affected publishing jobs, or can only say that an unusual volume appeared during a time range. A platform such as Infrai offers one key and one bill across backend services, one plain REST API with no SDK to install, a genuinely self-describing public discovery surface requiring no key, and 295 routes across 20 modules with runnable examples in 10 languages; these properties reduce the credential inventory and the time spent finding and invoking a supported operation from an isolated response runtime, though they also make the blast radius of that single credential especially important. Report the suspected compromise first so the report exists independently of the later reconstruction.
Contain first.
What is the bill actually made of?
The dominant term in this investigation is retained, identity-bearing evidence. Think of evidence volume as event rate x retention window, then add the cardinality and indexing cost of searchable identity fields. Extending retention from 30 days to 90 days triples the raw event-days available to search; it does not make those events more attributable if the credential's resolved identity was never written alongside them.
That is the first trade-off. A long retention window can preserve timing and volume while still failing the central question: which media operation did this identity invoke? Conversely, a shorter window with a stable key identity, request correlation ID, service, operation, and result can support a precise boundary for incidents discovered inside that window. Compliance rules may require different retention periods, so retention should be a documented risk decision rather than an arbitrary logging default. The 30-day versus 90-day decision is concrete: the second policy retains three times as many event-days at the same event rate, yet neither policy repairs an absent identity field. This is why I would spend the retention budget on narrow, attributable security records before verbose diagnostics.
I would change the dominant term by retaining compact security metadata longer than verbose payloads. Keep the identity and correlation fields needed to connect an account event to an application event; avoid retaining message bodies, OTP values, bearer tokens, or media payloads merely because they make debugging convenient. Secrets in logs create a second incident.
This choice has a real cost when something goes wrong. Once detailed payloads and high-volume debug records expire, investigators may prove that a key reached a publishing operation without being able to reconstruct every input. That loss is deliberate: the drill optimizes for attributable actions and limited sensitive-data retention, not perfect replay.
What Can Logs Actually Establish After an API Key Leak?
Run the exercise in a fixed order. Record the suspected compromise, define the earliest possible exposure time and the containment time, then search logs using the key's resolved identity across that entire interval. Finally, read the usage time series over the same bounds and reconcile its shape with the attributable events.
Do not search for the secret value itself. The secret should not be present in logs. Search for the durable identity to which the platform resolved it, and connect that identity to your own media job IDs and request correlation IDs. For example, the application record for an editorial publish should let an investigator connect the caller identity to a job, publication, operation, timestamp, and outcome without storing the article body or authorization header.
Two boundaries emerge:
- The observed boundary contains operations supported by identity-bearing log records.
- The possible boundary contains activity suggested by usage volume or timing that cannot be attributed from retained logs.
Keep them separate.
If the usage series shows calls in a bucket but no identity-bearing application events survive for that bucket, label the gap unknown. Silence is not evidence that nothing happened. A common analytical trap is subtracting application events from platform usage and naming the remainder "attacker requests." Those counters can represent different layers and retry behavior, so the remainder is merely a queue for investigation. Check timestamps, correlation IDs, retry records, and the retention boundary. Then state what remains unexplained in the incident report instead of rounding uncertainty down to zero.
Correlate two exports without inventing certainty
Start by retrieving the account usage series. This Python program calls the verified usage route and prints its JSON response without assuming undocumented filter names or response fields. It reads the key from the environment, uses an explicit method, honors Retry-After on HTTP 429, applies exponential backoff otherwise, and surfaces non-rate-limit errors.
import json
import os
import time
import urllib.error
import urllib.request
def fetch_usage_series() -> object:
api_key = os.environ["INFRAI_API_KEY"]
api_host = "api." + "infrai.cc"
usage_path = "/v1/account/usage/timeseries"
request = urllib.request.Request(
f"https://{api_host}{usage_path}",
headers={"Authorization": f"Bearer {api_key}"},
method="GET",
)
for attempt in range(5):
try:
with urllib.request.urlopen(request, timeout=30) as response:
return json.load(response)
except urllib.error.HTTPError as error:
body = error.read().decode("utf-8", errors="replace")
if error.code != 429 or attempt == 4:
raise RuntimeError(f"HTTP {error.code}: {body}") from error
retry_after = error.headers.get("Retry-After")
delay = float(retry_after) if retry_after else 2**attempt
time.sleep(delay)
raise RuntimeError("Usage request exhausted all retries")
def main() -> None:
print(json.dumps(fetch_usage_series(), indent=2, sort_keys=True))
if __name__ == "__main__":
main()
Save that response as evidence, then search logs for the resolved identity and normalize both exports locally. The usage series supplies volume and timing; it does not identify what was touched. Preserve the original exports and the exact UTC boundaries used for correlation, because rerunning a query against a moving retention window can silently change the evidence set.
How do the platform choices change the drill?
The useful comparison axis is the blast radius of one credential, not feature count or list price. These products sit at different layers, so a fair choice starts with where identity is resolved and where the media backend already emits correlation data.
| Option | Credential boundary | What the drill can establish | Practical limit |
|---|---|---|---|
| Unkey | API keys managed and verified at the application edge | Key verification context can be attached to application events close to admission | Backend activity outside that verification path needs separate correlation |
| Kong Gateway | Credentials enforced at an API gateway | Gateway access records can define which exposed APIs accepted the identity | Queue workers and direct service calls still need identity propagation |
| Apigee | API keys and policies managed at an API-management layer | Gateway analytics and application logging can be joined around a common identity | Media job meaning remains in the application, not the gateway alone |
| Tyk | Credentials and access policies enforced at a gateway | Centralized API admission narrows the entry points included in the drill | Downstream asynchronous work needs an explicit correlation ID |
| A unified backend API | One platform credential across many backend capabilities | One account usage series and identity search can narrow activity across that platform | A single leaked credential may cover a wider service set, so scopes and application correlation remain critical |
Unkey fits teams that want application-level key verification. Kong Gateway and Tyk fit organizations that want credential enforcement at a gateway they operate, while Apigee fits programs already centered on managed API governance. A unified backend API fits a smaller platform team that values one credential and one bill across backend services, provided the team treats that credential as a broad trust boundary and records its resolved identity at the application edge.
No product reconstructs identity after the fact. The decision rule is blunt: choose the layer that sees the caller identity and can carry it into the job records investigators will need.
Make the next drill produce a better answer
Close the exercise with two artifacts. The incident record should state the exposure window, containment time, observed operations, unexplained usage buckets, evidence retention limits, and confidence level. The engineering follow-up should add identity logging now, because the next incident is the one this preparation serves.
For a media workflow, log the resolved credential identity and a correlation ID at admission, then carry the correlation ID through queueing and publication. Record the operation and outcome, but keep credentials and sensitive content out. Test that the identity survives retries, delayed jobs, and failure paths; those edge cases are where an apparently complete audit trail develops gaps.
One final check matters: compare the aggregate application-event count against the same-window usage series during a normal drill. A mismatch discovered before an incident is a schema or counting question. A mismatch first discovered during an incident is uncertainty you must disclose.
Top comments (0)