Initial commit: AWS CDK stack and Priority Listing

This commit is contained in:
vickytechkey 2026-08-06 09:21:36 +05:30
commit 5cef51b0f6
13 changed files with 6320 additions and 0 deletions

15
.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
# Node dependencies
node_modules/
# CDK build outputs
aws_cdk/cdk.out/
aws_cdk/.jsii
aws_cdk/tsconfig.tsbuildinfo
aws_cdk/**/*.js
aws_cdk/**/*.d.ts
# Environments & IDEs
.env
.DS_Store
.idea/
.vscode/

8
aws_cdk/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
*.js
!jest.config.js
*.d.ts
node_modules
# CDK asset staging directory
.cdk.staging
cdk.out

6
aws_cdk/.npmignore Normal file
View file

@ -0,0 +1,6 @@
*.ts
!*.d.ts
# CDK asset staging directory
.cdk.staging
cdk.out

14
aws_cdk/README.md Normal file
View file

@ -0,0 +1,14 @@
# Welcome to your CDK TypeScript project
This is a blank project for CDK development with TypeScript.
The `cdk.json` file tells the CDK Toolkit how to execute your app.
## Useful commands
* `npm run build` type-check the project
* `npm run watch` watch for changes and type-check
* `npm run test` perform the jest unit tests
* `npx cdk deploy` deploy this stack to your default AWS account/region
* `npx cdk diff` compare deployed stack with current state
* `npx cdk synth` emits the synthesized CloudFormation template

20
aws_cdk/bin/aws_cdk.ts Normal file
View file

@ -0,0 +1,20 @@
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib/core';
import { AwsCdkStack } from '../lib/aws_cdk-stack';
const app = new cdk.App();
new AwsCdkStack(app, 'AwsCdkStack', {
/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */
/* Uncomment the next line to specialize this stack for the AWS Account
* and Region that are implied by the current CLI configuration. */
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});

110
aws_cdk/cdk.json Normal file
View file

@ -0,0 +1,110 @@
{
"app": "npx tsc && npx tsx bin/aws_cdk.ts",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"**/*.d.ts",
"**/*.js",
"tsconfig.json",
"package*.json",
"yarn.lock",
"node_modules",
"test"
]
},
"context": {
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/aws-batch:defaultToAL2023": true,
"@aws-cdk/aws-cloudfront:defaultFunctionRuntimeV2_0": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
"@aws-cdk/aws-dynamodb:retainTableReplica": true,
"@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true,
"@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-eks:defaultToAL2023": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-eks:useNativeOidcProvider": true,
"@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
"@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": true,
"@aws-cdk/aws-elasticloadbalancingv2:usePostQuantumTlsPolicy": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-events:requireEventBusPolicySid": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false,
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/aws-lambda:useCdkManagedLogGroup": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-route53-patterns:useDistribution": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
"@aws-cdk/aws-s3:publicAccessBlockedByDefault": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-s3:setUniqueReplicationRoleName": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
"@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true,
"@aws-cdk/core:annotationsInValidationReport": true,
"@aws-cdk/core:aspectPrioritiesMutating": true,
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:defaultCrossStackReferences": "weak",
"@aws-cdk/core:enableAdditionalMetadataCollection": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/core:explicitStackTags": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk/core:validateAgainstDefaultRules": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true
}
}

9
aws_cdk/jest.config.js Normal file
View file

@ -0,0 +1,9 @@
module.exports = {
testEnvironment: 'node',
roots: ['<rootDir>/test'],
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.tsx?$': ['@swc/jest']
},
setupFilesAfterEnv: ['aws-cdk-lib/testhelpers/jest-autoclean'],
};

View file

