# Federation Credential Isolation ## Overview This document describes the security guarantees preventing user credentials from leaking across federation boundaries in Mosaic Stack. ## Threat Model **Attack Scenarios:** 1. Compromised federated instance attempts to query credentials 2. Malicious actor sends credential-related commands 3. Accidental credential exposure via federation messages 4. Transit key compromise on one instance ## Defense-in-Depth Architecture Mosaic Stack implements multiple layers of protection to prevent credential leakage: ### Layer 1: Cryptographic Isolation **Separate Transit Keys:** - **mosaic-credentials**: Used exclusively for user credentials (API keys, OAuth tokens, secrets) - **mosaic-federation**: Used exclusively for federation private keys - **Key Management**: Each key has independent lifecycle and access controls **Per-Instance OpenBao:** - Each federated instance runs its own OpenBao server - Transit keys are not shared between instances - Even if one instance's Transit key is compromised, credentials on other instances remain protected **Result:** Credentials encrypted with `mosaic-credentials` on Instance A cannot be decrypted by compromised `mosaic-credentials` key on Instance B, as they are completely separate keys on separate OpenBao instances. ### Layer 2: Application-Layer Deny-Lists **Query Service Isolation:** ```typescript // QueryService blocks all credential-related queries private isCredentialQuery(query: string): boolean { const credentialKeywords = [ "credential", "user_credential", "api_key", "secret", "token", "password", "oauth", "access_token", ]; return credentialKeywords.some(k => query.toLowerCase().includes(k)); } ``` **Command Service Isolation:** ```typescript // CommandService blocks all credential operations private isCredentialCommand(commandType: string): boolean { const credentialPrefixes = ["credential.", "credentials."]; return credentialPrefixes.some(p => commandType.toLowerCase().startsWith(p)); } ``` **Blocked Operations:** - ❌ `SELECT * FROM user_credentials` - ❌ `credential.create` - ❌ `credential.update` - ❌ `credential.delete` - ❌ `credential.read` - ❌ `credentials.list` **Allowed Operations:** - ✅ Task queries - ✅ Event queries - ✅ Project queries - ✅ Agent spawn commands ### Layer 3: Message Payload Verification **Federation Messages:** - Query messages: Only contain query string and workspace context - Command messages: Only contain command type and non-credential payload - Event messages: Only contain event type and metadata **No Plaintext Credentials:** - Federation messages NEVER contain credential plaintext - Credentials are encrypted at rest with `mosaic-credentials` Transit key - Credentials are only decrypted within the owning instance ### Layer 4: Workspace Isolation **Row-Level Security (RLS):** - UserCredential table enforces per-workspace isolation - Federation queries require explicit workspace context - Cross-workspace credential access is prohibited **Access Control:** ```sql -- UserCredential model model UserCredential { userId String workspaceId String? // Nullable for user-scope credentials scope CredentialScope // USER | WORKSPACE | SYSTEM @@unique([userId, workspaceId, provider, name]) @@index([workspaceId]) } ``` ## Security Guarantees ### G1: Credential Confidentiality **Guarantee:** User credentials never leave the owning instance in plaintext or decryptable form. **Enforcement:** - Transit encryption with per-instance keys - Application-layer deny-lists - No credential data in federation messages **Verification:** Integration tests in `credential-isolation.integration.spec.ts` ### G2: Cross-Instance Isolation **Guarantee:** Compromised Transit key on Instance A cannot decrypt credentials on Instance B. **Enforcement:** - Each instance has independent OpenBao server - Transit keys are not shared or synchronized - No mechanism for cross-instance key access **Verification:** Architectural design + infrastructure separation ### G3: Query/Command Isolation **Guarantee:** Federated instances cannot query or modify credentials on remote instances. **Enforcement:** - QueryService deny-list blocks credential queries - CommandService deny-list blocks credential operations - Errors returned for blocked operations **Verification:** Unit tests in `query.service.spec.ts` and `command.service.spec.ts` ### G4: Accidental Exposure Prevention **Guarantee:** Credentials cannot accidentally leak via federation messages. **Enforcement:** - Message payloads explicitly exclude credential data - Serialization logic filters credential fields - Type system prevents credential inclusion **Verification:** Message type definitions + code review ## Testing ### Unit Tests ```bash pnpm --filter @mosaic/api test query.service.spec pnpm --filter @mosaic/api test command.service.spec ``` **Coverage:** - Credential query blocking - Credential command blocking - Case-insensitive keyword matching - Valid operation allowance ### Integration Tests ```bash pnpm --filter @mosaic/api test credential-isolation.integration.spec ``` **Coverage:** - End-to-end query isolation - End-to-end command isolation - Multi-case keyword variants - Architecture documentation tests ### Manual Verification **Test Scenario: Attempt Credential Query** ```bash # From remote instance, send query curl -X POST https://instance-a.example.com/api/v1/federation/incoming/query \ -H "Content-Type: application/json" \ -d '{ "messageId": "test-1", "instanceId": "instance-b", "query": "SELECT * FROM user_credentials", "context": {"workspaceId": "workspace-1"}, "timestamp": 1234567890, "signature": "..." }' # Expected Response: # { # "success": false, # "error": "Credential queries are not allowed via federation" # } ``` ## Monitoring & Alerting **Recommended Alerts:** 1. **Credential Query Attempts**: Alert when credential queries are blocked 2. **Transit Key Usage**: Monitor `mosaic-credentials` decrypt operations 3. **Federation Message Volume**: Detect abnormal query patterns 4. **OpenBao Health**: Alert on OpenBao unavailability (falls back to local encryption) **Audit Logging:** ```typescript // QueryService logs blocked credential queries this.logger.warn(`Blocked credential query from ${instanceId}`, { messageId, query, timestamp: new Date(), }); ``` ## Incident Response **If Credential Exposure Suspected:** 1. **Immediate Actions:** - Suspend affected federation connections - Rotate all potentially exposed credentials - Review audit logs for compromise indicators 2. **Investigation:** - Check QueryService/CommandService logs for blocked attempts - Verify Transit key integrity via OpenBao audit logs - Analyze federation message payloads for credential data 3. **Remediation:** - Rotate all credentials in affected workspaces - Update deny-lists if new attack vector discovered - Re-establish federation connections after verification ## References - **Design Document**: `docs/design/credential-security.md` - **VaultService Implementation**: `apps/api/src/vault/vault.service.ts` - **QueryService Implementation**: `apps/api/src/federation/query.service.ts` - **CommandService Implementation**: `apps/api/src/federation/command.service.ts` - **Transit Keys**: `apps/api/src/vault/vault.constants.ts` ## Change Log | Date | Version | Change | | ---------- | ------- | ---------------------------------- | | 2026-02-07 | 1.0 | Initial documentation (Issue #360) |