Captures: - Peer-to-peer federation model (master/spoke) - Agent Federation Protocol (CONNECT, QUERY, COMMAND, EVENT, DISCONNECT) - Authentik integration for enterprise SSO and RBAC - Data sovereignty principles (query, don't replicate) - RBAC model with workspace/team hierarchy - Implementation phases targeting 0.1.0 MVP - Versioning policy (0.0.x dev, 0.1.0 MVP, 1.0.0 stable)
29 KiB
Federation Architecture
Version: 0.0.1
Status: Design Phase
Author: Mosaic Stack Team
Date: 2025-01-29
Table of Contents
- Problem Statement
- Architecture Overview
- Identity & Authentication
- Agent Federation Protocol
- RBAC Model
- Data Sovereignty
- Implementation Phases
- Versioning
Problem Statement
Use Cases
-
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
-
Enterprise Control
- Organization runs their own Mosaic Stack instance
- Teams within the org have isolated workspaces
- IT controls access, audit, compliance
-
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:
{
"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
{
"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
{
"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
{
"type": "query",
"id": "q-abc123",
"name": "calendar.today",
"params": { "includeAllDay": true }
}
Response:
{
"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
{
"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:
{
"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):
{
"type": "command.accepted",
"id": "c-def456",
"status": "pending",
"pollUrl": "/federation/status/c-def456",
"estimatedCompletion": "30s"
}
5. EVENT — Push Notification from Spoke
{
"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
{
"type": "disconnect",
"reason": "user-initiated",
"revokeToken": true,
"preserveHistory": false
}
Agent-to-Agent Communication
Masters can command spokes to execute agent tasks:
{
"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:
{
"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:
{
"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
scopedWorkspacesonly - Capabilities are explicitly allowlisted
- Admin/federation capabilities always denied by default
Data Sovereignty
Core Principles
- Data Residency — Data lives where it's created, never crosses boundaries
- Query, Don't Replicate — Master queries spoke, doesn't store results
- Provenance Tagging — Every piece of data tagged with source instance
- 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
// 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
// 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)
// 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
- OIDC Specification
- Multi-Tenant RLS Design
- Agent Orchestration Design
- Architecture Decisions
Open Questions
- Identity Linking: How do we link the same person across instances with different IdPs?
- Conflict Resolution: What happens if the same entity is modified on multiple instances?
- Offline Handling: How long to cache spoke data when offline?
- Rate Limiting: How to prevent spoke overload from aggressive masters?
- Discovery: Should instances be discoverable, or always manual connection?
Next Steps:
- Review and approve this design document
- Create GitHub issues for Phase 1 tasks
- Set up Authentik development instance
- Begin federation protocol implementation
Questions/Feedback: Open an issue in mosaic-stack repo with label federation.