@ -0,0 +1,87 @@
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
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, 'MailServerSG', {
vpc,
description: 'Security Group for self-hosted mail server',
allowAllOutbound: true,
});
// Allow SSH
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(22), 'Allow SSH access');
// Mail Protocols (SMTP, SMTPS, Submission)
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(25), 'Allow SMTP');
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(465), 'Allow SMTPS');
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(587), 'Allow SMTP Submission');
// Mail Protocols (IMAP, IMAPS)
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(143), 'Allow IMAP');
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(993), 'Allow IMAPS');
// Web Traffic (HTTP, HTTPS for Admin UI & Webmail / SSL certificates)
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(80), 'Allow HTTP');
securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'Allow HTTPS');
// 3. Define the EC2 Instance (t3.medium recommended for running ClamAV/Rspamd)
const instance = new ec2.Instance(this, 'MailServerInstance', {
vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC },
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
machineImage: ec2.MachineImage.lookup({
name: 'ubuntu/images/hvm-ssd/ubuntu-noble-24.04-amd64-server-*',
owners: ['099720109477'], // Canonical owner ID
}),
securityGroup,
blockDevices: [
{
deviceName: '/dev/sda1',
volume: ec2.BlockDeviceVolume.ebs(60, { // 60GB Root Volume
volumeType: ec2.EbsDeviceVolumeType.GP3,
}),
},
],
});
// 4. Install Docker and Docker Compose via User Data
instance.addUserData(
'apt-get update -y',
'apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release',
'mkdir -m 0755 -p /etc/apt/keyrings',
'curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg',
'echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null',
'apt-get update -y',
'apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin',
'systemctl enable docker',
'systemctl start docker'
);
// 5. Provision Elastic IP and Associate with EC2
const eip = new ec2.CfnEIP(this, 'MailServerEIP', {
domain: 'vpc',
});
new ec2.CfnEIPAssociation(this, 'MailServerEIPAssociation', {
eip: eip.ref,
instanceId: instance.instanceId,
});
// Outputs
new cdk.CfnOutput(this, 'MailServerPublicIP', {
value: eip.ref,
description: 'The Elastic IP address of your Mail Server',
});
}
}

5892
aws_cdk/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

24
aws_cdk/package.json Normal file
View file

@ -0,0 +1,24 @@
{
"name": "aws_cdk",
"version": "0.1.0",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
"cdk": "cdk"
},
"devDependencies": {
"@swc/core": "^1.15.0",
"@swc/jest": "^0.2.39",
"@types/jest": "^30",
"@types/node": "^24.10.1",
"jest": "^30",
"aws-cdk": "2.1135.0",
"tsx": "^4.23.0",
"typescript": "~7.0.2"
},
"dependencies": {
"aws-cdk-lib": "^2.263.0",
"constructs": "^10.5.0"
}
}

View file

@ -0,0 +1,17 @@
// import * as cdk from 'aws-cdk-lib/core';
// import { Template } from 'aws-cdk-lib/assertions';
// import * as AwsCdk from '../lib/aws_cdk-stack';
// example test. To run these tests, uncomment this file along with the
// example resource in lib/aws_cdk-stack.ts
test('SQS Queue Created', () => {
// const app = new cdk.App();
// // WHEN
// const stack = new AwsCdk.AwsCdkStack(app, 'MyTestStack');
// // THEN
// const template = Template.fromStack(stack);
// template.hasResourceProperties('AWS::SQS::Queue', {
// VisibilityTimeout: 300
// });
});

38
aws_cdk/tsconfig.json Normal file
View file

@ -0,0 +1,38 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": [
"es2022"
],
"declaration": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"inlineSourceMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"skipLibCheck": true,
"typeRoots": [
"./node_modules/@types"
],
"noEmit": true,
"isolatedModules": true,
"types": [
"jest",
"node"
]
},
"exclude": [
"node_modules",
"cdk.out"
]
}

80
priority_listing.md Normal file
View file

