# Federation Architecture **Version:** 0.0.1 **Status:** Design Phase **Author:** Mosaic Stack Team **Date:** 2025-01-29 ## Table of Contents 1. [Problem Statement](#problem-statement) 2. [Architecture Overview](#architecture-overview) 3. [Identity & Authentication](#identity--authentication) 4. [Agent Federation Protocol](#agent-federation-protocol) 5. [RBAC Model](#rbac-model) 6. [Data Sovereignty](#data-sovereignty) 7. [Implementation Phases](#implementation-phases) 8. [Versioning](#versioning) --- ## Problem Statement ### Use Cases 1. **Work/Personal Separation** - Developer has personal projects at home and work projects at the office - Data must stay in its respective environment - Single pane of glass for unified visibility 2. **Enterprise Control** - Organization runs their own Mosaic Stack instance - Teams within the org have isolated workspaces - IT controls access, audit, compliance 3. **Cross-Organization Collaboration** - Partner companies need to share specific projects - Guest access with limited permissions - No data replication—query in place ### Requirements - **Data Sovereignty** — Data stays where it's created, never crosses boundaries - **Unified Control** — Single interface to view/manage multiple instances - **Clean Severance** — Disconnect = lose access, no data to clean up - **Enterprise Auth** — SSO, RBAC, audit trails - **Peer-to-Peer** — Any instance can be both master and spoke --- ## Architecture Overview ### Peer-to-Peer Federation Model Every Mosaic Stack instance is a **peer** that can simultaneously act as: - **Master** — Control and query downstream spokes - **Spoke** — Expose capabilities to upstream masters ``` ┌─────────────────┐ │ ENTERPRISE │ │ (Corp HQ) │ └────────┬────────┘ │ speaks to ┌──────────────┼──────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ IT Dept │ │ Dev Team │ │ HR Dept │ └────┬─────┘ └────┬─────┘ └──────────┘ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Jason │◄─►│ Mike │ ← peer sharing │ (Work) │ │ (Work) │ └────┬─────┘ └──────────┘ │ │ speaks to (personal master) ▼ ┌──────────┐ │ Jason │◄─► [Future: Family instance?] │ (Home) │◄─► [Future: Trusted collaborator?] └──────────┘ ``` ### Component Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ IDENTITY PLANE │ │ (Authentik) │ ├─────────────────────────────────────────────────────────────────┤ │ • Users (identities across instances) │ │ • Groups (teams, departments, roles) │ │ • Applications (Mosaic Stack instances) │ │ • Federation trust (OIDC/SAML between IdPs) │ └───────────────────────────┬─────────────────────────────────────┘ │ OIDC / SAML ┌───────────────────┼───────────────────┐ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ Instance A │ │ Instance B │ │ Instance C │ │ (Home) │ │ (Work) │ │ (Partner) │ ├───────────────┤ ├───────────────┤ ├───────────────┤ │ Agent Layer │ │ Agent Layer │ │ Agent Layer │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │ │ Jarvis │ │ │ │ Jarvis │ │ │ │ Partner │ │ │ │ Prime │◄┼───┼─┤ Work │ │ │ │ Agent │ │ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ ├───────────────┤ ├───────────────┤ ├───────────────┤ │ Workspaces: │ │ Workspaces: │ │ Workspaces: │ │ • Personal │ │ • IT Ops │ │ • Shared Proj │ │ • Side Proj │ │ • Dev Team │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ ``` --- ## Identity & Authentication ### Authentik as Identity Provider Authentik provides enterprise-grade identity management: | Feature | Purpose | |---------|---------| | **OIDC/SAML** | Single sign-on across instances | | **User Directory** | Centralized user management | | **Groups** | Team/department organization | | **RBAC** | Role-based access control | | **Audit Logs** | Compliance and security tracking | | **MFA** | Multi-factor authentication | | **Federation** | Trust between external IdPs | ### Auth Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ Identity Provider (Authentik) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ │ │ Users │ │ Groups │ │ Applications │ │ │ ├─────────────┤ ├─────────────┤ ├─────────────────────────┤ │ │ │ jason │ │ IT-Team │ │ mosaic-home │ │ │ │ mike │ │ Dev-Team │ │ mosaic-work-usc │ │ │ │ sarah │ │ Admins │ │ mosaic-partner-acme │ │ │ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Policies & Flows │ │ │ │ • Login flow (password + MFA) │ │ │ │ • OAuth2/OIDC scopes (profile, email, groups) │ │ │ │ • Conditional access (IP, device, time) │ │ │ │ • External IdP federation (Google, Azure AD) │ │ │ └──────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ┌───────────────────┼───────────────────┐ │ OIDC │ OIDC │ OIDC ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Mosaic Home │ │ Mosaic Work │ │ Mosaic Ext │ └─────────────┘ └─────────────┘ └─────────────┘ ``` ### OIDC Token Claims Mosaic Stack expects these claims from the IdP: ```json { "sub": "user-uuid-123", "preferred_username": "jason", "email": "jason@example.com", "groups": ["IT-Team", "Dev-Team", "Admins"], "roles": ["workspace:ws-123:owner", "workspace:ws-456:member"], "aud": "mosaic-home", "iss": "https://auth.example.com" } ``` ### Cross-Instance Identity When federating between instances with different IdPs: ``` ┌─────────────────┐ ┌─────────────────┐ │ Authentik A │◄── OIDC Trust ───►│ Authentik B │ │ (Home IdP) │ │ (Work IdP) │ └────────┬────────┘ └────────┬────────┘ │ │ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ Mosaic Home │ │ Mosaic Work │ │ │ │ │ │ User: jason │◄── Federation ───►│ User: jason │ │ (home identity)│ Protocol │ (work identity)│ └─────────────────┘ └─────────────────┘ ``` **Identity Mapping:** - Same email = same person (by convention) - Explicit identity linking via federation protocol - No implicit access—must be granted per instance --- ## Agent Federation Protocol ### Connection Lifecycle ``` ┌────────────┐ ┌────────────┐ │ MASTER │ │ SPOKE │ │ (Home) │ │ (Work) │ └─────┬──────┘ └─────┬──────┘ │ │ │ 1. CONNECT (auth token + scopes) │ │───────────────────────────────────────►│ │ │ │ 2. CAPABILITIES (available APIs) │ │◄───────────────────────────────────────│ │ │ │ 3. QUERY / COMMAND (ongoing) │ │◄──────────────────────────────────────►│ │ │ │ 4. EVENT (push notifications) │ │◄───────────────────────────────────────│ │ │ │ 5. DISCONNECT (clean exit) │ │───────────────────────────────────────►│ │ │ ``` ### Message Types #### 1. `CONNECT` — Establish Federation Trust ```json { "type": "connect", "version": "0.0.1", "masterIdentity": { "instanceId": "mosaic-home-jason", "userId": "jason", "instanceUrl": "https://mosaic.home.local" }, "authToken": "oidc-access-token-or-api-key", "requestedScopes": [ "calendar.read", "calendar.write", "tasks.read", "tasks.write", "agents.query", "agents.command" ] } ``` #### 2. `CAPABILITIES` — Spoke Advertises Available APIs ```json { "type": "capabilities", "spokeIdentity": { "instanceId": "mosaic-work-usc", "instanceUrl": "https://mosaic.uscllc.com" }, "grantedScopes": ["calendar.read", "tasks.read", "tasks.write"], "deniedScopes": ["calendar.write", "agents.command"], "availableCommands": [ { "name": "tasks.list", "description": "List tasks in workspace", "params": { "workspaceId": "string", "status": "string?" } }, { "name": "tasks.create", "description": "Create a new task", "params": { "title": "string", "description": "string?" } }, { "name": "calendar.today", "description": "Get today's calendar events", "params": {} } ], "availableQueries": [ { "name": "status", "description": "Get instance status", "returns": "InstanceStatus" }, { "name": "workspaces.list", "description": "List accessible workspaces", "returns": "Workspace[]" } ], "eventSubscriptions": [ "calendar.reminder", "tasks.assigned", "tasks.completed" ] } ``` #### 3. `QUERY` — Read-Only Data Fetch ```json { "type": "query", "id": "q-abc123", "name": "calendar.today", "params": { "includeAllDay": true } } ``` **Response:** ```json { "type": "query.result", "id": "q-abc123", "success": true, "data": [ { "title": "Standup", "time": "09:00", "duration": 30 }, { "title": "1:1 with Mike", "time": "14:00", "duration": 60 } ], "provenance": { "instanceId": "mosaic-work-usc", "timestamp": "2025-01-29T14:30:00Z" } } ``` #### 4. `COMMAND` — Execute an Action ```json { "type": "command", "id": "c-def456", "name": "tasks.create", "params": { "title": "Review PR #421", "description": "Security review for auth changes", "priority": 8, "workspaceId": "ws-dev-team" } } ``` **Sync Response:** ```json { "type": "command.result", "id": "c-def456", "success": true, "data": { "taskId": "task-789", "url": "https://mosaic.uscllc.com/tasks/task-789" }, "provenance": { "instanceId": "mosaic-work-usc", "timestamp": "2025-01-29T14:31:00Z" } } ``` **Async Response (for long-running):** ```json { "type": "command.accepted", "id": "c-def456", "status": "pending", "pollUrl": "/federation/status/c-def456", "estimatedCompletion": "30s" } ``` #### 5. `EVENT` — Push Notification from Spoke ```json { "type": "event", "name": "calendar.reminder", "data": { "title": "1:1 with Mike", "startsIn": "15m", "location": "Conference Room B" }, "provenance": { "instanceId": "mosaic-work-usc", "timestamp": "2025-01-29T13:45:00Z" } } ``` #### 6. `DISCONNECT` — Clean Severance ```json { "type": "disconnect", "reason": "user-initiated", "revokeToken": true, "preserveHistory": false } ``` ### Agent-to-Agent Communication Masters can command spokes to execute agent tasks: ```json { "type": "command", "id": "c-agent-001", "name": "agents.spawn", "params": { "taskTitle": "Review today's tickets", "taskDescription": "Check GLPI for new high-priority tickets", "inputContext": { "priority": "high", "category": "network" }, "callbackUrl": "https://mosaic.home.local/federation/callback/c-agent-001" } } ``` The spoke agent executes the task and calls back with results: ```json { "type": "callback", "id": "c-agent-001", "success": true, "data": { "ticketsFound": 3, "tickets": [ { "id": "GLPI-1234", "title": "Switch failure in Building A" }, { "id": "GLPI-1235", "title": "VPN connectivity issues" }, { "id": "GLPI-1236", "title": "Printer offline 3rd floor" } ] } } ``` --- ## RBAC Model ### Hierarchy ``` Instance └── Workspace (like a Teams "Team") ├── Roles: owner, admin, member, viewer, guest ├── Teams (sub-groups within workspace) │ └── Roles: owner, admin, member ├── Projects / Channels │ └── Permissions (inherit or override) └── Members (users or groups from IdP) ``` ### Role Permissions Matrix | Permission | Owner | Admin | Member | Viewer | Guest | |------------|-------|-------|--------|--------|-------| | View workspace | ✓ | ✓ | ✓ | ✓ | ✓* | | Create content | ✓ | ✓ | ✓ | ✗ | ✗ | | Edit content | ✓ | ✓ | ✓ | ✗ | ✗ | | Delete content | ✓ | ✓ | ✗ | ✗ | ✗ | | Manage members | ✓ | ✓ | ✗ | ✗ | ✗ | | Manage teams | ✓ | ✓ | ✗ | ✗ | ✗ | | Configure workspace | ✓ | ✗ | ✗ | ✗ | ✗ | | Delete workspace | ✓ | ✗ | ✗ | ✗ | ✗ | | Manage federation | ✓ | ✗ | ✗ | ✗ | ✗ | *Guest: scoped to specific shared items only ### Federation RBAC Cross-instance access is always scoped and limited: ```json { "federation": { "trustedInstances": [ { "instanceId": "mosaic-work-usc", "trustLevel": "verified", "maxRole": "member", "scopedWorkspaces": ["ws-shared-projects"], "allowedCapabilities": ["tasks.read", "tasks.write", "calendar.read"], "deniedCapabilities": ["admin.*", "federation.*"] } ] } } ``` **Key Constraints:** - Federated users cannot exceed `maxRole` (e.g., member can't become admin) - Access limited to `scopedWorkspaces` only - Capabilities are explicitly allowlisted - Admin/federation capabilities always denied by default --- ## Data Sovereignty ### Core Principles 1. **Data Residency** — Data lives where it's created, never crosses boundaries 2. **Query, Don't Replicate** — Master queries spoke, doesn't store results 3. **Provenance Tagging** — Every piece of data tagged with source instance 4. **Clean Exit** — Disconnect = lose access, no cleanup needed ### Data Flow ``` ┌──────────────────────────────────────────────────────────────────┐ │ MASTER (Home) │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Aggregation Layer │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ │ │ Home Data │ │ Work Data │ │ Partner Data │ │ │ │ │ │ (stored) │ │ (queried) │ │ (queried) │ │ │ │ │ │ │ │ ⚡ live │ │ ⚡ live │ │ │ │ │ └─────────────┘ └──────┬──────┘ └──────────┬──────────┘ │ │ │ │ │ │ │ │ │ └──────────────────────────┼─────────────────────┼─────────────┘ │ │ │ │ │ └─────────────────────────────┼─────────────────────┼───────────────┘ │ │ ┌─────────▼─────────┐ ┌────────▼────────┐ │ SPOKE (Work) │ │ SPOKE (Partner) │ │ Data stays here │ │ Data stays here │ └───────────────────┘ └─────────────────┘ ``` ### What's Stored vs Queried | Data Type | Home Instance | Work Instance | Notes | |-----------|---------------|---------------|-------| | Personal tasks | ✓ Stored | — | Only at home | | Work tasks | Queried live | ✓ Stored | Never replicated | | Personal calendar | ✓ Stored | — | Only at home | | Work calendar | Queried live | ✓ Stored | Never replicated | | Federation metadata | ✓ Stored | ✓ Stored | Connection config only | | Query results cache | Ephemeral (5m TTL) | — | Optional, short-lived | ### Severance Procedure When disconnecting from a spoke: ``` 1. Master initiates DISCONNECT 2. Spoke revokes master's access token 3. Spoke removes master from trusted instances 4. Master removes spoke from connection list 5. All live queries fail immediately 6. No data cleanup needed—nothing was stored Result: - Master retains: its own data, federation config (marked disconnected) - Spoke retains: its own data, audit log of the connection - Neither has: the other's data ``` --- ## Implementation Phases ### Phase 1: Foundation (v0.0.x) **Goal:** Multi-instance awareness, basic federation protocol **Deliverables:** - [ ] Instance identity model (instanceId, URL, public key) - [ ] Federation connection database schema - [ ] Basic CONNECT/DISCONNECT protocol - [ ] Manual connection setup (no auto-discovery) - [ ] Query/Command message handling (stub) **Testing:** - Two local instances can connect - Connection persists across restarts - Disconnect cleans up properly ### Phase 2: Authentik Integration (v0.0.x) **Goal:** Enterprise SSO with RBAC **Deliverables:** - [ ] Authentik OIDC provider setup guide - [ ] BetterAuth Authentik adapter - [ ] Group → Role mapping - [ ] Multi-workspace session handling - [ ] Audit logging for auth events **Testing:** - Login via Authentik works - Groups map to roles correctly - Session isolation between workspaces ### Phase 3: Federation Protocol (v0.0.x) **Goal:** Full query/command capability **Deliverables:** - [ ] QUERY message type with response streaming - [ ] COMMAND message type with async support - [ ] EVENT subscription and delivery - [ ] Capability negotiation - [ ] Error handling and retry logic **Testing:** - Master can query spoke calendar - Master can create tasks on spoke - Events push from spoke to master - Errors handled gracefully ### Phase 4: Single Pane of Glass (v0.1.0 MVP) **Goal:** Unified dashboard showing all instances **Deliverables:** - [ ] Connection manager UI - [ ] Aggregated calendar view - [ ] Aggregated task view - [ ] Instance status indicators - [ ] Visual provenance tagging (color/icon per instance) **Testing:** - Dashboard shows data from multiple instances - Clear visual distinction between sources - Offline instance shows gracefully ### Phase 5: Agent Federation (v0.1.x) **Goal:** Cross-instance agent coordination **Deliverables:** - [ ] Agent spawn command via federation - [ ] Callback mechanism for results - [ ] Agent status querying across instances - [ ] Cross-instance task assignment **Testing:** - Home agent can spawn task on work instance - Results callback works - Agent health visible across instances ### Phase 6: Enterprise Features (v0.2.x) **Goal:** Production-ready for organizations **Deliverables:** - [ ] Admin console for federation management - [ ] Compliance audit reports - [ ] Rate limiting and quotas - [ ] Webhook integration - [ ] Multi-region support --- ## Versioning ### Semantic Versioning Policy | Version | Meaning | |---------|---------| | `0.0.x` | Active development, breaking changes expected, internal use only | | `0.1.0` | **MVP** — First user-testable release, core features working | | `0.x.y` | Pre-stable iteration, API may change with notice | | `1.0.0` | Stable release, public API contract, breaking changes require major version | ### Version Milestones | Version | Target | Features | |---------|--------|----------| | 0.0.1 | Design | This document | | 0.0.5 | Foundation | Basic federation protocol | | 0.0.10 | Auth | Authentik integration | | 0.1.0 | **MVP** | Single pane of glass, basic federation | | 0.2.0 | Agents | Cross-instance agent coordination | | 0.3.0 | Enterprise | Admin console, compliance | | 1.0.0 | Stable | Production-ready, API frozen | --- ## Security Considerations ### Transport Security - All federation traffic over TLS 1.3 - Certificate pinning for known instances (optional) - mTLS for high-security deployments ### Authentication - OIDC tokens with short expiry (1h) - Refresh tokens with longer expiry (7d) - API keys for service-to-service (no user context) ### Authorization - Capability-based access control - Explicit allowlists (deny by default) - No implicit transitivity (A→B→C doesn't mean A→C) ### Audit - All federation connections logged - All queries/commands logged with user identity - Retention configurable per compliance requirements ### Secrets - Never log tokens or credentials - Encrypt sensitive federation config at rest - Rotate API keys periodically --- ## API Endpoints ### Federation Management ```typescript // List connected instances GET /api/v1/federation/connections Response: FederationConnection[] // Initiate connection to spoke POST /api/v1/federation/connect { "spokeUrl": "https://mosaic.work.example.com", "authToken": "...", "requestedScopes": ["calendar.read", "tasks.*"] } // Disconnect from spoke DELETE /api/v1/federation/connections/:instanceId // Get connection status GET /api/v1/federation/connections/:instanceId/status // Update connection scopes PATCH /api/v1/federation/connections/:instanceId { "requestedScopes": ["calendar.*", "tasks.*"] } ``` ### Federated Queries ```typescript // Query a spoke POST /api/v1/federation/query { "instanceId": "mosaic-work-usc", "query": "calendar.today", "params": { "includeAllDay": true } } // Execute command on spoke POST /api/v1/federation/command { "instanceId": "mosaic-work-usc", "command": "tasks.create", "params": { "title": "Review PR", "priority": 8 } } ``` ### Spoke Configuration (for instances accepting connections) ```typescript // Get spoke settings GET /api/v1/federation/spoke/settings // Update spoke settings PATCH /api/v1/federation/spoke/settings { "acceptConnections": true, "allowedMasters": ["mosaic-home-jason"], "defaultScopes": ["calendar.read", "tasks.read"], "maxScopes": ["calendar.*", "tasks.*"] } // List connected masters GET /api/v1/federation/spoke/masters // Revoke master access DELETE /api/v1/federation/spoke/masters/:instanceId ``` --- ## Glossary | Term | Definition | |------|------------| | **Instance** | A single Mosaic Stack deployment | | **Master** | Instance that initiates connection and queries spoke | | **Spoke** | Instance that accepts connections and serves data | | **Peer** | An instance that can be both master and spoke | | **Federation** | Network of connected Mosaic Stack instances | | **Scope** | Permission to perform specific actions (e.g., `calendar.read`) | | **Capability** | API endpoint exposed by a spoke | | **Provenance** | Source attribution for data (which instance it came from) | | **Severance** | Clean disconnection with no data cleanup required | | **IdP** | Identity Provider (e.g., Authentik) | --- ## References - [Authentik Documentation](https://goauthentik.io/docs/) - [OIDC Specification](https://openid.net/specs/openid-connect-core-1_0.html) - [Multi-Tenant RLS Design](./multi-tenant-rls.md) - [Agent Orchestration Design](./agent-orchestration.md) - [Architecture Decisions](./architecture-decisions.md) --- ## Open Questions 1. **Identity Linking:** How do we link the same person across instances with different IdPs? 2. **Conflict Resolution:** What happens if the same entity is modified on multiple instances? 3. **Offline Handling:** How long to cache spoke data when offline? 4. **Rate Limiting:** How to prevent spoke overload from aggressive masters? 5. **Discovery:** Should instances be discoverable, or always manual connection? --- **Next Steps:** 1. Review and approve this design document 2. Create GitHub issues for Phase 1 tasks 3. Set up Authentik development instance 4. Begin federation protocol implementation **Questions/Feedback:** Open an issue in `mosaic-stack` repo with label `federation`.