Skip to content

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

Open
tiagoek wants to merge 8 commits into
mainfrom
fix/ias-telemetry-verified-claims
Open

tiagoek wants to merge 8 commits into
mainfrom
fix/ias-telemetry-verified-claims

Conversation

@tiagoek

@tiagoek tiagoek commented Oct 7, 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)
Fix ruff-format violations in starlette_a2a.py and ias/__init__.py
(multi-line imports and method signature wrapping) and bump patch
version to 0.57.3 to satisfy the version-bump CI check.
Add a "Verified Claims" section to the IAS user guide covering
IASVerifier, VerifiedIASClaims, and zero-config middleware usage.
Update the telemetry user guide to document token verification
behaviour, the fail-closed default, and the custom verifier option.
@tiagoek
tiagoek force-pushed the fix/ias-telemetry-verified-claims branch from 453ce63 to 3f1a85d Compare October 7, 2026 18:41
Comment thread src/sap_cloud_sdk/ias/user-guide.md Outdated
Keep each prose paragraph on a single line so Markdown renders correctly
and the raw text is easier to read — addresses review feedback.
Extend the three-step lookup in from_env() with a new step 2 that reads
the identity-service secret from the volume mount at
/etc/secrets/appfnd/identity-service/default/ (url + clientid fields).

The mount is populated automatically by the agent deployment template
(via the existing identity-service PushSecret), so agents need no
app.yaml changes to get zero-config IAS verification.

Lookup order: VCAP_SERVICES → K8s mount → IAS_URL env var.
Comment thread src/sap_cloud_sdk/ias/_verifier.py Fixed
Comment thread src/sap_cloud_sdk/ias/_verifier.py Fixed
tiagoek and others added 3 commits October 8, 2026 15:56
…f sensitive information'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

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.

3 participants