Commit ab88e14f authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

Update according to the new oauth2 drift

(cherry picked from commit 4b6ff2c1)
parent b38955dd
Loading
Loading
Loading
Loading
+21 −18
Changes for fm/persistence-model.md: 21 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -41,8 +41,9 @@ Keep one distinction in mind, the FM analogue of OEG's:

`fm_db` is authoritative for exactly three things:

1. **Who our federation partners are** — partner profiles, the mTLS trust material (thumbprint for
   inbound, cert/key/CA references for outbound), and connection status.
1. **Who our federation partners are** — partner profiles, the OAuth2 client identity that maps an
   inbound token back to a partner, the credentials we use to obtain tokens for outbound calls, and
   connection status.
2. **What each partnership is allowed to do** — federation agreements (permitted API types, zones,
   usage limits, validity) and the partner-app → local `service_specification_id` mappings
   (ADR-0018) that drive SRM dispatch, plus the routing rules that resolve identifiers to partners.
@@ -57,9 +58,10 @@ references; it never stores SRM inventory, placement, or capacity.
### Core entities

**PartnerOP** — an external operator platform FM federates with over the EWBI. Holds EWBI base
URL, inbound `cert_thumbprint`, outbound mTLS material (cert/key/CA path references), supported API
families, SLA limits, and connection status. Exactly one current row per partner in `partner_ops`;
updates mutate in place (no immutable version history in Release 2.0).
URL, the partner's OAuth2 client id (the `azp` claim we match inbound tokens against), the client
credentials and token endpoint we use for outbound calls, supported API families, SLA limits, and
connection status. Exactly one current row per partner in `partner_ops`; updates mutate in place
(no immutable version history in Release 2.0).

**FederationAgreement** — the rules governing what may be shared with one partner: permitted API
types, permitted zones, usage limits, validity window, and — crucially — the `service_spec_mappings`
@@ -96,7 +98,7 @@ anything owned by SRM is held only as a UUID reference.

| # | Entity | Table | FM owns? | Rationale |
|---|---|---|---|---|
| 1 | Partner OP profiles | `partner_ops` | ✅ Yes | Identity + mTLS trust material + connection status for each federated operator. |
| 1 | Partner OP profiles | `partner_ops` | ✅ Yes | Identity + OAuth2 client credentials + connection status for each federated operator. |
| 2 | Federation agreements | `federation_agreements` | ✅ Yes | Permissions + `appId → service_specification_id` mappings (ADR-0018); the self-contained federation contract. |
| 3 | Routing rules | `routing_rules` | ✅ Yes | Resolve MSISDN prefix / IP CIDR → partner for outbound routing. |
| 4 | Shared resource catalogues | `shared_resource_catalogues` | ✅ Yes | Zone/capability availability exchanged with partners; validates federated deployment targets. |
@@ -112,7 +114,7 @@ anything owned by SRM is held only as a UUID reference.
|---|---|
| Per-partner rate-limit counters | In-process per-pod counters (REQ-FED-11); no shared store in Release 2.0. |
| Partner / agreement / routing caches | **Not cached at all** — this data must be strongly consistent (suspending a partner takes effect next request), so it is read from PostgreSQL per request (G1). |
| Raw certificate material | `partner_ops` stores path/secret references, not inline cert/key bytes. |
| Raw secret material | `partner_ops` stores secret/path references, not inline client secrets or key bytes. |
| SRM inventory, placement, capacity, topology | SRM-owned; FM reads live via `/internal/*` or consumes `event.srm.*`. |
| Intermediate operation progress | Phase 1 tracks `pending → in_progress → terminal`; SRM emits no `in_progress` (K.2). |

