UNPKG

@codai/cbd

Version:

Codai Better Database - High-Performance Vector Memory System with HPKV-inspired architecture and MCP server

441 lines (367 loc) • 14.8 kB
// CBD SSL Certificate - AWS Cloud Automation // Fully automated SSL certificate management with zero maintenance const { ACMClient, RequestCertificateCommand, DescribeCertificateCommand, ListCertificatesCommand } = require('@aws-sdk/client-acm'); const { ElasticLoadBalancingV2Client, ModifyListenerCommand, DescribeListenersCommand, CreateListenerCommand } = require('@aws-sdk/client-elastic-load-balancing-v2'); const { LambdaClient, CreateFunctionCommand, UpdateFunctionCodeCommand } = require('@aws-sdk/client-lambda'); const { EventBridgeClient, PutRuleCommand, PutTargetsCommand } = require('@aws-sdk/client-eventbridge'); class CBDSSLCloudAutomation { constructor() { this.domain = 'cbd.memorai.ro'; this.region = 'us-east-1'; // ACM certificates for CloudFront must be in us-east-1 this.loadBalancerArn = process.env.CBD_ALB_ARN; this.acmClient = new ACMClient({ region: this.region }); this.elbClient = new ElasticLoadBalancingV2Client({ region: this.region }); this.lambdaClient = new LambdaClient({ region: this.region }); this.eventBridgeClient = new EventBridgeClient({ region: this.region }); } /** * šŸŽÆ Main automation setup - Run this once to set up everything */ async setupFullAutomation() { console.log('šŸš€ Setting up CBD SSL Cloud Automation...'); try { // Step 1: Request SSL certificate via AWS Certificate Manager const certificateArn = await this.requestCertificate(); // Step 2: Set up automatic certificate monitoring await this.setupCertificateMonitoring(certificateArn); // Step 3: Configure Load Balancer HTTPS listener await this.configureHTTPSListener(certificateArn); // Step 4: Set up auto-renewal Lambda function await this.setupAutoRenewalFunction(); // Step 5: Create EventBridge rule for periodic checks await this.setupPeriodicChecks(); console.log('šŸŽ‰ CBD SSL Cloud Automation setup complete!'); console.log('āœ… Fully automated SSL certificate management active'); console.log('āœ… Zero maintenance required'); return { success: true, certificateArn, automation: 'fully-configured', maintenance: 'zero-touch' }; } catch (error) { console.error('āŒ SSL automation setup failed:', error.message); throw error; } } /** * šŸ“œ Request SSL certificate via AWS Certificate Manager */ async requestCertificate() { console.log('šŸ“œ Requesting SSL certificate via AWS Certificate Manager...'); // Check if certificate already exists const existingCert = await this.findExistingCertificate(); if (existingCert) { console.log('āœ… SSL certificate already exists:', existingCert.CertificateArn); return existingCert.CertificateArn; } const command = new RequestCertificateCommand({ DomainName: this.domain, SubjectAlternativeNames: [`*.${this.domain}`], // Include wildcard ValidationMethod: 'DNS', // DNS validation is automatic KeyAlgorithm: 'RSA_2048', Options: { CertificateTransparencyLoggingPreference: 'ENABLED' }, Tags: [ { Key: 'Service', Value: 'CBD-Universal-Database' }, { Key: 'Environment', Value: 'Production' }, { Key: 'AutoManaged', Value: 'true' }, { Key: 'Project', Value: 'CODAI-Ecosystem' } ] }); const response = await this.acmClient.send(command); console.log('āœ… SSL certificate requested:', response.CertificateArn); // Wait for DNS validation records await this.waitForValidationRecords(response.CertificateArn); return response.CertificateArn; } /** * šŸ” Find existing certificate for the domain */ async findExistingCertificate() { const command = new ListCertificatesCommand({ CertificateStatuses: ['ISSUED', 'PENDING_VALIDATION'] }); const response = await this.acmClient.send(command); return response.CertificateSummaryList?.find(cert => cert.DomainName === this.domain || cert.SubjectAlternativeNameSummaries?.includes(this.domain) ); } /** * ā³ Wait for DNS validation records and display them */ async waitForValidationRecords(certificateArn) { console.log('ā³ Waiting for DNS validation records...'); let attempts = 0; const maxAttempts = 30; while (attempts < maxAttempts) { const command = new DescribeCertificateCommand({ CertificateArn: certificateArn }); const response = await this.acmClient.send(command); const cert = response.Certificate; if (cert.DomainValidationOptions && cert.DomainValidationOptions.length > 0) { console.log('šŸ“‹ DNS Validation Records Required:'); cert.DomainValidationOptions.forEach((option, index) => { if (option.ResourceRecord) { console.log(`\n🌐 Record ${index + 1}:`); console.log(` Domain: ${option.DomainName}`); console.log(` Type: ${option.ResourceRecord.Type}`); console.log(` Name: ${option.ResourceRecord.Name}`); console.log(` Value: ${option.ResourceRecord.Value}`); } }); console.log('\nšŸ’” Add these DNS records to your domain provider'); console.log('ā³ Certificate will be issued automatically after DNS propagation'); break; } attempts++; await new Promise(resolve => setTimeout(resolve, 2000)); } } /** * šŸ”§ Configure HTTPS listener on Application Load Balancer */ async configureHTTPSListener(certificateArn) { console.log('šŸ”§ Configuring HTTPS listener on Load Balancer...'); if (!this.loadBalancerArn) { console.log('āš ļø Load Balancer ARN not provided, skipping HTTPS configuration'); return; } // Get existing listeners const listenersCommand = new DescribeListenersCommand({ LoadBalancerArn: this.loadBalancerArn }); const listenersResponse = await this.elbClient.send(listenersCommand); const httpsListener = listenersResponse.Listeners?.find(l => l.Port === 443); if (httpsListener) { // Update existing HTTPS listener const updateCommand = new ModifyListenerCommand({ ListenerArn: httpsListener.ListenerArn, Certificates: [{ CertificateArn: certificateArn }] }); await this.elbClient.send(updateCommand); console.log('āœ… HTTPS listener updated with new certificate'); } else { // Create new HTTPS listener const createCommand = new CreateListenerCommand({ LoadBalancerArn: this.loadBalancerArn, Protocol: 'HTTPS', Port: 443, Certificates: [{ CertificateArn: certificateArn }], DefaultActions: [{ Type: 'forward', TargetGroupArn: process.env.CBD_TARGET_GROUP_ARN }] }); await this.elbClient.send(createCommand); console.log('āœ… HTTPS listener created with SSL certificate'); } } /** * šŸ¤– Set up Lambda function for automatic certificate monitoring */ async setupAutoRenewalFunction() { console.log('šŸ¤– Setting up auto-renewal Lambda function...'); const functionCode = this.generateLambdaCode(); try { const createCommand = new CreateFunctionCommand({ FunctionName: 'cbd-ssl-auto-renewal', Runtime: 'nodejs18.x', Role: process.env.LAMBDA_EXECUTION_ROLE_ARN, Handler: 'index.handler', Code: { ZipFile: Buffer.from(functionCode) }, Description: 'CBD SSL Certificate Auto-Renewal and Monitoring', Timeout: 300, Environment: { Variables: { DOMAIN: this.domain, LOAD_BALANCER_ARN: this.loadBalancerArn || '', TARGET_GROUP_ARN: process.env.CBD_TARGET_GROUP_ARN || '' } }, Tags: { Service: 'CBD-Universal-Database', Purpose: 'SSL-Automation' } }); await this.lambdaClient.send(createCommand); console.log('āœ… Auto-renewal Lambda function created'); } catch (error) { if (error.name === 'ResourceConflictException') { // Function exists, update it const updateCommand = new UpdateFunctionCodeCommand({ FunctionName: 'cbd-ssl-auto-renewal', ZipFile: Buffer.from(functionCode) }); await this.lambdaClient.send(updateCommand); console.log('āœ… Auto-renewal Lambda function updated'); } else { throw error; } } } /** * šŸ“… Set up EventBridge rule for periodic certificate checks */ async setupPeriodicChecks() { console.log('šŸ“… Setting up periodic certificate checks...'); // Create EventBridge rule (runs every 12 hours) const ruleCommand = new PutRuleCommand({ Name: 'cbd-ssl-certificate-check', Description: 'Periodic check for CBD SSL certificate status and renewal', ScheduleExpression: 'rate(12 hours)', // Every 12 hours State: 'ENABLED' }); await this.eventBridgeClient.send(ruleCommand); // Add Lambda target to the rule const targetCommand = new PutTargetsCommand({ Rule: 'cbd-ssl-certificate-check', Targets: [{ Id: '1', Arn: `arn:aws:lambda:${this.region}:${process.env.AWS_ACCOUNT_ID}:function:cbd-ssl-auto-renewal` }] }); await this.eventBridgeClient.send(targetCommand); console.log('āœ… Periodic certificate checks scheduled (every 12 hours)'); } /** * 🧬 Generate Lambda function code for certificate monitoring */ generateLambdaCode() { return ` const { ACMClient, DescribeCertificateCommand, ListCertificatesCommand } = require('@aws-sdk/client-acm'); const { ELBv2Client, ModifyListenerCommand, DescribeListenersCommand } = require('@aws-sdk/client-elbv2'); exports.handler = async (event) => { console.log('šŸ” CBD SSL Certificate Auto-Monitor started...'); const domain = process.env.DOMAIN; const loadBalancerArn = process.env.LOAD_BALANCER_ARN; const acmClient = new ACMClient(); const elbClient = new ELBv2Client(); try { // Find certificate for domain const listCommand = new ListCertificatesCommand({ CertificateStatuses: ['ISSUED'] }); const listResponse = await acmClient.send(listCommand); const certificate = listResponse.CertificateSummaryList?.find(cert => cert.DomainName === domain ); if (!certificate) { console.log('āš ļø No certificate found for domain:', domain); return { statusCode: 404, body: 'Certificate not found' }; } // Check certificate details const describeCommand = new DescribeCertificateCommand({ CertificateArn: certificate.CertificateArn }); const certResponse = await acmClient.send(describeCommand); const cert = certResponse.Certificate; console.log('šŸ“œ Certificate Status:', cert.Status); console.log('šŸ“… Expires:', cert.NotAfter); // Check if certificate expires in next 30 days const expiryDate = new Date(cert.NotAfter); const thirtyDaysFromNow = new Date(); thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30); if (expiryDate < thirtyDaysFromNow) { console.log('āš ļø Certificate expires soon, but ACM auto-renews'); // ACM automatically renews certificates, so we just log this } // Verify Load Balancer is using the certificate if (loadBalancerArn) { const listenersCommand = new DescribeListenersCommand({ LoadBalancerArn: loadBalancerArn }); const listenersResponse = await elbClient.send(listenersCommand); const httpsListener = listenersResponse.Listeners?.find(l => l.Port === 443); if (httpsListener) { const currentCertArn = httpsListener.Certificates?.[0]?.CertificateArn; console.log('šŸ”§ Load Balancer Certificate:', currentCertArn); console.log('āœ… SSL configuration verified'); } } return { statusCode: 200, body: JSON.stringify({ status: 'healthy', certificate: certificate.CertificateArn, domain: domain, expires: cert.NotAfter, autoRenewal: 'enabled' }) }; } catch (error) { console.error('āŒ SSL monitoring error:', error.message); throw error; } }; `; } /** * šŸ“Š Get current SSL automation status */ async getAutomationStatus() { console.log('šŸ“Š Checking SSL automation status...'); try { const certificate = await this.findExistingCertificate(); return { certificateExists: !!certificate, certificateArn: certificate?.CertificateArn, domain: this.domain, automationActive: true, renewalSchedule: 'every-12-hours', maintenance: 'zero-touch', provider: 'AWS-Certificate-Manager' }; } catch (error) { console.error('āŒ Status check failed:', error.message); return { error: error.message }; } } } // Usage example if (require.main === module) { const automation = new CBDSSLCloudAutomation(); const command = process.argv[2]; switch (command) { case 'setup': automation.setupFullAutomation() .then(result => console.log('šŸŽ‰ Setup complete:', result)) .catch(error => console.error('āŒ Setup failed:', error)); break; case 'status': automation.getAutomationStatus() .then(status => console.log('šŸ“Š Status:', status)) .catch(error => console.error('āŒ Status check failed:', error)); break; default: console.log('šŸ”’ CBD SSL Cloud Automation'); console.log('Usage:'); console.log(' node cbd-ssl-cloud-automation.js setup - Set up full automation'); console.log(' node cbd-ssl-cloud-automation.js status - Check automation status'); process.exit(1); } } module.exports = CBDSSLCloudAutomation;