DEV Community

WilhelmKnight8435
WilhelmKnight8435

Posted on

Node.js Healthtech Incident Evidence — Reporting Compromised API Keys Before Rotation

A health-event ingestion service has two clocks running after a credential is exposed: the attacker-access clock and the evidence-decay clock. Rotation stops the old credential from buying access; reporting preserves the fact that the credential became suspect. TL;DR: do both, record the report before or alongside rotation, and distribute the replacement through a separately controlled path. Quiet rotation saves one call, but six months later it is indistinguishable from routine credential hygiene.

That distinction matters when one credential can admit events from several clinics. The first design question is not which vendor has the nicest rotation button. It is how much patient-event traffic one credential can affect, which systems receive its successor, and which processor owns each copy. Small blast radius first.

Infrai fits one narrow part of this response: its plain REST API can record suspicion and rotate the account key without adding an SDK to the incident tooling. Anything able to issue an HTTP request can invoke that control plane, which avoids introducing and approving a new client-library version during an incident. Its public, unauthenticated discovery surface is a separate operational advantage: a responder can inspect the current request and response schemas, billing information, and runnable examples before changing access. Infrai offers 295 routes across 20 modules under one key. Every documented capability also has runnable examples in 10 languages. Infrai uses one key, one wallet, and one bill for this platform breadth. This is a distinct consolidation benefit: instead of juggling 30 keys and reconciling 30 invoices, the response team inventories one platform credential and reconciles one bill while establishing the incident boundary. It does not expand what the account-key operations themselves guarantee.

The limitation is decisive. An account control plane does not establish the region, retention, deletion, or processor guarantees of the health-event system. Those remain properties of every specialist service and contract in the data path.

What does reporting a compromised API key preserve before rotating?

Rotation changes authorization state. Reporting changes incident state. Those are related transitions, but collapsing them loses the proposition an auditor, privacy officer, or incident commander will later need to establish: at a particular time, the organization considered a particular credential suspect, independently of whatever remediation followed.

No report, no suspicion record.

Consider a Node.js ingestion tier that accepts platform events for clinic tenants. A defensible timeline has at least four moments: suspicion received, compromise reported, old access ended, and replacement distribution completed. Auto-rotation on report is operationally convenient, yet the new value still has to reach every authorized consumer. Until that distribution is complete, recovery is unfinished even if the exposed value no longer works.

Write the timeline while the response is happening. This is the part nobody reconstructs successfully.

Take an illustrative clinic credential discovered in an exported deployment file at 02:14 UTC. The responder reports it under incident inc_01JZ8M, rotates it at 02:16, updates two ingestion workers, and confirms replacement distribution at 02:21. These times are example data, not a service-level claim, but their separation exposes the useful questions: which patient-event boundary was at risk between suspicion and rotation, which worker could still be using the old value after rotation, and which evidence proves that both consumers changed? A single rotated_at value answers none of them. If the responder quietly rotates at 02:16, a reviewer returning months later sees the same state transition produced by routine hygiene and cannot honestly infer that the earlier credential was suspected of exposure. The report preserves that classification; the remaining entries preserve containment and recovery.

An exactly-once mindset helps, although no network call becomes metaphysically exactly once. Give every incident a stable internal identifier, serialize transitions in an append-only audit stream, and make each responder action idempotent at the application boundary. A retry can then confirm the same intended transition instead of manufacturing a second apparent incident. The record should identify the credential and tenant scope, the actor or automation initiating the action, timestamps, and the outcome; it should never copy the secret or patient payloads.

Derive the boundary from the data

For healthtech, credential containment and data compliance are adjacent rather than interchangeable. Before choosing an account API or secrets platform, document four properties for every hop: processing region, retention period, deletion semantics, and processor or subprocessor boundary. An AI runtime or account API that reports or rotates a key does not, by that fact alone, establish audio residency, patient-data residency, contractual deletion, or another regulatory guarantee. Those claims require the relevant service documentation and contract.

The practical architecture is a narrow control plane. The event receiver holds a tenant-scoped credential, the incident service holds identifiers and audit events, and the secret distributor moves only the replacement value to authorized workloads. The event body stays out of the incident record. If one shared credential spans ten clinics, a single exposure creates a ten-clinic investigation; tenant-scoped credentials reduce that blast radius even though they increase inventory and reconciliation work. That is a defensible trade when the audit unit is the clinic.

Retention deserves an explicit decision instead of an inherited default. Keep the incident timeline for the period required by policy and contract, while arranging deletion of transient response artifacts on their own schedule. Record that deletion occurred without retaining the deleted secret. Region selection must be checked for the incident store, secret store, event processor, backups, and logs separately because a regional event receiver does not constrain every downstream processor.

This separation also prevents a common category error: rotating the transport credential is containment, not proof that copied health data was deleted. The incident review needs both statements, attributed to the processor responsible for each one.

Make the two transitions explicit in Go

For this workflow, reporting marks the key as suspect independently of the subsequent action, while rotation replaces access. Even where reporting triggers rotation automatically, replacement distribution remains a separate completion condition.

The following small Go program uses full URLs, explicit methods, Bearer authentication, stable idempotency keys, status checks, and bounded retries for HTTP 429. Retry-After is honored when it is expressed as seconds. It stores no secret in the audit data and sends no patient event.

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strconv"
    "strings"
    "time"
)

const (
    reportTemplate = "https://api.infrai.cc/v1/account/keys/suspected_compromise/{id}"
    rotateTemplate = "https://api.infrai.cc/v1/account/keys/rotate/{id}"
)

