Commit c0775aab authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

docs: remove mentions of nginx and artefact manager

parent c3d0b8ef
Loading
Loading
Loading
Loading
+42 −49

File changed.

Preview size limit exceeded, changes collapsed.

+10 −11
Changes for fm/implementation-and-delivery.md: 10 added lines, 11 removed lines.
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ This is Document 3 of 3. See also:

## O. Architecture Proposal

FM follows the same hexagonal-inspired ports-and-adapters architecture as other OOP components and is implemented as a **single FastAPI service** (ADR-0016; the legacy Envoy + Go EWBI gateway is superseded). FastAPI uses `httpx` for outbound OAuth2 token acquisition and Bearer-authenticated EWBI calls; Nginx handles inbound HTTPS termination and canonical OPG.04 path routing.
FM follows the same hexagonal-inspired ports-and-adapters architecture as other OOP components and is implemented as a **single FastAPI service** (ADR-0016; the legacy Envoy + Go EWBI gateway is superseded). FastAPI uses `httpx` for outbound OAuth2 token acquisition and Bearer-authenticated EWBI calls.

### Module Structure

@@ -140,9 +140,9 @@ class HttpxEwbiClient:

### P.3.1 Future: mTLS Defense-in-Depth (deferred, ADR-0042)

Not built yet, and not required for a request to be authorized today. Once Nginx performs real mTLS termination (ADR-0016's original assumption), this layers back in as sender-constrained tokens (RFC 8705), binding a partner's JWT to their TLS client certificate:
Not built yet, and not required for a request to be authorized today. Once client-certificate TLS termination exists in front of FM, this layers back in as sender-constrained tokens (RFC 8705), binding a partner's JWT to their TLS client certificate:

The current schema deliberately contains no thumbprint or client-certificate identity fields. A future RFC 8705 design must define certificate issuance, rotation, revocation, Nginx's trusted forwarding boundary, token `cnf` validation, and the new persistence fields together. It must bind the JWT to the TLS client key; a standalone caller-supplied certificate header is not authentication.
The current schema deliberately contains no thumbprint or client-certificate identity fields. A future RFC 8705 design must define certificate issuance, rotation, revocation, the TLS terminator's trusted forwarding boundary, token `cnf` validation, and the new persistence fields together. It must bind the JWT to the TLS client key; a standalone caller-supplied certificate header is not authentication.

---

@@ -152,7 +152,7 @@ The current schema deliberately contains no thumbprint or client-certificate ide

| Boundary | Mechanism | Owner |
|---|---|---|
| Partner OP → Nginx → FM (EWBI) | OAuth 2.0 Client-Credentials + signed JWT (Keycloak realm `federation`, `fed-mgmt` scope) — ADR-0042. mTLS deferred defense-in-depth, not required today. | FM |
| Partner OP → FM (EWBI) | OAuth 2.0 Client-Credentials + signed JWT (Keycloak realm `federation`, `fed-mgmt` scope) — ADR-0042. mTLS deferred defense-in-depth, not required today. | FM |
| Operator → FM (`/internal/*`) | No token check in FM: the routes are reachable only inside the cluster, and OEG authenticates the operator (`operator` role) on the routes it relays (ADR-0051) | Platform deployment, OEG |
| FM → SRM (internal HTTP) | Cluster network trust initially; service JWT when available | Platform deployment |
| FM → Partner OP (outbound EWBI) | OAuth 2.0 Client-Credentials — FM as client, per-partner credentials (ADR-0042). mTLS with our client certificate deferred. | FM |
@@ -177,9 +177,8 @@ Not built yet; this is the design.
  `partner_op_id` and API type, with configurable windows (REQ-FED-11).
- There is **no shared fleet-wide counter** in the current release: the effective maximum is
  approximately `(configured limit × FM pod count)`. Operators sizing agreements and abuse
  thresholds must account for replica count; a Redis-backed (or Nginx) global limiter is a
  thresholds must account for replica count; a Redis-backed global limiter is a
  later hardening step when partner SLAs require a single ceiling.
- IP whitelisting at the Nginx level: only known partner OP source IPs reach FM.
- Federation agreements may define maximum request rates; FM enforces the pod-local limit in
  addition to platform-level limits.

@@ -188,7 +187,7 @@ Not built yet; this is the design.
| Threat | Mitigation |
|---|---|
| Unauthorized partner impersonation | OAuth2 Client-Credentials + signed JWT validation (`fed-mgmt` scope, Keycloak `federation` realm); RFC 8705 sender-binding may layer in later (ADR-0042) |
| DDoS from partner or internet | Nginx IP whitelisting + per-partner rate limiting (not built yet) |
| DDoS from partner or internet | Per-partner rate limiting (not built yet) |
| Topology leakage | Mandatory topology-hiding middleware (`domain/topology.py`) + automated security tests |
| Internal header injection via EWBI | FM strips all `X-Internal-*` headers from inbound requests before processing (not built yet) |

@@ -275,7 +274,7 @@ remove the FM fleet from load balancing. Tracking it (`fm_partner_federation_hea
Not built yet: CI runs type checks, lint, format and pytest, but no OpenAPI contract gate.

- **OPG.04 compliance:** Vendor the published OPG.04 v6.0 OpenAPI v1.4.0 artifact unchanged, apply only a separately reviewed/versioned profile overlay for recorded upstream defects, and compare FM's generated external OpenAPI against the resulting contract by method/path, parameters, required headers, request/response media types and schemas, status codes, callbacks, security-scheme names, and scopes. The canonical contract has 74 operations under `/operatorplatform/federation/v1`; CI fails on an undocumented alias or deviation.
- **Federation-lifecycle proxy alias (ADR-0051):** OEG also serves eight GSMA operations — `CreateFederation`, `GetFederationContextId`, `GetFederationDetails`, `DeleteFederationDetails`, `GetZoneData`, `ZoneSubscribe`, `GetZoneDetails`, `ZoneUnsubscribe` (`UpdateFederation` out of scope) — for the operator-triggered *outbound* direction, forwarding the raw GSMA payload and query string byte-for-byte to FM. Unlike the first version of ADR-0051, this is not a shared-URL/ingress-split situation: OEG serves these on its own `/platform/v1/federation/partners/{partnerOpId}/federations/...` namespace, never the canonical `/operatorplatform/federation/v1/*` prefix, so there is no path collision to reconcile at the gate. Two follow-ups remain open: (1) FM still declares all 74 operations in its generated OpenAPI regardless — this alias needs recording explicitly so the "undocumented alias" check does not flag it against OEG's own, differently-shaped paths; (2) OEG's generated OpenAPI for those eight paths needs its own conformance check, validating request/response **bodies** (not routes, which are OEG's own) against the same vendored artifact + overlay — this does not exist yet. The OPG.04 contract version to pin is resolved (ADR-0051): GSMA OPG.04 v6.0 / artifact v1.4.0, validated against FM's profiled overlay `docs/OPG.04-v6.0-EWBI-Federation-API-v1.4.0-oop-profile.yaml`. The legacy `federation-manager.yaml` (`1.2.0`, snake_case operationIds, ~20 operations) present in earlier drafts of the `refactor/fm` code branch is not a GSMA artifact and is not used by this surface.
- **Federation-lifecycle proxy alias (ADR-0051):** OEG also serves eight GSMA operations — `CreateFederation`, `GetFederationContextId`, `GetFederationDetails`, `DeleteFederationDetails`, `GetZoneData`, `ZoneSubscribe`, `GetZoneDetails`, `ZoneUnsubscribe` (`UpdateFederation` out of scope) — for the operator-triggered *outbound* direction, forwarding the raw GSMA payload and query string byte-for-byte to FM. OEG serves these on its own `/platform/v1/federation/partners/{partnerOpId}/federations/...` namespace, never the canonical `/operatorplatform/federation/v1/*` prefix, so there is no path collision to reconcile at the gate. Two follow-ups remain open: (1) FM still declares all 74 operations in its generated OpenAPI regardless — this alias needs recording explicitly so the "undocumented alias" check does not flag it against OEG's own, differently-shaped paths; (2) OEG's generated OpenAPI for those eight paths needs its own conformance check, validating request/response **bodies** (not routes, which are OEG's own) against the same vendored artifact + overlay — this does not exist yet. The OPG.04 contract version to pin is resolved (ADR-0051): GSMA OPG.04 v6.0 / artifact v1.4.0, validated against FM's profiled overlay `docs/OPG.04-v6.0-EWBI-Federation-API-v1.4.0-oop-profile.yaml`. The legacy `federation-manager.yaml` (`1.2.0`, snake_case operationIds, ~20 operations) present in earlier drafts of the `refactor/fm` code branch is not a GSMA artifact and is not used by this surface.
- **Security metadata and runtime:** Preserve the root OpenAPI OR between `oAuth2ClientCredentials: [fed-mgmt]` and `notifClientCredentials: [fed-mgmt-notif]`, plus callback-specific notification security. Runtime policy must implement the declared operation security exactly or record a deliberate profile deviation; a runtime scope check alone does not repair incorrect OpenAPI metadata.
- **SRM interface:** Validate that `command.srm.*` messages published by FM conform to `CommandEnvelopeV1` and the per-subject payload schemas defined in [srm/interface-contract.md](/srm/interface-contract.md).

@@ -292,7 +291,7 @@ conformance until the contract gate above exists and passes.
| Error representation | Partial | `application/problem+json` with `type`, `title`, `status`, `detail`, `instance`; whether each operation's statuses match the contract is not checked |
| Outbound authorization | Pass | Token provider/cache, Bearer injection, `fed-mgmt-notif` for callbacks FM sends |
| OpenAPI contract gate | Not built yet | The GSMA artifact and the OOP overlay are vendored in FM's `docs/`, but no CI step compares FM's OpenAPI with them |
| TLS 1.3 support | Unverified | The partner-facing ingress (Nginx) is not deployed |
| TLS 1.3 support | Unverified | No TLS terminator is deployed in front of FM |

### S.4 Security Tests

@@ -335,7 +334,7 @@ Use FastAPI or WireMock plus a test Keycloak realm.

| Tradeoff | What We Chose | Why |
|---|---|---|
| **Python/FastAPI vs. Envoy + Go** | Python/FastAPI (ADR-0016) | Single-language stack; FastAPI validates Bearer JWTs, `httpx` handles outbound OAuth2/HTTPS, and Nginx terminates server-side TLS. |
| **Python/FastAPI vs. Envoy + Go** | Python/FastAPI (ADR-0016) | Single-language stack; FastAPI validates Bearer JWTs, and `httpx` handles outbound OAuth2/HTTPS. |
| **Static routing vs. Telco Finder** | Static routing initially, Telco Finder integration when available | Building or integrating a global Telco Finder is complex and may not have a stable API yet (per OPG.10 v2.0). Static routing with < 50 partners is manageable and validates the federation flow end-to-end. |

---
@@ -416,7 +415,7 @@ query API, staging tests against a real partner, and metrics. Advanced Federatio

| Epic | Description |
|---|---|
| **EWBI Gateway Foundation** | FastAPI service scaffold, OAuth2/JWT validation, Nginx HTTPS routing, topology hiding, health checks |
| **EWBI Gateway Foundation** | FastAPI service scaffold, OAuth2/JWT validation, topology hiding, health checks |
| **Federation Control Plane** | Partner OP lifecycle management, federation agreement CRUD, admin API |
| **Routing Engine** | PostgreSQL routing rules, MSISDN/IP resolution, per-partner rate limiting |
| **Inbound Federation Pipeline** | EWBI service endpoints, DataBus `command.srm.*` publishing, `event.srm.operation.completed` consumption, federation transaction tracking |
+8 −8
Changes for fm/overview-and-architecture.md: 8 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@ status: "ETSI SDG OOP"
If you are new to FM, this is the simplest useful way to think about it:

- **FM is the bridge to other operators.** When a request needs capabilities on a partner operator's network — or a partner operator needs capabilities on ours — FM handles the cross-boundary routing, identity validation, and response sanitization.
- **FM terminates the East/Westbound Interface (EWBI).** The partner-facing ingress routes the whole canonical OPG.04 prefix `/operatorplatform/federation/v1/*` straight to FM. Every inbound partner operation lands there.
- **FM terminates the East/Westbound Interface (EWBI).** Partners call the whole canonical OPG.04 prefix `/operatorplatform/federation/v1/*` on FM's EWBI port. Every inbound partner operation lands there.
- **OEG relays the operator-triggered outbound direction on its own path.** Eight GSMA operations (`CreateFederation`, `GetFederationContextId`, `GetFederationDetails`, `DeleteFederationDetails`, `GetZoneData`, `ZoneSubscribe`, `GetZoneDetails`, `ZoneUnsubscribe`; `UpdateFederation` out of scope) are served by OEG under `/platform/v1/federation/partners/{partnerOpId}/federations/...`, not on the canonical prefix.
- **The relay is byte-for-byte.** OEG forwards the raw GSMA payload and query string to FM's mirrored `/internal/*` endpoint over a synchronous internal HTTP call (RD §L.3b; ADR-0051). FM validates, executes and drives the outbound handshake.
- **The two directions use different paths.** They are not split at the ingress on a shared URL.
- **The two directions use different paths.** They do not share a URL.
- **FM does not fulfill requests itself.** For OPG.04 lifecycle mutations (install/remove application and supported network-capability operations), it publishes the same `command.srm.*` commands to DataBus that OEG publishes (ADR-0001).
- **Stateless queries go to SRM over HTTP.** For device location, FM calls SRM's internal HTTP endpoint synchronously (device status is not built yet). SRM handles all fulfillment the same way whether the request came from OEG or FM.
- **Federated Service APIs cover Device Location and QoD.** A partner's Device Location query is answered through SRM, and a partner's QoD request becomes SRM network-capability commands (UC-FM-04, UC-FM-05). Device Status is not built yet.
@@ -30,12 +30,12 @@ If you are new to FM, this is the simplest useful way to think about it:
- **FM manages partner relationships.** It stores partner operator profiles, federation agreements, routing rules, and shared resource catalogues in its own PostgreSQL database (`fm_db`).
- **A new federation starts in one of two ways.** Either an operator calls one of the eight lifecycle operations on OEG, which relays it to FM byte-for-byte with no DataBus, no new schema and no reshaping (ADR-0051, keeping ADR-0046's transport, superseding ADR-0043's `command.fm.federation.*` transport). Or FM starts it itself from bootstrap configuration at startup (ADR-0043).
- **FM alone owns federation state.** It stores the partner-issued `federationContextId` and alone executes the outbound OPG.04 handshake.
- **A partner establishing federation with us arrives inbound.** It uses the canonical `/operatorplatform/federation/v1/*` prefix through the partner-facing ingress straight to FM — a path OEG never serves.
- **A partner establishing federation with us arrives inbound.** It uses the canonical `/operatorplatform/federation/v1/*` prefix straight to FM — a path OEG never serves.
- **SRM, not OEG, decides whether a deployment zone is local or federated (ADR-0044).** SRM checks its own zone inventory first and queries FM for federated zone data when the target isn't found locally.
- **SRM hands federated deploys to FM over the DataBus.** It publishes `command.fm.service.deploy` (ADR-0053). This is an interim layer pending a future "runtime coordinator" component (see [platform/future-architecture.md](/platform/future-architecture.md) §6.1).
- **OEG's outbound hand-off to FM covers subscriber routing only.** It is scoped to subscriber-identifier (MSISDN/IP) routing.

![FM: partner ingress, OEG relay, fm_db, DataBus and SRM](diagrams/overview.drawio.svg)
![FM: partner EWBI, OEG relay, fm_db, DataBus and SRM](diagrams/overview.drawio.svg)

**What FM is not:**

@@ -71,7 +71,7 @@ There are two success definitions:

| Area | Current architecture position |
|---|---|
| **EWBI termination** | Terminate all inbound EWBI HTTPS requests routed via the partner-facing ingress under the OPG.04 server prefix `/operatorplatform/federation/v1/*`. That ingress is not deployed today, so there is no partner-facing EWBI ingress and inbound federation from external partner OPs is not exercised — it is a future release (OEG [interface-contract §1](/oeg/interface-contract.md#1-api-surfaces-and-errors)). Separately, eight GSMA operations arrive for the operator-triggered *outbound* direction as a synchronous internal HTTP call from OEG's own `/platform/v1/federation/partners/{partnerOpId}/federations/...` namespace onto FM's mirrored `/internal/*` endpoint (§L.3b; ADR-0051), carrying the raw GSMA payload and query string byte-for-byte, protected only by cluster-internal network-policy reachability and validated/executed by FM — this path works today and does not depend on the partner-facing ingress. The two directions are on different paths entirely, not split at the ingress. Client mTLS is a future defense-in-depth layer (ADR-0042) for the EWBI partner hop, not required today and not applicable to the internal OEG→FM hop. |
| **EWBI termination** | Terminate all inbound EWBI requests under the OPG.04 server prefix `/operatorplatform/federation/v1/*` on FM's EWBI port, :8082 (OEG [interface-contract §1](/oeg/interface-contract.md#1-api-surfaces-and-errors)). Separately, eight GSMA operations arrive for the operator-triggered *outbound* direction as a synchronous internal HTTP call from OEG's own `/platform/v1/federation/partners/{partnerOpId}/federations/...` namespace onto FM's mirrored `/internal/*` endpoint (§L.3b; ADR-0051), carrying the raw GSMA payload and query string byte-for-byte, protected only by cluster-internal network-policy reachability and validated/executed by FM. The two directions are on different paths entirely. Client mTLS is a future defense-in-depth layer (ADR-0042) for the EWBI partner hop, not required today and not applicable to the internal OEG→FM hop. |
| **Partner authentication** | OAuth2 Client-Credentials + signed JWT. Our Keycloak `federation` realm issues inbound tokens; each target partner's Authorization Server issues outbound tokens. FM validates `fed-mgmt` and maps inbound `azp` to the partner profile (ADR-0042). |
| **Federation agreement enforcement** | Check that the requesting partner has a valid agreement before routing any request. |
| **Outbound federation routing** | Resolve target partner from user identifiers (MSISDN — Mobile Station International Subscriber Directory Number — prefix, IP CIDR — Classless Inter-Domain Routing block) via routing table. Forward requests over EWBI to partner OPs. |
@@ -200,7 +200,7 @@ A partner operator requests deployment of an edge application on our infrastruct
- **Actor:** Partner Operator
- **Trigger:** Partner OP calls OPG.04 `POST /operatorplatform/federation/v1/{federationContextId}/application/lcm` (`InstallApp`).
- **Main flow:**
  1. The partner-facing ingress routes `/operatorplatform/federation/v1/*` to FM.
  1. FM receives the request on its EWBI port under `/operatorplatform/federation/v1/*`.
  2. FM validates the Bearer JWT (signature, issuer, expiry, audience, `fed-mgmt` scope) and maps its `azp` claim to an active partner in `partner_ops`.
  3. FM resolves `federationContextId` to an inbound federation context of that partner. A repeated `Idempotency-Key` with the same request returns the original `202`; with a different request it is rejected.
  4. FM checks that the agreement permits deploying on the requested zone, and resolves the application to a local service specification: from the partner's EWBI onboarding first (ADR-0068), otherwise from the agreement's app mapping (ADR-0018).
@@ -470,8 +470,8 @@ sequenceDiagram

### In Scope

- **EWBI termination** under `/operatorplatform/federation/v1/*` (partner-facing ingress) for all inbound partner operator requests — the entire prefix.
- **Operator-triggered federation lifecycle** for the outbound direction — the eight operations proxied by OEG from its own platform namespace as a synchronous internal HTTP call carrying the raw GSMA payload and query string byte-for-byte (§L.3b; ADR-0051), validated and executed by FM; on a different path from inbound entirely, not split at a shared ingress.
- **EWBI termination** under `/operatorplatform/federation/v1/*` for all inbound partner operator requests — the entire prefix.
- **Operator-triggered federation lifecycle** for the outbound direction — the eight operations proxied by OEG from its own platform namespace as a synchronous internal HTTP call carrying the raw GSMA payload and query string byte-for-byte (§L.3b; ADR-0051), validated and executed by FM; on a different path from inbound entirely.
- **OAuth2 Client-Credentials authorization** with signed JWTs for all EWBI requests (`fed-mgmt`; `fed-mgmt-notif` for callbacks).
- **Federation agreement management** — partner profiles, agreements, routing rules, and catalogue sharing (the admin API for routing rules is not built yet).
- **Inbound request dispatch** — publish `command.srm.*` commands to DataBus with `source=federation` for SRM fulfillment.
+2 −2
Changes for fm/persistence-model.md: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -341,10 +341,10 @@ FM follows the same hexagonal layout as OEG/SRM (ADR-0016; single Python/FastAPI
| Inbound AuthN/Z | OAuth2 Client-Credentials + signed JWT via Keycloak `federation` realm (`fed-mgmt` scope); FM validates against Keycloak's JWKS (ADR-0042) |
| Admin AuthN/Z | No token check in FM on `/internal/*`: the routes are reachable only inside the cluster, and OEG authenticates the operator (`operator` role) on the routes it relays (ADR-0051) |
| Outbound AuthN | OAuth2 Client-Credentials — FM fetches a token from the partner's realm using our registered client credentials (ADR-0042) |
| Future: mTLS defense-in-depth | Deferred until real Nginx mTLS termination exists (ADR-0042). `partner_ca_cert_path` supports ordinary HTTPS verification; it is not an mTLS identity field. |
| Future: mTLS defense-in-depth | Deferred until client-certificate TLS termination exists in front of FM (ADR-0042). `partner_ca_cert_path` supports ordinary HTTPS verification; it is not an mTLS identity field. |
| Topology hiding | mandatory `TopologyHidingMiddleware` on every EWBI response (REQ-FED-02); strips internal IPs, cluster/namespace/node names, pod UIDs, trace IDs |
| Correlation boundary | internal `correlation_id` stays in logs and `federation_transactions`; no custom header or field crosses the EWBI; partner-side correlation uses OPG.04 identifiers (`federationContextId`, `txnIdentifier`, `Idempotency-Key`) |
| Header trust | FM must be reachable only via Nginx. FM trusts no caller-supplied identity header — partner identity comes solely from the validated JWT. |
| Header trust | FM trusts no caller-supplied identity header — partner identity comes solely from the validated JWT. |

Reference: OPG.04 v6.0 §9 (E/WBI OAuth2 Client-Credentials authorization — ADR-0042); OPG.02 v10.0 §2.4 (topology hiding), §4.2.3 (E/WBI authentication + agreed-resource exposure; not §4.2.2.3, corrected), §3.3.4.5 (mTLS as a mutually-agreed mechanism, deferred).

+10 −12

File changed.

Preview size limit exceeded, changes collapsed.

Loading