cdkinfracode/aws_cdk/lib/aws_cdk-stack.ts

190 lines
6.9 KiB
TypeScript

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as dlm from 'aws-cdk-lib/aws-dlm';
export class AwsCdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 1. Look up the existing Default VPC (Free, avoids NAT Gateway charges)
const vpc = ec2.Vpc.fromLookup(this, 'DefaultVpc', {
isDefault: true,
});
// 2. Create a Security Group for the Mail Server
const securityGroup = new ec2.SecurityGroup(this, 'internalsSG', {
vpc,
description: 'Security Group for self-hosted mail server',
allowAllOutbound: true,
});
// Allow SSH
securityGroup.addIngressRule(ec2.Peer.ipv4('16.113.57.0/24'), ec2.Port.tcp(22), 'Allow SSH access');
// Web Traffic (HTTP, HTTPS for Admin UI & Webmail / SSL certificates)
securityGroup.addIngressRule(ec2.Peer.ipv4('16.113.57.0/24'), ec2.Port.tcp(80), 'Allow HTTP');
securityGroup.addIngressRule(ec2.Peer.ipv4('16.113.57.0/24'), ec2.Port.tcp(443), 'Allow HTTPS');
// WireGuard VPN
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.udp(5010), 'Allow WireGuard VPN');
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(51821), 'Allow WireGuard Web UI');
// Woodpecker CI
securityGroup.addIngressRule(ec2.Peer.ipv4('16.113.57.0/24'), ec2.Port.tcp(8000), 'Allow Woodpecker Web UI');
// Django App Backends (Prod and Beta)
securityGroup.addIngressRule(ec2.Peer.ipv4('16.113.57.0/24'), ec2.Port.tcp(8080), 'Allow Django Beta Backend');
securityGroup.addIngressRule(ec2.Peer.ipv4('16.113.57.0/24'), ec2.Port.tcp(8090), 'Allow Django Production Backend');
// Create IAM Role for EC2 Instance (to allow CloudWatch Agent to write logs & metrics)
const role = new iam.Role(this, 'internalsRole', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchAgentServerPolicy'),
],
});
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'));
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly'));
// 3. Define the EC2 Instance (t4g.medium)
const instance = new ec2.Instance(this, 'internalsInstance', {
vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.MEDIUM),
machineImage: ec2.MachineImage.fromSsmParameter(
'/aws/service/canonical/ubuntu/server/24.04/stable/current/arm64/hvm/ebs-gp3/ami-id'
),
securityGroup,
role,
keyName: 'vignesh_tipro_apsouth2',
detailedMonitoring: true,
blockDevices: [
{
deviceName: '/dev/sda1',
volume: ec2.BlockDeviceVolume.ebs(50, { // 50GB Root Volume
volumeType: ec2.EbsDeviceVolumeType.GP3,
}),
},
],
});
// 4. Structured User Data installation
instance.addUserData(
// Ensure folder structures exist
'mkdir -p /home/ubuntu/basic_requirements',
'mkdir -p /home/ubuntu/build_tools',
// 4.1 Write and run installation for basic requirements (Python 3, pip, venv, git, build-essential)
'cat <<\'EOF\' > /home/ubuntu/basic_requirements/install.sh',
'#!/bin/bash',
'set -e',
'apt-get update -y',
'apt-get install -y ca-certificates curl gnupg lsb-release wget python3 python3-pip python3-venv git build-essential',
'EOF',
'chmod +x /home/ubuntu/basic_requirements/install.sh',
'/home/ubuntu/basic_requirements/install.sh',
// 4.2 Setup permissions for all user folders
'chown -R ubuntu:ubuntu /home/ubuntu/basic_requirements',
'chown -R ubuntu:ubuntu /home/ubuntu/build_tools',
// 4.3 Install CloudWatch Agent (ARM64 package for Graviton instance)
'wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/arm64/latest/amazon-cloudwatch-agent.deb',
'dpkg -i -E ./amazon-cloudwatch-agent.deb',
'mkdir -p /opt/aws/amazon-cloudwatch-agent/etc',
'cat <<\'EOF\' > /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json',
'{',
' "agent": {',
' "metrics_collection_interval": 60,',
' "run_as_user": "root"',
' },',
' "metrics": {',
' "metrics_collected": {',
' "disk": {',
' "measurement": ["used_percent"],',
' "metrics_collection_interval": 60,',
' "resources": ["/"]',
' },',
' "mem": {',
' "measurement": ["mem_used_percent"],',
' "metrics_collection_interval": 60',
' }',
' }',
' }',
'}',
'EOF',
'/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json'
);
// 5. Associate your pre-created Elastic IP using its Allocation ID
new ec2.CfnEIPAssociation(this, 'internalsEIPAssociation', {
allocationId: 'eipalloc-0d1630fa0633874cb',
instanceId: instance.instanceId,
});
// 6. Automated Backup: Tag the EC2 instance and configure DLM Lifecycle Policy
cdk.Tags.of(instance).add('Backup', 'Daily');
// Create the IAM Role for DLM to manage snapshots
const dlmRole = new iam.Role(this, 'DLMLifecycleRole', {
assumedBy: new iam.ServicePrincipal('dlm.amazonaws.com'),
description: 'Role for DLM to manage EC2 daily snapshots',
});
dlmRole.addToPolicy(new iam.PolicyStatement({
actions: [
'ec2:CreateSnapshot',
'ec2:CreateSnapshots',
'ec2:DeleteSnapshot',
'ec2:DescribeInstances',
'ec2:DescribeVolumes',
'ec2:DescribeSnapshots',
'ec2:CreateTags',
],
resources: ['*'],
}));
// Create the DLM Lifecycle Policy (snapshots are stored automatically in S3)
new dlm.CfnLifecyclePolicy(this, 'DailySnapshotPolicy', {
description: 'Daily EC2 Instance Snapshot Policy',
executionRoleArn: dlmRole.roleArn,
state: 'ENABLED',
policyDetails: {
resourceTypes: ['INSTANCE'],
targetTags: [
{
key: 'Backup',
value: 'Daily',
},
],
schedules: [
{
name: 'DailySnapshotSchedule',
createRule: {
interval: 24,
intervalUnit: 'HOURS',
times: ['20:00'], // Runs daily at 20:00 UTC (1:30 AM IST)
},
retainRule: {
count: 7, // Keep the last 7 daily snapshots
},
copyTags: true,
},
],
},
});
// Outputs
new cdk.CfnOutput(this, 'internalsPublicIP', {
value: '16.113.57.127',
description: 'The Elastic IP address of your Mail Server',
});
}
}