Skip to content

fix(ias): verify JWT signature before stamping telemetry and audit identity - #371

Draft
tiagoek wants to merge 1 commit into
mainfrom
fix/ias-jwks-verified-telemetry
Draft

tiagoek wants to merge 1 commit into
mainfrom
fix/ias-jwks-verified-telemetry

Conversation

@tiagoek

@tiagoek tiagoek commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Summary

StarletteIASTelemetryMiddleware was calling parse_token() — a deliberately unverified JWT decoder — and promoting the decoded sap_gtid/user_uuid directly onto OTel span attributes (sap.tenancy.tenant_id, user.id) and the IAS auth context (used by AuditClient auto-fill). An attacker could forge a JWT carrying a victim tenant/user ID and permanently pollute telemetry and audit attribution.

Root cause: no signature verification before stamping security-sensitive span attributes or setting the auth context.

Fix (SDK-only — no consumer changes required):

  1. New IASVerifier class — JWKS-backed verifier, auto-configured from the SAP BTP Identity service binding (VCAP_SERVICES on CF, IAS_URL env var on Kubernetes). Caches signing keys internally and handles key rotation transparently.
  2. New VerifiedIASClaims frozen dataclass — the SDK's provenance marker. Instances can only come from a verifier that ran signature + issuer + algorithm + expiry checks.
  3. StarletteIASTelemetryMiddleware now auto-configures IASVerifier.from_env() at construction. Verified claims flow to both set_auth_context and OTel span attrs — forged tokens result in None auth context and empty identity attrs. No consumer code changes needed.

Behaviour change

Scenario Before After
IAS service binding present (CF or K8s) Unverified claims stamped + set in auth context Verified-only claims stamped + set in auth context automatically
No IAS binding / env var Unverified claims stamped No identity attrs + WARNING logged; app starts normally
Forged JWT (attacker-signed) Victim tenant_id/user.id stamped and in auth context Nothing stamped, auth context set to None
x-sap-origin header Always stamped Always stamped (unchanged — not JWT identity)

Zero-config usage

from starlette.applications import Starlette
from sap_cloud_sdk.core.telemetry import auto_instrument
from sap_cloud_sdk.core.telemetry.middleware import StarletteIASTelemetryMiddleware

app = Starlette(...)
# Auto-configures IASVerifier from VCAP_SERVICES (CF) or IAS_URL (K8s)
auto_instrument(middlewares=[StarletteIASTelemetryMiddleware(app=app)])

Agents that already have an IAS service binding get verified telemetry and auth context with zero code changes.

Apps without an IAS service binding

Identity span attributes will not be stamped and a WARNING is logged at startup — the app continues running normally. Bind an SAP Identity service instance to restore them.

For advanced scenarios (e.g. Istio/Kyma already verified the token), a custom verifier can be passed via token_verifier=. See IAS user guide for details.

Scope

  • SDK only. No consumer app changes.
  • parse_token() is unchanged — still available as an unverified claim extractor (diagnostics, pre-auth inspection).
  • AuditClient is unchanged — set_auth_context now only receives verified claims, so any auto-fill downstream is also protected.

Files changed

File Change
src/sap_cloud_sdk/ias/_verifier.py NEW — IASVerifier + IASConfigError
src/sap_cloud_sdk/ias/_token.py Added VerifiedIASClaims, TokenVerifier
src/sap_cloud_sdk/ias/__init__.py Export new types; preserve get_auth_context, set_auth_context
src/sap_cloud_sdk/core/telemetry/middleware/starlette_a2a.py Auto-configure IASVerifier; verified claims to both auth context and OTel attrs
tests/ias/unit/test_verifier.py NEW — 20 tests for IASVerifier
tests/core/unit/telemetry/middleware/test_starlette_a2a.py Rewritten with auto-config + auth-context coverage + regression tests

…entity

StarletteIASTelemetryMiddleware was calling parse_token() (unverified JWT
decoder) and promoting sap_gtid/user_uuid onto OTel span attributes and the
IAS auth context. An attacker could forge a JWT carrying a victim tenant/user
ID and permanently pollute telemetry and AuditClient attribution.

- Add IASVerifier: JWKS-backed verifier with PyJWKClient, RS256/ES256 alg
  pinning, issuer/audience/exp/nbf enforcement, key caching and rotation
- Add IASVerifier.from_env(): auto-configures from VCAP_SERVICES (CF) or
  IAS_URL/IAS_CLIENT_ID env vars (K8s); raises IASConfigError if not found
- Add VerifiedIASClaims frozen dataclass as provenance marker; add TokenVerifier
  type alias to sap_cloud_sdk.ias public API
- StarletteIASTelemetryMiddleware auto-calls IASVerifier.from_env() at init;
  logs WARNING and disables identity attrs if no binding found (fail-closed)
- _verify_and_extract calls verifier once per request; verified IASClaims flow
  to both set_auth_context (AuditClient) and OTel span attrs — forged tokens
  result in None auth context and empty identity attrs
- parse_token() unchanged — available as unverified diagnostic decoder
- 488 tests pass (22 new for IASVerifier, rewritten middleware tests with
  auto-config and auth-context coverage)

This branch has not been deployed

No deployments
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.

1 participant