Commit 979250ea authored by Sergio Gimenez's avatar Sergio Gimenez Committed by Dimitrios Gogos
Browse files

feat: add ADR-0038 — EWBI auth is OAuth2 via Keycloak; mTLS deferred

E/WBI authorization is OAuth2 Client-Credentials + signed JWT (JWS, RFC 7515) via
the platform's centralized Keycloak in a dedicated federation realm, per GSMA
OPG.04 v6.0 Sec. 9. mTLS is not removed — it is deferred as defense-in-depth
(sender-constrained tokens, RFC 8705) until real Nginx mTLS termination exists.

Corrects ADR-0016's passing mTLS assumption: today's cert-thumbprint header is
not real authentication (no TLS client-certificate handshake behind it), so it
cannot satisfy REQ-FED-01 on its own. The platform already runs centralized
Keycloak for OEG and FM admin routes; this extends that pattern with a separate
federation realm for the external partner trust domain.

Renumbered from 0037 to 0038 (slot 0037 is taken by canonical-target-ports on
develop).

Refs: oop/code/federation-manager#13, #18
parent 2ec1168c
Loading
Loading
Loading
Loading
+48 −0
Changes for decisions/0042-ewbi-oauth2-client-credentials-mtls-deferred.md: 48 added lines, 0 removed lines.
Original line number Diff line number Diff line
---
type: Decision Record
title: "ADR-0042: EWBI authorization is OAuth2 Client-Credentials via centralized Keycloak; mTLS is deferred defense-in-depth"
description: "FM authorizes E/WBI requests with OAuth2 Client-Credentials + signed JWT (OPG.04 Sec. 9), issued by the platform's centralized Keycloak in a dedicated federation realm; mTLS is not built yet and is reclassified as a future layer, not the primary mechanism"
tags: [adr, fm, federation, security]
timestamp: 2026-08-06T00:00:00Z
status: "accepted"
---

# ADR-0042: EWBI authorization is OAuth2 Client-Credentials via centralized Keycloak; mTLS is deferred defense-in-depth

**Status:** accepted
**Date:** 2026-08-06
**Affects:** [fm/requirements-and-design.md](/fm/requirements-and-design.md), [fm/overview-and-architecture.md](/fm/overview-and-architecture.md), [fm/implementation-and-delivery.md](/fm/implementation-and-delivery.md), [fm/persistence-model.md](/fm/persistence-model.md), [platform/architecture.md](/platform/architecture.md), [platform/future-architecture.md](/platform/future-architecture.md), [ADR-0016](0016-fm-python-fastapi-stack.md)

## Context

FM's specs (REQ-FED-01, ADR-0016) currently describe mTLS with pre-exchanged client certificates as *the* E/WBI authorization mechanism: Nginx terminates mTLS and forwards the client-certificate thumbprint, FM looks it up in `partner_ops`.

Checked against GSMA OPG.04 v6.0's actual normative artifact — the OpenAPI 3.0.3 contract GSMA publishes alongside the PRD (Annex A; distributed separately as `OPG.04_EWBI_Federation_API_v1.4.0.yaml`), not just the PDF prose — the E/WBI Federation Management Service declares one root-level `security` requirement covering all 74 operations, with zero per-operation overrides and no mTLS securityScheme anywhere in the document:

```yaml
security:
  - oAuth2ClientCredentials: [fed-mgmt]
  - notifClientCredentials: [fed-mgmt-notif]
```

Sec. 9.2 assigns roles (Partner OP = Authorization + Resource Server, Originating OP = Client); Sec. 9.3 mandates signed JWT (JWS, RFC 7515); Sec. 9.5 requires the same grant for callbacks. Sec. 9's opening paragraph has one internally-contradictory hedge ("if OAuth2 is used") against otherwise-unconditional language throughout the rest of Sec. 9 and the contract itself — read as a drafting slip, not real optionality.

GSMA OPG.02 v10.0 Sec. 4.2.3 / Sec. 3.3.4.5 separately and explicitly sanctions certificate-based mutual authentication ("commonly used API authentication mechanisms, e.g. Public Key Certificates") for OP-to-OP *connection* identity — legitimate, but a different layer than Sec. 9's per-request *authorization*, and not what OPG.04's contract checks.

