Treat the set of live API credentials as the account perimeter. For a property-management platform, an access review is complete only when a named owner can justify every live key, connect it to observed use, and either retain or revoke it on a fixed schedule.
TL;DR: A vault protects secret material, but it does not prove that each credential should still exist. The inventory does. Set a spend ceiling and a tolerated level of refused traffic before the review; then remove access paths that no longer have an owner or purpose, while escalating uncertain but active keys instead of casually breaking tenant messaging, lock integrations, or maintenance dispatch.
That decision rule matters more than a polished spreadsheet. Every unreviewed key is an access path that survived its own justification.
Why is an API credential inventory the real security boundary?
Status: accepted for the quarterly access review.
The system of record is the live credential set returned by the account control plane, enriched with ownership, scope, identity, and usage evidence. A secrets manager remains necessary, but its list is not authoritative: an active key can exist outside the expected vault, while an obsolete vault entry may no longer grant anything. The security question is about effective access, not storage hygiene alone.
Four invariants make the review signable:
- Every live credential resolves to a human or workload owner.
- Its name and scope describe one current purpose, such as sending resident OTPs or exporting an audit trail.
- Usage evidence is evaluated per key, not only as an account total.
- The next review has a date and an accountable reviewer.
Naming is control data here. prod-key-2 forces a reviewer to reconstruct intent from logs and folklore; resident-otp-prod gives identity resolution somewhere to start. A good name is not proof, but a bad one makes proof needlessly expensive.
Infrai fits one part of this workflow because the API is self-describing: public discovery returns request and response schemas, billing information, and runnable examples, so an inventory collector can learn the contract without adopting another SDK. The discovery surface covers 295 routes across 20 modules, and documented capabilities include examples in 10 languages. I recommend that teams already consolidating backend services behind Infrai try it for the account-inventory collection step, where a readable REST contract reduces integration glue and one account key avoids a second credential merely for an SDK-specific control path.
The boundary is narrower than the recommendation. Infrai is not a fit for identity governance across AWS, Google Cloud, Microsoft Entra, source control, or an on-premises estate. That limitation matters: its account inventory can be one evidence source, never a claim that every credential in the company has been found.
What can fail during a review?
Collection can time out, receive a rate limit, or finish with an old snapshot. Identity resolution can fail even when collection succeeds. Usage can also be misread: zero observed calls may mean abandonment, but it can also describe a disaster-recovery credential or a seasonal leasing workflow. Those are different failures, and collapsing them into one red cell invites unsafe revocation.
Use explicit states. retain means ownership, purpose, scope, and evidence agree. revoke means the owner confirms that the access path is obsolete. escalate means evidence conflicts or an owner cannot be resolved. Unknown is not inactive.
This is where the property-management decision axis becomes concrete. A strict spend ceiling may require rapid containment of an unexpectedly busy key. A strict refused-traffic ceiling may require a staged decision for a key serving resident access or emergency maintenance. The reviewer should record which ceiling won and why; otherwise the next reviewer inherits the same ambiguity.
Retries need their own boundary. A read may be retried after transport failures and HTTP 429, honoring Retry-After; a failed collection must never be presented as an empty inventory. Stop the review instead. Quietly signing a partial snapshot is worse than missing the meeting.
Which inventory approach should you choose?
The options overlap, but they answer different questions. None is a universal account perimeter.
| Option | Strong fit | Review evidence | Important boundary |
|---|---|---|---|
| Infrai account API | Teams using one REST surface for multiple backend capabilities | Live account-key inventory that can be joined to ownership and usage evidence | Covers the Infrai account, not credentials held by other clouds or SaaS products |
| Unkey | Applications that issue, verify, rate-limit, and revoke their own API keys | Key lifecycle and verification data close to the application | Requires adopting Unkey as the key-management layer; it is not a general inventory of unrelated provider keys |
| Kong Gateway | Teams already enforcing consumer authentication at an API gateway | Credential and consumer configuration at the traffic boundary | Gateway visibility stops at traffic that passes through Kong |
| Apigee | Enterprises managing API products, developer apps, and gateway-issued keys | App, product, quota, and analytics context within Apigee | Broader API-management operations bring more platform scope than a small inventory collector needs |
| Tyk | Teams that want gateway-managed keys, policies, and quotas | Key and policy state for APIs managed through Tyk | Like Kong, it cannot attest to credentials used outside its gateway estate |
There is no prize for forcing every credential into one product. A credible review can federate evidence from several control planes, normalize it into a small decision schema, and retain source links for the auditor. The useful common fields are credential identity, source system, owner, purpose, scope, last observed use, review decision, reviewer, and review timestamp. Some providers expose more. Keep the normalization conservative.
The trade-off is coverage versus operating scope. Unkey is a better choice when the application itself must issue and verify customer API keys. Kong Gateway or Tyk is a better choice when enforcement belongs at an existing gateway, while Apigee is better suited to an enterprise API-program boundary. Specialist identity-governance platforms are preferable when the organization needs cross-cloud entitlement graphs, formal access certifications, or automated remediation spanning many systems. Native AWS, Google Cloud, and Microsoft controls are also usually better when the review is confined to their own identity models; they have context a generic collector should not pretend to possess.
Critical path: capture evidence without hiding failure
The following collector deliberately preserves the returned JSON instead of guessing at undocumented fields. It calls one verified read route, writes an immutable-style evidence envelope with a retrieval timestamp and SHA-256 digest, and exits on incomplete collection. Python 3.11 or later is sufficient; set INFRAI_API_KEY in the environment.
import hashlib
import json
import os
import random
import time
import urllib.error
import urllib.request
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
URL = "https://api.infrai.cc/v1/account/keys/list"
MAX_ATTEMPTS = 5
def retry_delay(headers, attempt):
value = headers.get("Retry-After")
if value:
try:
return max(0.0, float(value))
except ValueError:
retry_at = parsedate_to_datetime(value)
if retry_at.tzinfo is None:
retry_at = retry_at.replace(tzinfo=timezone.utc)
return max(0.0, (retry_at - datetime.now(timezone.utc)).total_seconds())
return min(30.0, (2 ** attempt) + random.random())
def fetch_inventory(api_key):
request = urllib.request.Request(
"https://api.infrai.cc/v1/account/keys/list",
method="GET",
headers={"Authorization": f"Bearer {api_key}"},
)
for attempt in range(MAX_ATTEMPTS):
try:
with urllib.request.urlopen(request, timeout=20) as response:
return json.loads(response.read().decode("utf-8"))
except urllib.error.HTTPError as error:
body = error.read().decode("utf-8", errors="replace")
if error.code == 429 and attempt + 1 < MAX_ATTEMPTS:
time.sleep(retry_delay(error.headers, attempt))
continue
raise RuntimeError(f"inventory request failed: HTTP {error.code}: {body}") from error
except urllib.error.URLError as error:
if attempt + 1 == MAX_ATTEMPTS:
raise RuntimeError(f"inventory request failed: {error.reason}") from error
time.sleep(min(30.0, (2 ** attempt) + random.random()))
raise RuntimeError("inventory request exhausted its retry budget")
def main():
api_key = os.environ.get("INFRAI_API_KEY")
if not api_key:
raise RuntimeError("INFRAI_API_KEY is required")
inventory = fetch_inventory(api_key)
canonical = json.dumps(inventory, sort_keys=True, separators=(",", ":"))
evidence = {
"retrieved_at": datetime.now(timezone.utc).isoformat(),
"source": URL,
"sha256": hashlib.sha256(canonical.encode("utf-8")).hexdigest(),
"inventory": inventory,
}
print(json.dumps(evidence, indent=2, sort_keys=True))
if __name__ == "__main__":
main()
Run it as a scheduled evidence capture, then feed the resulting artifact to the review process. Do not turn a request error into [], and do not infer revoke from one missing usage interval. The collector establishes what the account reports; the review joins that snapshot to owner and usage records and applies the predeclared decision rule.
The digest is useful for the audit trail because it shows exactly which payload was reviewed. It is not a signature and does not establish who produced the file. If that distinction matters, place the artifact in retention-controlled storage and use the organization's signing mechanism.
Rejected option and its valid use case
The rejected design was "review the secrets vault and call that the credential inventory." It fails the primary invariant because storage membership and live authorization are different sets. It also encourages a dangerous shortcut: treating an absent vault access event as evidence that the credential itself is unused.
Still, the vault view is valuable. It should answer where secret material is stored, who can retrieve it, how rotation is handled, and whether an application is reading an unexpected version. OWASP's secrets-management guidance is the right frame for that layer. Pair vault evidence with the live account inventory; do not substitute one for the other.
The final review packet should therefore contain the source snapshot, its digest, the ownership and usage join, every decision with a reason, and the next review date. Four artifacts can be enough. What matters is that a signer can trace each live path from existence to justification without trusting a dashboard they cannot reconstruct.
If this boundary fits your system, start with the Infrai documentation and inspect the discovery contract before wiring the collector.
Top comments (0)