feat(#359): Encrypt LLM provider API keys in database
Implemented transparent encryption/decryption of LLM provider API keys stored in llm_provider_instances.config JSON field using OpenBao Transit encryption. Implementation: - Created llm-encryption.middleware.ts with encryption/decryption logic - Auto-detects format (vault:v1: vs plaintext) for backward compatibility - Idempotent encryption prevents double-encryption - Registered middleware in PrismaService - Created data migration script for active encryption - Added migrate:encrypt-llm-keys command to package.json Tests: - 14 comprehensive unit tests - 90.76% code coverage (exceeds 85% requirement) - Tests create, read, update, upsert operations - Tests error handling and backward compatibility Migration: - Lazy migration: New keys encrypted, old keys work until re-saved - Active migration: pnpm --filter @mosaic/api migrate:encrypt-llm-keys - No schema changes required - Zero downtime Security: - Uses TransitKey.LLM_CONFIG from OpenBao Transit - Keys never touch disk in plaintext (in-memory only) - Transparent to LlmManagerService and providers - Follows proven pattern from account-encryption.middleware.ts Files: - apps/api/src/prisma/llm-encryption.middleware.ts (new) - apps/api/src/prisma/llm-encryption.middleware.spec.ts (new) - apps/api/scripts/encrypt-llm-keys.ts (new) - apps/api/prisma/migrations/20260207_encrypt_llm_api_keys/ (new) - apps/api/src/prisma/prisma.service.ts (modified) - apps/api/package.json (modified) Note: The migration script (encrypt-llm-keys.ts) is not included in tsconfig.json to avoid rootDir conflicts. It's executed via tsx which handles TypeScript directly. Refs #359 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from "@nestjs/commo
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { VaultService } from "../vault/vault.service";
|
||||
import { registerAccountEncryptionMiddleware } from "./account-encryption.middleware";
|
||||
import { registerLlmEncryptionMiddleware } from "./llm-encryption.middleware";
|
||||
|
||||
/**
|
||||
* Prisma service that manages database connection lifecycle
|
||||
@@ -33,6 +34,10 @@ export class PrismaService extends PrismaClient implements OnModuleInit, OnModul
|
||||
// VaultService provides OpenBao Transit encryption with AES-256-GCM fallback
|
||||
registerAccountEncryptionMiddleware(this, this.vaultService);
|
||||
this.logger.log("Account encryption middleware registered");
|
||||
|
||||
// Register LLM provider API key encryption middleware
|
||||
registerLlmEncryptionMiddleware(this, this.vaultService);
|
||||
this.logger.log("LLM encryption middleware registered");
|
||||
} catch (error) {
|
||||
this.logger.error("Failed to connect to database", error);
|
||||
throw error;
|
||||
|
||||
Reference in New Issue
Block a user