FM does not currently implement OAuth2/JWT for E/WBI at all. Real Nginx mTLS termination also does not exist yet — today's cert-thumbprint header is not derived from any actual TLS client-certificate handshake, so it proves no identity cryptographically; it is a partner lookup, not authentication.

The platform already runs a centralized Keycloak as core shared infrastructure (`core` Compose profile: PostgreSQL, Redis, NATS, Keycloak, Nginx; `platform/architecture.md` Security Architecture table), currently serving OEG's NBI auth and FM's own internal admin routes (both realm `oop`). This ADR extends that existing pattern rather than introducing a new one.

## Decision

1. **E/WBI authorization is OAuth2 Client-Credentials + signed JWT (OPG.04 Sec. 9), issued and validated via the platform's centralized Keycloak, in a dedicated `federation` realm** — separate from the `oop` realm used for internal admin and (via OEG) app-provider auth. Rationale for a separate realm: partner OPs are an external, adversarial-by-default trust domain; isolating it from internal/admin identity is standard practice and cheap given Keycloak already supports multiple realms on one deployment. Each partner relationship gets its own Keycloak client with the `fed-mgmt` scope (`fed-mgmt-notif` for callbacks); FM is both a Client (outbound calls to a partner's realm) and an Authorization+Resource Server (inbound calls, via its own realm) per OPG.04 Sec. 9.2.
2. **mTLS is not deleted, it is reclassified as deferred defense-in-depth.** `partner_ops.cert_thumbprint` stays in the schema as a future hook (e.g. RFC 8705 sender-constrained tokens once real Nginx mTLS termination exists); it is removed from today's authorization decision path. Today's cert-thumbprint-header check is not real authentication and must not be described as satisfying REQ-FED-01 on its own.
3. Signing is JWS (RFC 7515), matching Keycloak's default and OPG.04 Sec. 9.3's primary recommendation — not the Sec. 9.3 pre-shared-symmetric-key (MAC) alternative, which only earns its keep when there is no real Authorization Server to lean on. There is one.

## Consequences

FM gains a real dependency on the centralized Keycloak (already a platform dependency for OEG and FM's own admin routes, so no new infrastructure). FM must implement: inbound Bearer-JWT validation (signature via Keycloak's JWKS, issuer, expiry, `fed-mgmt` scope) replacing today's cert-thumbprint gate; outbound Client-Credentials token acquisition and caching before calling a partner. `partner_ops` needs OAuth2 client-credential fields per partner (client_id, and a reference to where the secret is stored) alongside the retained `cert_thumbprint` column.

Cost: FM does not get to skip Authorization Server work by leaning on Nginx alone — Nginx's role here stays limited to HTTPS termination and routing, not the authorization decision. Revisit trigger: real Nginx mTLS termination is deployed (ADR-0016's original assumption) — at that point, sender-constrained tokens (RFC 8705) can layer mTLS back in as defense-in-depth, per the E/WBI security model both GSMA documents (OPG.02 Sec. 4.2.3/3.3.4.5, OPG.04 Sec. 9) actually describe: connection-level mutual authentication *and* request-level OAuth2 authorization, stacked, not substituted.

This ADR does not change FM's stack choice (ADR-0016 stands); it corrects only the E/WBI authorization mechanism ADR-0016 assumed in passing.
+1 −0
Changes for decisions/index.md: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -44,3 +44,4 @@ the reasoning lives here. Never renumber; supersede instead (see the record-deci
* [ADR-0039](0039-source-spec-stated-by-publisher.md) - source_spec is stated by the publishing component (OEG from CAMARA, FM from OPG.04) on network capability commands; SRM never derives it from the envelope source and never synthesizes a family, API, or version
* [ADR-0040](0040-target-serveability-is-a-tri-state.md) - can_serve_target answers can_serve | unknown_subscriber | unsupported_identifier; a boolean cannot carry the 404/422 split §E.2 requires, and 404 needs positive evidence (supersedes ADR-0038's boolean)
* [ADR-0041](0041-tfsdk-owns-adapter-construction.md) - TF-SDK builds adapters behind a factory keyed by adapter kind; SRM resolves control_path_ref to an instance but never enumerates adapter kinds
* [ADR-0042](0042-ewbi-oauth2-client-credentials-mtls-deferred.md) - E/WBI authorization is OAuth2 Client-Credentials via centralized Keycloak (dedicated federation realm), per OPG.04 Sec. 9; mTLS deferred to future defense-in-depth once real Nginx termination exists