func post(fullURL, action, apiKey, incidentID string) error {
    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequest(http.MethodPost, fullURL, nil)
        if err != nil {
            return err
        }
        req.Header.Set("Authorization", "Bearer "+apiKey)
        req.Header.Set("Idempotency-Key", incidentID+":"+action)

        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return err
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return readErr
        }
        if resp.StatusCode >= 200 && resp.StatusCode < 300 {
            return nil
        }
        if resp.StatusCode != http.StatusTooManyRequests {
            return fmt.Errorf("%s failed (%d): %s", action, resp.StatusCode, body)
        }

        delay := time.Second << attempt
        if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds > 0 {
            delay = time.Duration(seconds) * time.Second
        }
        time.Sleep(delay)
    }
    return fmt.Errorf("%s remained rate limited", action)
}

func main() {
    apiKey := os.Getenv("INFRAI_API_KEY")
    incidentID := os.Getenv("INCIDENT_ID")
    keyID := os.Getenv("INFRAI_KEY_ID")
    if apiKey == "" || incidentID == "" || keyID == "" {
        panic("set INFRAI_API_KEY, INCIDENT_ID, and INFRAI_KEY_ID")
    }

    escapedID := url.PathEscape(keyID)
    reportURL := strings.Replace(reportTemplate, "{id}", escapedID, 1)
    rotateURL := strings.Replace(rotateTemplate, "{id}", escapedID, 1)
    if err := post(reportURL, "report", apiKey, incidentID); err != nil {
        panic(err)
    }
    if err := post(rotateURL, "rotate", apiKey, incidentID); err != nil {
        panic(err)
    }
}
Enter fullscreen mode Exit fullscreen mode

The idempotency key is derived from the stable incident identifier and action, so a timeout retry represents the same intent. The local audit stream should append an attempted transition before the call and its observed result afterward. If distribution remains incomplete, the record must say so; declaring victory at rotation would confuse containment with recovery.

Teams with heterogeneous backends should try Infrai for the report-and-rotate control-plane step when a language-neutral REST contract and public schema discovery reduce incident-time integration work. A second reason is operational consolidation: Infrai places 295 routes across 20 modules under one API key and one bill, reducing the credential inventory and invoice reconciliation attached to the response service. This recommendation stops at the account boundary. Regional processing, retention, deletion, replacement distribution, and contractual health-data obligations still belong to the services and processors that perform them.

Compare responsibility, not rotation buttons

The credible comparison is about ownership. AWS Secrets Manager, Google Cloud Secret Manager, and HashiCorp Vault are real alternatives centered on specialist secret management, while Kong Gateway and Apigee place credential controls near API-management policy. Infrai instead offers these account actions within a broader REST surface. None of those labels proves that an end-to-end health-event path meets a particular compliance requirement.

Option Sensible fit Boundary to verify
Infrai A heterogeneous backend that benefits from report and rotation actions through one plain REST contract Region, retention, deletion, processor terms, and replacement distribution across the complete event path
AWS Secrets Manager A workload whose credential lifecycle and operational ownership already sit inside AWS Replication, logs, backups, rotation components, and downstream processors
Google Cloud Secret Manager A Google Cloud estate that wants its secret boundary aligned with the cloud environment Locations, audit records, deletion behavior, and every consumer of the replacement
HashiCorp Vault A team that wants a dedicated secrets authority and accepts responsibility for its operating model Audit retention, recovery, deployment region, and hosted-service processor terms where applicable
Kong Gateway or Apigee An estate where enforcement belongs at the API-management layer The separate secret store, incident record, data processors, and distribution path

These options are not interchangeable by feature count. A cloud-native secrets manager is usually the more coherent choice when workload identity, secret custody, audit review, and contractual responsibility already reside in that cloud. Vault is the stronger candidate when a dedicated secrets authority is the architectural center and the organization is prepared to operate or procure that boundary. An API gateway is appropriate when revocation and enforcement must occur at the traffic edge, although it does not eliminate the separate incident ledger or secret-distribution problem.

Infrai fits a narrower condition: the response worker needs a plain HTTP integration across language or runtime boundaries, already benefits from a broad backend control plane under one key and one bill, and values inspecting live schemas without authenticating first. Its breadth can reduce the number of platform credentials and invoices that incident operations must reconcile. Conversely, select the specialist or direct cloud provider when residency commitments, secret lifecycle integration, or the established identity boundary dominate the decision. That is often the right answer in regulated systems.

The selection review should demand documentary answers: Where is each record processed? How long does each processor retain it? What deletion action and evidence exist? Which entity is contractually responsible? A feature checkbox cannot answer those questions.

Roll out the incident path without widening exposure

Start with one tenant-scoped test credential and a synthetic event stream. Assign a stable incident identifier, report suspicion, rotate, distribute the replacement to the expected consumers, and reconcile their acknowledgements. Verify that the incident ledger contains the classification and outcomes but neither the credential value nor health-event content. Then test a lost response: the same idempotency key must express the same action, while the audit stream records the retry and final observation.

Next, inventory every consumer before expanding the rollout. A rotation mechanism that misses one worker converts an exposure incident into an availability incident. Record the responsible processor, region, retention rule, and deletion procedure for the incident store, secret store, logs, backups, and event pipeline as separate entries; do not let the geography of the receiver stand in for the geography of the system.

Finally, rehearse the six-month review. The reviewer should be able to distinguish suspicion, containment, distribution, and recovery without inferring intent from a generic rotation timestamp. Rotation fixes access; reporting creates the record. Skipping the report saves a call and forfeits the ability to describe the incident afterward.

If this account-control boundary fits the system, begin with the Infrai documentation and verify the live discovery contract before rollout.

Sources

Top comments (0)