The Key Management Service implements multiple layers of security to protect encryption keys and sensitive data. These measures include rate limiting, data validation, key expiration enforcement, and comprehensive monitoring.
Security is a shared responsibility. While the service provides robust protection, proper deployment configuration, network security, and access controls are essential.
To prevent abuse and DoS attacks, the service implements rate limiting for key generation:
private readonly MAX_KEY_GEN_PER_DEVICE = 5;private readonly KEY_GEN_WINDOW_MS = 24 * 60 * 60 * 1000; // 24 hoursprivate enforceKeyGenerationRateLimit(deviceId: string): void { const now = Date.now(); const deviceLimits = this.deviceKeyGenLimits.get(deviceId) || { count: 0, resetTime: now + this.KEY_GEN_WINDOW_MS, }; // Reset counter if time window has passed if (now > deviceLimits.resetTime) { deviceLimits.count = 0; deviceLimits.resetTime = now + this.KEY_GEN_WINDOW_MS; } // Increment counter and update deviceLimits.count++; this.deviceKeyGenLimits.set(deviceId, deviceLimits);}
Reference: encryption.service.ts:16-17, 227-254
Default Limits: A device can generate a maximum of 5 keys per 24-hour period. This prevents malicious actors from overwhelming the service while allowing legitimate use cases.
Every key operation validates that the key has not expired:
private async getPrivateKey(keyId: string): Promise<string> { const keyEntry = await this.prismaService.clientEncryptionKey.findUnique({ where: { id: keyId }, }); if (!keyEntry) { throw new Error('Encryption key not found'); } // Check if key has expired if (keyEntry.expiresAt && keyEntry.expiresAt < new Date()) { this.logger.warn(`Key with ID ${keyId} has expired`); throw new Error('Encryption key has expired'); } return keyEntry.privateKey;}
The monitoring service provides comprehensive analytics:
async generateMetricsSummary(timeframeHours: number = 24): Promise<any> { const timeThreshold = new Date(); timeThreshold.setHours(timeThreshold.getHours() - timeframeHours); // Get total counts by operation and status const metrics = await this.prismaService.$queryRaw` SELECT operation, status, COUNT(*) as count, AVG(duration) as avg_duration FROM "EncryptionMetric" WHERE timestamp >= ${timeThreshold} GROUP BY operation, status `; // Get failure rates const failureRates = await this.prismaService.$queryRaw` SELECT operation, SUM(CASE WHEN status = 'failure' THEN 1 ELSE 0 END) * 100.0 / COUNT(*) as failure_rate FROM "EncryptionMetric" WHERE timestamp >= ${timeThreshold} GROUP BY operation `; // Top failure reasons const topFailures = await this.prismaService.$queryRaw` SELECT operation, "errorReason" AS reason, COUNT(*) AS count FROM "EncryptionMetric" WHERE status = 'failure' AND timestamp >= ${timeThreshold} GROUP BY operation, "errorReason" ORDER BY count DESC LIMIT 10 `; return { metrics, failureRates, topFailures, timeframeHours };}
Private keys are NEVER exposed to clients. They remain secure on the server at all times.
/** * Retrieves the private key for a given keyId * Never exposes private key to clients */private async getPrivateKey(keyId: string): Promise<string> { // Private method - not accessible via API const keyEntry = await this.prismaService.clientEncryptionKey.findUnique({ where: { id: keyId }, }); return keyEntry.privateKey;}