@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
JavaScript
// 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;