UNPKG

@iota-big3/sdk-security

Version:

Advanced security features including zero trust, quantum-safe crypto, and ML threat detection

610 lines 21.8 kB
"use strict"; /** * AWS Secrets Manager Provider * Native AWS integration for secrets management */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AWSSecretsProvider = void 0; const events_1 = require("events"); const types_1 = require("../types"); class AWSSecretsProvider extends events_1.EventEmitter { constructor(config) { super(); this.provider = types_1.SecretsProvider.AWS_SECRETS_MANAGER; this.isInitialized = false; this.cache = new Map(); this.config = config; this.validateConfig(); } /** * Initialize AWS Secrets Manager client */ async initialize() { if (this.isInitialized) return; try { // In production, would initialize AWS SDK client // const client = new SecretsManagerClient({ // region: this.config.region, // credentials: this.getAWSCredentials() // }); this.isInitialized = true; this.emit('initialized', { provider: this.provider }); } catch (error) { this.emit('error', { error, operation: 'initialize' }); throw error; } } /** * Get secret from AWS Secrets Manager */ async getSecret(name, version) { await this.ensureInitialized(); // Check cache if (this.config.caching?.enabled && !version) { const cached = this.getFromCache(name); if (cached) return cached; } try { // Simulate AWS API call const response = await this.awsGetSecret(name, version); const secret = { name: response.Name, value: this.parseSecretValue(response.SecretString, response.SecretBinary), type: this.inferSecretType(response.Name, response.Tags), createdAt: response.CreatedDate, updatedAt: response.LastChangedDate || response.CreatedDate, version: response.VersionId, tags: this.convertTagsToRecord(response.Tags), description: response.Description }; // Check rotation if (response.RotationEnabled) { secret.rotationPolicy = { enabled: true, interval: 30, // AWS default lastRotated: response.LastRotatedDate, nextRotation: response.NextRotationDate, autoRotate: true, rotationFunction: response.RotationLambdaARN }; } // Cache if enabled if (this.config.caching?.enabled && !version) { this.addToCache(name, secret); } // Audit this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.READ, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'SUCCESS' }); return secret; } catch (error) { this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.READ, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'FAILURE', error: error.message }); throw error; } } /** * Create or update secret */ async setSecret(name, value, metadata) { await this.ensureInitialized(); try { const secretString = typeof value === 'string' ? value : JSON.stringify(value); const tags = metadata?.tags ? this.convertRecordToTags(metadata.tags) : undefined; // Check if secret exists const exists = await this.secretExists(name); if (exists) { // Update existing secret await this.awsUpdateSecret(name, secretString, metadata?.description); // Update tags if provided if (tags) { await this.awsTagResource(name, tags); } } else { // Create new secret await this.awsCreateSecret(name, secretString, { description: metadata?.description, tags, kmsKeyId: this.config.encryption?.keyId }); } // Configure rotation if specified if (metadata?.rotationPolicy?.enabled) { await this.configureRotation(name, metadata.rotationPolicy); } // Clear cache this.cache.delete(name); // Audit this.auditLog({ timestamp: new Date(), action: exists ? types_1.SecretAction.UPDATE : types_1.SecretAction.CREATE, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'SUCCESS', metadata: { type: metadata?.type } }); this.emit('secret:' + (exists ? 'updated' : 'created'), { name, metadata }); } catch (error) { this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.CREATE, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'FAILURE', error: error.message }); throw error; } } /** * Delete secret */ async deleteSecret(name, permanent) { await this.ensureInitialized(); try { if (permanent) { // Force delete without recovery window await this.awsDeleteSecret(name, true); } else { // Schedule deletion with 30-day recovery window await this.awsDeleteSecret(name, false); } // Clear cache this.cache.delete(name); // Audit this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.DELETE, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'SUCCESS', metadata: { permanent } }); this.emit('secret:deleted', { name, permanent }); } catch (error) { this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.DELETE, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'FAILURE', error: error.message }); throw error; } } /** * List secrets */ async listSecrets(filter) { await this.ensureInitialized(); try { const allSecrets = await this.awsListSecrets(); const secrets = []; for (const secretSummary of allSecrets) { // Apply name filter if (filter?.namePattern && !secretSummary.Name.match(new RegExp(filter.namePattern))) { continue; } // Get full metadata for filtering const tags = this.convertTagsToRecord(secretSummary.Tags); // Apply tag filter if (filter?.tags && !this.matchTags(tags, filter.tags)) { continue; } // Apply date filter if (filter?.modifiedSince && secretSummary.LastChangedDate < filter.modifiedSince) { continue; } const metadata = { name: secretSummary.Name, type: this.inferSecretType(secretSummary.Name, secretSummary.Tags), description: secretSummary.Description, createdAt: secretSummary.CreatedDate, updatedAt: secretSummary.LastChangedDate || secretSummary.CreatedDate, tags }; // Add rotation info if available if (secretSummary.RotationEnabled) { metadata.rotationPolicy = { enabled: true, interval: 30, lastRotated: secretSummary.LastRotatedDate, autoRotate: true }; } secrets.push(metadata); } return secrets; } catch (error) { throw new Error(`Failed to list secrets: ${error.message}`); } } /** * Rotate secret */ async rotateSecret(name) { await this.ensureInitialized(); try { // Trigger rotation await this.awsRotateSecret(name); // Clear cache this.cache.delete(name); // Audit this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.ROTATE, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'SUCCESS' }); this.emit('secret:rotated', { name }); } catch (error) { this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.ROTATE, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'FAILURE', error: error.message }); throw error; } } /** * Schedule rotation */ async scheduleRotation(name, policy) { await this.ensureInitialized(); if (!policy.rotationFunction) { throw new Error('Rotation Lambda ARN is required for AWS Secrets Manager'); } await this.awsConfigureRotation(name, { AutomaticallyAfterDays: policy.interval, LambdaFunctionArn: policy.rotationFunction }); this.emit('rotation:scheduled', { name, interval: policy.interval }); } /** * Get secret versions */ async getSecretVersions(name) { await this.ensureInitialized(); const versions = await this.awsListSecretVersions(name); return versions .filter(v => !v.VersionStages?.includes('AWSPENDING')) .map(v => v.VersionId) .filter(Boolean); } /** * Rollback to specific version */ async rollbackSecret(name, version) { await this.ensureInitialized(); try { // Get the specified version const oldValue = await this.awsGetSecret(name, version); // Update current version with old value await this.awsUpdateSecret(name, oldValue.SecretString || Buffer.from(oldValue.SecretBinary).toString('base64')); // Clear cache this.cache.delete(name); // Audit this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.ROLLBACK, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'SUCCESS', metadata: { targetVersion: version } }); this.emit('secret:rollback', { name, version }); } catch (error) { this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.ROLLBACK, secretName: name, actor: { id: 'system', type: 'SYSTEM' }, result: 'FAILURE', error: error.message }); throw error; } } /** * Get multiple secrets */ async getBulkSecrets(names) { // AWS doesn't have bulk get, so we parallelize individual requests const secrets = await Promise.all(names.map(name => this.getSecret(name).catch(() => null))); return secrets.filter(Boolean); } /** * Import secrets */ async importSecrets(secrets) { // Process in batches to avoid rate limits const batchSize = 10; for (let i = 0; i < secrets.length; i += batchSize) { const batch = secrets.slice(i, i + batchSize); await Promise.all(batch.map(secret => this.setSecret(secret.name, secret.value, secret))); } this.emit('secrets:imported', { count: secrets.length }); } /** * Export secrets */ async exportSecrets(filter) { const metadata = await this.listSecrets(filter); const secrets = []; // Export in batches const batchSize = 10; for (let i = 0; i < metadata.length; i += batchSize) { const batch = metadata.slice(i, i + batchSize); const batchSecrets = await Promise.all(batch.map(meta => this.getSecret(meta.name).catch(() => null))); secrets.push(...batchSecrets.filter(Boolean)); } this.auditLog({ timestamp: new Date(), action: types_1.SecretAction.EXPORT, secretName: '*', actor: { id: 'system', type: 'SYSTEM' }, result: 'SUCCESS', metadata: { count: secrets.length } }); return secrets; } /** * Health check */ async healthCheck() { const startTime = Date.now(); try { // Try to list secrets with limit 1 await this.awsListSecrets(1); return { healthy: true, provider: this.provider, connectivity: true, authentication: true, lastCheck: new Date(), latency: Date.now() - startTime }; } catch (error) { return { healthy: false, provider: this.provider, connectivity: false, authentication: false, lastCheck: new Date(), latency: Date.now() - startTime, errors: [error.message] }; } } /** * Helper methods */ validateConfig() { if (!this.config.region) { throw new Error('AWS region is required'); } } async ensureInitialized() { if (!this.isInitialized) { await this.initialize(); } } getFromCache(name) { if (!this.config.caching?.enabled) return null; const cached = this.cache.get(name); if (!cached) return null; const age = Date.now() - cached.cachedAt.getTime(); if (age > (this.config.caching.ttl * 1000)) { this.cache.delete(name); return null; } return cached.secret; } addToCache(name, secret) { if (!this.config.caching?.enabled) return; // Check cache size const maxSize = this.config.caching.maxSize || 100; if (this.cache.size >= maxSize) { // Remove oldest entry const oldest = Array.from(this.cache.entries()) .sort((a, b) => a[1].cachedAt.getTime() - b[1].cachedAt.getTime())[0]; this.cache.delete(oldest[0]); } this.cache.set(name, { secret, cachedAt: new Date() }); } parseSecretValue(secretString, secretBinary) { if (secretString) { try { return JSON.parse(secretString); } catch { return secretString; } } if (secretBinary) { return Buffer.from(secretBinary); } return null; } inferSecretType(name, tags) { // Check tags first const tagMap = this.convertTagsToRecord(tags); if (tagMap.type) { return tagMap.type; } // Infer from name if (name.includes('api') || name.includes('key')) return types_1.SecretType.API_KEY; if (name.includes('db') || name.includes('database') || name.includes('rds')) { return types_1.SecretType.DATABASE_CREDENTIAL; } if (name.includes('cert')) return types_1.SecretType.CERTIFICATE; if (name.includes('ssh')) return types_1.SecretType.SSH_KEY; if (name.includes('token')) return types_1.SecretType.TOKEN; return types_1.SecretType.CUSTOM; } convertTagsToRecord(tags) { if (!tags) return {}; const record = {}; for (const tag of tags) { record[tag.Key] = tag.Value; } return record; } convertRecordToTags(record) { return Object.entries(record).map(([Key, Value]) => ({ Key, Value })); } matchTags(secretTags, filterTags) { return Object.entries(filterTags).every(([key, value]) => secretTags[key] === value); } async secretExists(name) { try { await this.awsGetSecret(name); return true; } catch (error) { if (error.name === 'ResourceNotFoundException') { return false; } throw error; } } async configureRotation(name, policy) { if (!policy.rotationFunction) { // Auto-create rotation Lambda for RDS/DocumentDB if (name.includes('rds') || name.includes('docdb')) { policy.rotationFunction = await this.createRotationLambda(name); } else { throw new Error('Rotation function ARN required'); } } await this.awsConfigureRotation(name, { AutomaticallyAfterDays: policy.interval, LambdaFunctionArn: policy.rotationFunction }); } async createRotationLambda(secretName) { // In production, would create appropriate rotation Lambda // based on secret type (RDS, DocumentDB, etc.) return `arn:aws:lambda:${this.config.region}:123456789012:function:SecretsManagerRotation`; } auditLog(event) { this.emit('audit', event); // Could also send to CloudTrail or CloudWatch } /** * AWS API Mock Methods * In production, these would use actual AWS SDK */ async awsGetSecret(name, version) { await new Promise(resolve => setTimeout(resolve, 50)); return { Name: name, VersionId: version || 'AWSCURRENT', SecretString: JSON.stringify({ username: 'admin', password: 'secret123' }), CreatedDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), LastChangedDate: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), Description: 'Mock secret', Tags: [{ Key: 'Environment', Value: 'production' }], RotationEnabled: name.includes('rds'), LastRotatedDate: name.includes('rds') ? new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) : undefined, NextRotationDate: name.includes('rds') ? new Date(Date.now() + 23 * 24 * 60 * 60 * 1000) : undefined, RotationLambdaARN: name.includes('rds') ? 'arn:aws:lambda:us-east-1:123456789012:function:rotation' : undefined }; } async awsCreateSecret(name, value, options) { await new Promise(resolve => setTimeout(resolve, 100)); // Mock create } async awsUpdateSecret(name, value, description) { await new Promise(resolve => setTimeout(resolve, 100)); // Mock update } async awsDeleteSecret(name, forceDelete) { await new Promise(resolve => setTimeout(resolve, 100)); // Mock delete } async awsListSecrets(maxResults) { await new Promise(resolve => setTimeout(resolve, 100)); return [ { Name: 'prod/api/key', Description: 'Production API key', CreatedDate: new Date(Date.now() - 60 * 24 * 60 * 60 * 1000), LastChangedDate: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), Tags: [{ Key: 'Environment', Value: 'production' }] }, { Name: 'prod/rds/master', Description: 'RDS master credentials', CreatedDate: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000), LastChangedDate: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), Tags: [{ Key: 'Type', Value: 'database' }], RotationEnabled: true, LastRotatedDate: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) } ].slice(0, maxResults); } async awsRotateSecret(name) { await new Promise(resolve => setTimeout(resolve, 200)); // Mock rotation } async awsConfigureRotation(name, config) { await new Promise(resolve => setTimeout(resolve, 100)); // Mock rotation configuration } async awsListSecretVersions(name) { await new Promise(resolve => setTimeout(resolve, 100)); return [ { VersionId: 'AWSCURRENT', VersionStages: ['AWSCURRENT'] }, { VersionId: 'v2', VersionStages: [] }, { VersionId: 'v1', VersionStages: [] } ]; } async awsTagResource(arn, tags) { await new Promise(resolve => setTimeout(resolve, 50)); // Mock tagging } } exports.AWSSecretsProvider = AWSSecretsProvider; //# sourceMappingURL=aws-secrets-provider.js.map