@@ -133,10 +135,11 @@ anything owned by SRM is held only as a UUID reference.
| `name` | VARCHAR(255) | NOT NULL | Human-readable partner name |
| `mcc_mnc` | VARCHAR(10) | NOT NULL, UNIQUE | MCC+MNC; used as `federation_partner_ref` |
| `base_url` | TEXT | NOT NULL | Partner's EWBI base URL |
| `cert_thumbprint` | VARCHAR(128) | NOT NULL | SHA-256 thumbprint of partner's client cert (inbound mTLS lookup key) |
| `our_client_cert_path` | TEXT | | Ref to our client cert for outbound mTLS to this partner |
| `our_client_key_path` | TEXT | | Ref to our client private key for outbound mTLS |
| `partner_ca_cert_path` | TEXT | | Ref to CA bundle verifying this partner's server cert |
| `oauth2_client_id` | VARCHAR(255) | NOT NULL, UNIQUE | Partner's OAuth2 client id; matched against the `azp` claim of an inbound token (inbound identity lookup key) |
| `our_client_id` | VARCHAR(255) | | Client id we present when obtaining a token for outbound calls to this partner |
| `our_client_secret_ref` | TEXT | | Ref to the secret backing `our_client_id` (never stored inline) |
| `token_endpoint` | TEXT | | Partner's OAuth2 token endpoint for the outbound Client-Credentials grant |
| `partner_ca_cert_path` | TEXT | | Ref to CA bundle verifying this partner's server TLS certificate |
| `supported_apis` | JSONB | NOT NULL, DEFAULT '[]' | API families the partner supports |
| `sla_config` | JSONB | DEFAULT '{}' | SLA parameters (max rps, max concurrent) |
| `status` | VARCHAR(20) | NOT NULL, DEFAULT 'pending' | `pending`, `active`, `suspended`, `decommissioned` |
@@ -144,7 +147,7 @@ anything owned by SRM is held only as a UUID reference.
| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |
| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT now() | |

Indexes: `idx_partner_ops_mcc_mnc`, `idx_partner_ops_status`, `idx_partner_ops_cert_thumbprint`.
Indexes: `idx_partner_ops_mcc_mnc`, `idx_partner_ops_status`, `idx_partner_ops_oauth2_client_id`.

#### `federation_agreements`

@@ -275,15 +278,15 @@ federation-manager/

| Topic | Approach |
|---|---|
| Inbound AuthN/Z | OAuth2 Client-Credentials + signed JWT via Keycloak `federation` realm (`fed-mgmt` scope); FM validates against Keycloak's JWKS (ADR-0037) |
| Inbound AuthN/Z | OAuth2 Client-Credentials + signed JWT via Keycloak `federation` realm (`fed-mgmt` scope); FM validates against Keycloak's JWKS (ADR-0038) |
| Admin AuthN/Z | Keycloak JWT, `operator` role, on `/internal/*` admin routes only — same centralized Keycloak, `oop` realm |
| Outbound AuthN | OAuth2 Client-Credentials — FM fetches a token from the partner's realm using our registered client credentials (ADR-0037) |
| Future: mTLS defense-in-depth | Deferred until real Nginx mTLS termination exists; `cert_thumbprint` column retained but not part of today's authorization decision (ADR-0037) |
| Outbound AuthN | OAuth2 Client-Credentials — FM fetches a token from the partner's realm using our registered client credentials (ADR-0038) |
| Future: mTLS defense-in-depth | Deferred until real Nginx mTLS termination exists (ADR-0038). No certificate columns are carried today; the trust material they would need is defined when that layer is actually built. |
| Topology hiding | mandatory `TopologyHider` on every EWBI response (REQ-FED-02); strips internal IPs, cluster/namespace/node names, pod UIDs, trace IDs |
| Correlation boundary | internal `correlation_id` ↔ external `X-Federation-Correlation-ID`; internal IDs never leave |
| Header trust | FM must be reachable only via Nginx, which must strip any client-supplied `X-Client-Certificate-Thumbprint` (relevant once the mTLS layer above is built) |
| Header trust | FM must be reachable only via Nginx. 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-0037); 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).
Reference: OPG.04 v6.0 §9 (E/WBI OAuth2 Client-Credentials authorization — ADR-0038); 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).

## Implementation Status

@@ -291,7 +294,7 @@ Tracks the FM rewrite (branch `feature/r2-fastapi-rewrite`). Update as tables la

| Table | Schema in code | Repo adapter | Notes |
|---|---|---|---|
| `partner_ops` | Partial (id, mcc_mnc, cert_thumbprint, status) | `PostgresPartnerRepo.find_by_cert_thumbprint` | mTLS material + SLA columns pending |
| `partner_ops` | Partial (id, mcc_mnc, oauth2_client_id, status) | `PostgresPartnerRepo.find_by_oauth2_client_id` | Outbound credential + SLA columns pending |
| `federation_agreements` | Not yet | — | Needed for deploy flow (ADR-0018 mapping) |
| `routing_rules` | Not yet | — | Outbound federation (Phase 2/3) |
| `shared_resource_catalogues` | Not yet | — | Catalogue sync (Phase 2) |