- .npmrc routes the @insignia scope to https://git.lynkedup.cloud/api/packages/insignia/npm/ (auth via ${GITEA_TOKEN} env — no secret committed). - The 9 frontend SDK packages (contracts, kernel-client, adapter-sdk, *-web) are now publishable: private dropped, version 0.1.0, publishConfig pinned to Gitea. iios-service and iios-testkit stay private (pnpm publish skips them). - Root `release` / `release:dry` scripts; a Gitea Actions workflow publishes on a v* tag. - PUBLISHING.md documents publish + consumer (.npmrc) setup. Verified: dry-run packs cleanly and workspace:* deps resolve to 0.1.0 in the tarball. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.0 KiB
Insignia Platform — Live State (from the mesh-verify probe, 2026-07-10)
Distilled from the authenticated
mesh-verify.lynkedup.clouddashboard (/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 domainspiffe://insignia.tech(SVIDs likespiffe://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
subonly as a SHA-256 hash, never raw;canonical_person_idis null until MDM VERIFIES (MDM never blocks login).
- 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. - External login (Supabase) → SAT (ES256 JWT). Claims:
iss(project/auth/v1), opaque UUIDsub,aud=authenticated,email,user_metadata(full_name, avatar_url),aal,amr. Proves the session, not the person/permission. Verified via Supabase JWKS (kid-selected). - 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. - 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. - 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. - 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. - CRM renders — applies OPA
row_filter(SQL WHERE) +mask_fields+deny_fieldsserver-side; rows referencecanonical_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(publicinsignia-memberships.lynkedup.cloud) —POST /v1/internal/resolve,GET /v1/memberships(Bearer PAT) → scope tuple +allowed[]. - AppShell BFF
appshell-bff.insignia:80(publicinsignia-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, PVCinsignia-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
- 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, soMessagePrincipalmaps ~1:1:userId = platform_principal_id(→canonical_person_idonce VERIFIED),appId = app_id,orgId = org_id,tenantId = tenant_id,+ buId. Wire it by adding the broker as anAUTH_ISSUERSentry (isshttps://identity.insignia.internal, ES256, its JWKS). - OPA — point
OpaPortat the Policy Gateway (POST /v1/decisions). Build{principal, caller. spiffe_id, resource, action, context}from the PAT + the op;decideOrThrowmapsallow→ 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. - 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/resolveif IIOS is the identity-exchange edge (it isn't — the Broker is). - CMP — consent gate via
insignia-consent-adapter /v1/consent/evaluate {purpose}when processing content for AI/analytics/marketing. - 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.