# Insignia Platform — Live State (from the mesh-verify probe, 2026-07-10) > Distilled from the authenticated `mesh-verify.lynkedup.cloud` dashboard (`/api/results` + > `/api/journey`). This is the **real** platform IIOS is meant to plug into — service inventory, > the identity/session/governance flow, and the exact contracts to wire IIOS's platform ports. > Tokens redacted (the raw JSON dumps contain live SAT/PAT/refresh tokens — do not commit them). ## Cluster / mesh - **Cluster:** `lynkedup-tech` (NYC2 / DigitalOcean). **Istio** (istio-envoy) + **SPIFFE/SPIRE**, trust domain **`spiffe://insignia.tech`** (SVIDs like `spiffe://insignia.tech/ns/sre/sa/default`, `.../sa/realmdm-sas`). mTLS **PERMISSIVE**. Reached by ClusterIP DNS. - **Namespaces:** `sre` (MDM, OPA, misc), `cmp` (consent platform), `insignia` (identity/session/ app-facing services), `istio-system`. - Public edges: `*.lynkedup.cloud` (behind oauth2-proxy → Keycloak). ## The identity/session/governance flow (7 steps — the doctrine) > **Separate authorities:** Session Broker *authenticates*, OPA *authorizes*, CMP decides *purpose*, > RealMDM *resolves identity*. Purpose-proof ≠ authorization. The PAT carries the external `sub` > only as a **SHA-256 hash**, never raw; `canonical_person_id` is null until MDM VERIFIES (MDM never > blocks login). 1. **Anonymous consent (CMP Edge)** — browser CMP SDK → `POST /edge/v1/cache-policy` → EdDSA-signed cache-category manifest; a ConsentReceipt goes to CMP over gRPC. Purpose proof only. 2. **External login (Supabase)** → **SAT** (ES256 JWT). Claims: `iss` (project `/auth/v1`), opaque UUID `sub`, `aud=authenticated`, `email`, `user_metadata` (full_name, avatar_url), `aal`, `amr`. Proves the *session*, not the person/permission. Verified via Supabase **JWKS** (kid-selected). 3. **Session Broker exchange SAT → PAT** — `POST /v1/sessions/exchange` (Bearer SAT + `X-Client-Authorization` = BFF Keycloak client-creds, aud=session-broker). Broker verifies the SAT, calls the MDM bridge, resolves scope from **memberships**, mints the **PAT** (~5 min). 3b. **Workload identity (SPIFFE/mTLS)** — each meshed pod gets an X.509-SVID; OPA receives **both** the user (`principal`) and the caller (`caller.spiffe_id`) — different layers, never merged. 4. **MDM Auth-Subject Bridge** — `POST /v1/auth-subjects/resolve {issuer, subject}` → `{platform_ principal_id, canonical_person_id (null until VERIFIED), link_state (PENDING/VERIFIED), link_version, match_method}`. Keyed on **iss+sub** (never email). Idempotent. 5. **OPA decision** — `POST /v1/decisions` → `{decision_id, allow, reason_codes, obligations, policy_version}`. Obligations = masks / row-filters / denied fields / audit level / ttl. A decision, not a 50-line entitlement JWT — the PEP MUST enforce every obligation. 6. **AppShell assembles the ACE** — combines PAT + OPA obligations + CMP consent into an App Context Envelope (HttpOnly cookie): `capabilities[]` (policy-derived), `ui_obligations` (hide/mask/step_up), `consent`. **No tokens, no raw PII in the browser.** 7. **CRM renders** — applies OPA `row_filter` (SQL WHERE) + `mask_fields` + `deny_fields` server-side; rows reference `canonical_person_id`, not email. ## Service inventory + real endpoints **Identity / session (`insignia` ns):** - **Session Broker** `session-broker.insignia:80` — `POST /v1/sessions/exchange` (SAT→PAT). - **Memberships** `memberships.insignia` (public `insignia-memberships.lynkedup.cloud`) — `POST /v1/internal/resolve`, `GET /v1/memberships` (Bearer PAT) → scope tuple + `allowed[]`. - **AppShell BFF** `appshell-bff.insignia:80` (public `insignia-appshell.lynkedup.cloud`) — `GET /apps/crm-web/bootstrap` (Bearer PAT) → ACE. - **Profile** `profile.insignia:80` — `GET /v1/profile`, `GET /v1/stats`. Backed by **sqlite3** (`/data/profiles.db`, PVC `insignia-profile-data`, WAL, persistent, single-replica RWO). - **CRM** `crm.insignia:80` — `GET /v1/leads?view=list` (applies obligations). - **Policy Gateway** `policy-gateway.insignia:80` — `POST /v1/decisions`, `POST /v1/decisions/batch`. **MDM (`sre` ns):** `mdm-kernel.sre:80` (`/v1/auth-subjects/resolve`, `/healthz`, `/readyz`; auth = Keycloak service token **aud=realmdm**) · `mdm-ai.sre:80` · `mdm-sas.sre:9090` (**gRPC** — tokenization/SAS). **OPA / policy (`sre` ns):** `opa.sre:8181` (`/health`, `GET /v1/data` = live policy tree; default-deny) · `realmdm-opa.sre:8181` · `opal-server.sre:7002` (OPAL policy distribution). **CMP (`cmp` ns), backed by Postgres + NATS + Redis:** `cmp-core:8080` (real `CheckConsent` gRPC; service token aud=cmp) · `cmp-admin:8086` · `cmp-evidence:8081` · `cmp-sync:8085` · `cmp-tollgate:8082` (NATS JetStream gating) · `cmp-media:8083` · `cmp-worker:8084`. Plus `insignia-consent-edge.insignia` (`POST /edge/v1/cache-policy`) and `insignia-consent-adapter.insignia` (`POST /v1/consent/evaluate {purpose}` → `{permitted, legal_basis, state, consent_epoch}`). **Other (`sre` ns):** `poi-api:5000` · `roof:8002` (YOLO segmentation) · `commit:8081` · `presign:8080` · `egs:8090` · `artifact-retrieval:8082` (was 503 on probe day) · `cmp-docs`. ## The two contracts IIOS must match ### PAT (Platform Access Token) — what IIOS should verify `iss = https://identity.insignia.internal` · **ES256** (EC P-256), verify via the broker **JWKS** (`.../.well-known/jwks.json`, kid-selected — **no shared secret**) · `aud` includes the app (e.g. `crm-web`) · `lifetime ~300s`. Claims: ``` sub = platform_principal_id app_id tenant_id org_id bu_id region environment role aal amr auth_source external_subject_hash = sha256:… (NOT the raw external sub) canonical_person_id (null until VERIFIED) session_epoch · policy_epoch · consent_epoch (stale-detection) sid (platform_session_id) · typ = platform-access+jwt ``` ### OPA decision — `POST http://policy-gateway.insignia.svc.cluster.local/v1/decisions` Request `{ input: { principal{platform_principal_id, canonical_person_id, auth_source, aal, roles, memberships[]}, caller{spiffe_id}, resource{type, id, tenant_id, classification[]}, action, context{purpose, device_trust, consent_receipt_ids[], network_zone, time} } }` Response `{ decision_id, allow, reason_codes[], obligations{ row_filter, allow_fields[], mask_fields{}, deny_fields[], audit, decision_ttl_seconds }, policy_version }`. ## What this means for wiring IIOS's ports 1. **Auth — verify the PAT, not the Supabase SAT.** IIOS today verifies the Supabase SAT directly (a dev shortcut). In the real platform the **Session Broker** does SAT→PAT; a platform workload verifies the **PAT**. The PAT already carries the full scope tuple + `platform_principal_id`, so `MessagePrincipal` maps ~1:1: `userId = platform_principal_id` (→ `canonical_person_id` once VERIFIED), `appId = app_id`, `orgId = org_id`, `tenantId = tenant_id`, `+ buId`. Wire it by adding the broker as an `AUTH_ISSUERS` entry (iss `https://identity.insignia.internal`, ES256, its JWKS). 2. **OPA — point `OpaPort` at the Policy Gateway** (`POST /v1/decisions`). Build `{principal, caller. spiffe_id, resource, action, context}` from the PAT + the op; `decideOrThrow` maps `allow` → proceed and **must enforce the obligations** (masks/row-filter/deny). The gateway's input is richer than IIOS's current `{action,…}` — that's the adapter's job to assemble. 3. **MDM — usually don't call it.** The PAT already carries `platform_principal_id`/`canonical_person_id` (the broker resolved at login). Only call `/v1/auth-subjects/resolve` if IIOS is the identity-exchange edge (it isn't — the Broker is). 4. **CMP — consent gate** via `insignia-consent-adapter /v1/consent/evaluate {purpose}` when processing content for AI/analytics/marketing. 5. **SAS — tokenization/masking** is `mdm-sas` (gRPC) — the "tokenize sensitive parts before storage" requirement. *Source: two API payloads captured 2026-07-10 (`result.json` = probes, `journey.json` = the CRM first-vertical-slice journey). Re-capture from the authenticated dashboard to refresh.*