fix(#84): address critical security issues in federation identity
Implemented comprehensive security fixes for federation instance identity: CRITICAL SECURITY FIXES: 1. Private Key Encryption at Rest (AES-256-GCM) - Implemented CryptoService with AES-256-GCM encryption - Private keys encrypted before database storage - Decrypted only when needed in-memory - Master key stored in ENCRYPTION_KEY environment variable - Updated schema comment to reflect actual encryption method 2. Admin Authorization on Key Regeneration - Created AdminGuard for system-level admin operations - Requires workspace ownership for admin privileges - Key regeneration restricted to admin users only - Proper authorization checks before sensitive operations 3. Private Key Never Exposed in API Responses - Changed regenerateKeypair return type to PublicInstanceIdentity - Service method strips private key before returning - Added tests to verify private key exclusion - Controller returns only public identity ADDITIONAL SECURITY IMPROVEMENTS: 4. Audit Logging for Key Regeneration - Created FederationAuditService - Logs all keypair regeneration events - Includes userId, instanceId, and timestamp - Marked as security events for compliance 5. Input Validation for INSTANCE_URL - Validates URL format (must be HTTP/HTTPS) - Throws error on invalid URLs - Prevents malformed configuration 6. Added .env.example - Documents all required environment variables - Includes INSTANCE_NAME, INSTANCE_URL - Includes ENCRYPTION_KEY with generation instructions - Clear security warnings for production use TESTING: - Added 11 comprehensive crypto service tests - Updated 8 federation service tests for encryption - Updated 5 controller tests for security verification - Total: 24 tests passing (100% success rate) - Verified private key never exposed in responses - Verified encryption/decryption round-trip - Verified admin authorization requirements FILES CREATED: - apps/api/src/federation/crypto.service.ts (encryption) - apps/api/src/federation/crypto.service.spec.ts (tests) - apps/api/src/federation/audit.service.ts (audit logging) - apps/api/src/auth/guards/admin.guard.ts (authorization) - apps/api/.env.example (configuration template) FILES MODIFIED: - apps/api/prisma/schema.prisma (updated comment) - apps/api/src/federation/federation.service.ts (encryption integration) - apps/api/src/federation/federation.controller.ts (admin guard, audit) - apps/api/src/federation/federation.module.ts (new providers) - All test files updated for new security requirements CODE QUALITY: - All tests passing (24/24) - TypeScript compilation: PASS - ESLint: PASS - Test coverage maintained at 100% Fixes #84 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,16 +4,22 @@
|
||||
* API endpoints for instance identity and federation management.
|
||||
*/
|
||||
|
||||
import { Controller, Get, Post, UseGuards, Logger } from "@nestjs/common";
|
||||
import { Controller, Get, Post, UseGuards, Logger, Req } from "@nestjs/common";
|
||||
import { FederationService } from "./federation.service";
|
||||
import { FederationAuditService } from "./audit.service";
|
||||
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||
import { PublicInstanceIdentity, InstanceIdentity } from "./types/instance.types";
|
||||
import { AdminGuard } from "../auth/guards/admin.guard";
|
||||
import type { PublicInstanceIdentity } from "./types/instance.types";
|
||||
import type { AuthenticatedRequest } from "../common/types/user.types";
|
||||
|
||||
@Controller("api/v1/federation")
|
||||
export class FederationController {
|
||||
private readonly logger = new Logger(FederationController.name);
|
||||
|
||||
constructor(private readonly federationService: FederationService) {}
|
||||
constructor(
|
||||
private readonly federationService: FederationService,
|
||||
private readonly auditService: FederationAuditService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get this instance's public identity
|
||||
@@ -27,12 +33,23 @@ export class FederationController {
|
||||
|
||||
/**
|
||||
* Regenerate instance keypair
|
||||
* Requires authentication - this is an admin operation
|
||||
* Requires system administrator privileges
|
||||
* Returns public identity only (private key never exposed in API)
|
||||
*/
|
||||
@Post("instance/regenerate-keys")
|
||||
@UseGuards(AuthGuard)
|
||||
async regenerateKeys(): Promise<InstanceIdentity> {
|
||||
this.logger.log("POST /api/v1/federation/instance/regenerate-keys");
|
||||
return this.federationService.regenerateKeypair();
|
||||
@UseGuards(AuthGuard, AdminGuard)
|
||||
async regenerateKeys(@Req() req: AuthenticatedRequest): Promise<PublicInstanceIdentity> {
|
||||
if (!req.user) {
|
||||
throw new Error("User not authenticated");
|
||||
}
|
||||
|
||||
this.logger.warn(`Admin user ${req.user.id} regenerating instance keypair`);
|
||||
|
||||
const result = await this.federationService.regenerateKeypair();
|
||||
|
||||
// Audit log for security compliance
|
||||
this.auditService.logKeypairRegeneration(req.user.id, result.instanceId);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user