@ -0,0 +1,80 @@
# Priority Listing: Self-Hosted Email Service on AWS EC2
This document outlines the step-by-step priority list to deploy and verify a self-hosted, Docker-based email server on AWS EC2.
---
## Phase 1: AWS Configuration & Requests (Immediate Priority)
Before writing any configuration files or launching servers, you must set up the AWS infrastructure and submit request forms to AWS Support. **AWS manually reviews these requests, which can take 2448 hours.**
### 1. Provision AWS Resources
- **EC2 Instance**: Launch a `t3.medium` (or larger) instance running Ubuntu 24.04 LTS.
- **Elastic IP**: Allocate a static Elastic IP and associate it with the EC2 instance. (Note the IP address).
- **Security Group**: Configure the security group to allow inbound traffic on:
* Port `25` (SMTP)
* Port `143` / `993` (IMAP / IMAPS)
* Port `587` / `465` (Submission / SMTPS)
* Port `80` / `443` (HTTP / HTTPS for Webmail & SSL certificates)
### 2. Request Port 25 Unblocking & Reverse DNS (PTR)
You cannot send emails from EC2 without removing the default Port 25 limit.
- **Action**: Submit the [Request to Remove Sending Limitations](https://aws.amazon.com/premiumsupport/knowledge-center/ec2-port-25-throttle/) form in the AWS Support Center.
- **Provide the following details**:
* Your Elastic IP address.
* Your email domain (e.g., `yourdomain.com`).
* The Reverse DNS (PTR) record you want associated with the IP (e.g., `mail.yourdomain.com`).
* A clear explanation of your use case (e.g., "Hosting our company email service for internal staff communications").
---
## Phase 2: Development & Infrastructure Setup
Once AWS approves your request, proceed with the software installation.
### 1. Host Setup
- Install Docker and Docker Compose on the EC2 instance.
- Set up a swap file if memory usage is tight (especially if using Mailcow).
### 2. Mail Server Installation (Example: Mailcow)
- Clone the repository: `git clone https://github.com/mailcow/mailcow-dockerized`
- Generate configuration: `./generate_config.sh`
* Enter your mail subdomain (e.g., `mail.yourdomain.com`).
- Adjust configurations in `mailcow.conf` (e.g., timezone, HTTP/S ports).
- Spin up the containers: `docker compose up -d`
### 3. DNS Configuration
Add the following records at your Domain Registrar or DNS manager (Route 53, Cloudflare, etc.):
| Record Type | Host / Name | Value | Purpose |
| :--- | :--- | :--- | :--- |
| **A** | `mail` | `<Your EC2 Elastic IP>` | Points to your mail server |
| **MX** | `@` (Root) | `10 mail.yourdomain.com.` | Directs incoming mail to the mail server |
| **TXT** | `@` | `v=spf1 ip4:<Your Elastic IP> -all` | SPF: Authorizes EC2 to send mail |
| **TXT** | `dkim._domainkey` | *Generated by Mailcow UI* | DKIM: Cryptographic mail signing |
| **TXT** | `_dmarc` | `v=DMARC1; p=quarantine; pct=100;` | DMARC: Action policy for failures |
---
## Phase 3: Testing & Verification Plan
Run these verification checks before onboarding your organization.
### 1. Inbound Connection Port Check
Verify that the firewall/security groups are open to the public internet:
```bash
# From a remote machine, test SMTP
nc -zv <Your Elastic IP> 25
# Test IMAPS
nc -zv <Your Elastic IP> 993
```
### 2. Inbound & Outbound Email Delivery
* **Outbound Test**: Create an inbox in your new mail server and send an email to an external address (e.g., a personal Gmail or Outlook account). Verify it arrives and does not go to spam.
* **Inbound Test**: Reply to that email from Gmail/Outlook and verify it is received on your self-hosted server.
### 3. Comprehensive Deliverability & Trust Test
* Use a service like [Mail-Tester](https://www.mail-tester.com/) or [MxToolbox](https://mxtoolbox.com/).
* Send a test email from your mail server to the address provided by Mail-Tester.
* **Target Score**: 10/10. Ensure SPF, DKIM, DMARC, and Reverse DNS (PTR) alignment are all marked green.