Skip to content

feat(auth): record peer address and request ID on authentication events - #4673

Merged
krishicks merged 1 commit into
mainfrom
feat/2912-auth-event-origin/krishicks
Oct 16, 2026
Merged

krishicks merged 1 commit into
mainfrom
feat/2912-auth-event-origin/krishicks

Conversation

@krishicks

@krishicks krishicks commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Gateway authentication failure events now record where the request came from and its request ID, so operators can tell which client was rejected and join the event to other logs for the same request.

Related Issue

Refs #2912

This is the third of several PRs that together satisfy #2912, so it does not close the issue. The remaining work is listed under Follow-ups.

Changes

  • src_endpoint is the connection's immediate peer address (IPv4-mapped IPv6 addresses are normalized to IPv4). Behind a proxy or load balancer, that is the proxy's address. Requests carried over the WebSocket tunnel endpoint record edge-tunnel as the endpoint name.
  • metadata.correlation_uid is the request's x-request-id, the same value the gateway returns to the caller. Only canonical UUIDs are recorded because the header is client-controlled.
  • openshell-ocsf: Endpoint.name, Metadata.correlation_uid, and AuthenticationBuilder::correlation_uid. Shorthand output falls back to the endpoint name when there is no domain or IP.
  • The router receives the connection source from each serve* entry point and attaches it to requests.
  • The RefreshSandboxToken handler's authentication events carry the same fields.
  • Docs: ocsf-json-export.mdx describes both fields.

No other request headers are recorded.

The examples below show what an authentication failure event looked like before this PR and what it looks like now, for each way a request can reach the gateway. Expand the section for details.

Before and after examples

Take a CLI whose OIDC token has expired and that calls ListSandboxes. Before this PR, the gateway logged:

AUTH:LOGON [LOW] DENIED unknown [protocol:OpenID op:/openshell.v1.OpenShell/ListSandboxes reason:expired_credential]

The event shows that a request failed and why. It does not show who sent the request, and nothing ties it to the client's error or to the gateway's request trace. A burst of invalid_credential events from one source looks the same as scattered failures from many clients.

With this PR, the same request logs:

AUTH:LOGON [LOW] DENIED unknown from 198.51.100.23:51234 [protocol:OpenID op:/openshell.v1.OpenShell/ListSandboxes reason:expired_credential]

The JSONL record gains two fields. Everything else is unchanged:

{
  "metadata": {
    "correlation_uid": "8b6f0c52-3d1e-4f7a-9c2b-5e4d3a2f1b0c",
    ...
  },
  "src_endpoint": {
    "ip": "198.51.100.23",
    "port": 51234
  },
  ...
}

What each field contains depends on how the request arrived:

Circumstance src_endpoint metadata.correlation_uid
Client connects to the gateway directly Client IP and port Request ID
Gateway behind a proxy or load balancer Proxy's IP and port, not the client's Request ID
Request over the WebSocket edge tunnel {"name": "edge-tunnel"}, shorthand from edge-tunnel Request ID
Client sends a non-UUID x-request-id As above Omitted

The request ID is the x-request-id the gateway returns to the caller. The gateway generates one when the client sends none, so it is normally present. The same value appears as request_id on the gateway's request trace span, so the event can be joined to the caller's error and to the trace. Shorthand output doesn't show it; it appears only in JSONL.

X-Forwarded-For is not used because clients can set it. Tunneled requests don't yet record the address of the tunnel's own connection. That is a follow-up.

Testing

  • cargo nextest run -p openshell-server -p openshell-ocsf (2567 passed)
  • cargo clippy --workspace --all-targets -- -D warnings
  • Unit tests added/updated: peer and edge-tunnel endpoints, request ID filtering, shorthand fallback, and an end-to-end test that the event's correlation_uid matches the x-request-id returned to the caller
  • E2E tests added/updated (not applicable)

Follow-ups

  • Source address of the edge tunnel's own connection on tunneled requests
  • Opt-in authentication success events
  • Authorization denial events (API Activity), with a dual-emitted Detection Finding for cross-sandbox and admin-only attempts by sandbox principals
  • Remaining paths: SSH tokens and IssueSandboxToken

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)

Authentication events now carry the connection's immediate peer as
src_endpoint, or edge-tunnel for WebSocket-tunneled requests, and the
request's x-request-id as metadata.correlation_uid when it is a UUID.

Refs #2912

Signed-off-by: Kris Hicks <khicks@nvidia.com>
@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

Compatibility review (advisory)

New or updated breaking changes; see the full report for all findings.

1. api-behavior — No explicit risk acceptance found

Authentication events previously never included request-header values; they now write a UUID-form x-request-id to metadata.correlation_uid.

  • Impact: Operators relying on the documented header-free audit boundary now persist caller-controlled values in gateway OCSF records.
  • Action: For v0.1.5, stop populating metadata.correlation_uid from x-request-id; otherwise defer the change to a minor release with notice and actionable log-retention or scrubbing guidance.
  • PR: feat(auth): record peer address and request ID on authentication events #4673
Review details
  • Execution: complete
  • Candidate: PR #4673 (e7c879948ec57dbc258a84ddc220b3160b57b679)
  • Baseline: 604b9f66f685c582114cd571ae3a10accec23ec2 (604b9f66f685c582114cd571ae3a10accec23ec2)
  • Reviewed: rust-sdk, python-sdk, go-sdk, typescript-sdk, api-behavior, cli, configuration, policy, helm, state

Advisory review; publication gates are unchanged.

Branch check run

@krishicks
krishicks added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit f41f24b Oct 16, 2026
83 checks passed
@krishicks
krishicks deleted the feat/2912-auth-event-origin/krishicks branch October 16, 2026 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants