This repository contains AWS CloudFormation templates for deploying a complete AWS infrastructure including VPC, EKS cluster, Bastion host, S3 buckets, CloudFront CDN, and Route53 DNS configuration.
The infrastructure consists of the following components:
- VPC: Multi-AZ VPC with public and private subnets across 3 availability zones
- EKS: Kubernetes cluster with managed node groups (ARM64 Graviton instances)
- Bastion: Jump host with SSM Session Manager support
- S3: Static content and user content buckets with encryption
- CloudFront: CDN distribution for static content delivery
- Route53: DNS configuration with hosted zone and records
- AWS CLI configured with appropriate credentials
- Sufficient AWS permissions to create all resources
- (Optional) A registered domain name for Route53
- (Optional) ACM certificate in us-east-1 for CloudFront custom domain
.
├── vpc.yaml # VPC CloudFormation template
├── eks.yaml # EKS CloudFormation template
├── bastion.yaml # Bastion host template
├── s3.yaml # S3 buckets template
├── cloudfront.yaml # CloudFront distribution template
├── route53.yaml # Route53 DNS template
├── parameters/
│ ├── dev/ # Dev environment parameters
│ │ ├── vpc-params.json
│ │ ├── eks-params.json
│ │ ├── bastion-params.json
│ │ ├── s3-params.json
│ │ ├── cloudfront-params.json
│ │ └── route53-params.json
│ └── prod/ # Prod environment parameters
│ ├── vpc-params.json
│ ├── eks-params.json
│ ├── bastion-params.json
│ ├── s3-params.json
│ ├── cloudfront-params.json
│ └── route53-params.json
└── README.md
The stacks must be deployed in the following order due to dependencies:
- VPC (no dependencies)
- EKS (depends on VPC)
- Bastion (depends on VPC)
- S3 (no dependencies)
- CloudFront (depends on S3)
- Route53 (depends on CloudFront and Bastion)
aws cloudformation create-stack \
--stack-name myproject-dev-vpc \
--template-body file://vpc.yaml \
--parameters file://parameters/dev/vpc-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region us-west-2
# Wait for stack creation to complete
aws cloudformation wait stack-create-complete \
--stack-name myproject-dev-vpc \
--region us-west-2aws cloudformation create-stack \
--stack-name myproject-dev-eks \
--template-body file://eks.yaml \
--parameters file://parameters/dev/eks-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region us-west-2
# Wait for stack creation (this takes 15-20 minutes)
aws cloudformation wait stack-create-complete \
--stack-name myproject-dev-eks \
--region us-west-2aws cloudformation create-stack \
--stack-name myproject-dev-bastion \
--template-body file://bastion.yaml \
--parameters file://parameters/dev/bastion-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region us-west-2
# Wait for stack creation
aws cloudformation wait stack-create-complete \
--stack-name myproject-dev-bastion \
--region us-west-2aws cloudformation create-stack \
--stack-name myproject-dev-s3 \
--template-body file://s3.yaml \
--parameters file://parameters/dev/s3-params.json \
--region us-west-2
# Wait for stack creation
aws cloudformation wait stack-create-complete \
--stack-name myproject-dev-s3 \
--region us-west-2aws cloudformation create-stack \
--stack-name myproject-dev-cloudfront \
--template-body file://cloudfront.yaml \
--parameters file://parameters/dev/cloudfront-params.json \
--region us-west-2
# Wait for stack creation (this takes 10-15 minutes)
aws cloudformation wait stack-create-complete \
--stack-name myproject-dev-cloudfront \
--region us-west-2Before deploying Route53, update the domain name in parameters/dev/route53-params.json if needed.
aws cloudformation create-stack \
--stack-name myproject-dev-route53 \
--template-body file://route53.yaml \
--parameters file://parameters/dev/route53-params.json \
--region us-west-2
# Wait for stack creation
aws cloudformation wait stack-create-complete \
--stack-name myproject-dev-route53 \
--region us-west-2For production, use the same deployment order but replace dev with prod in the stack names and parameter files:
# Example for production VPC
aws cloudformation create-stack \
--stack-name myproject-prod-vpc \
--template-body file://vpc.yaml \
--parameters file://parameters/prod/vpc-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region us-west-2You can create a deployment script to automate the process:
#!/bin/bash
ENV=$1 # dev or prod
REGION="us-west-2"
PROJECT="myproject"
if [ -z "$ENV" ]; then
echo "Usage: ./deploy.sh <dev|prod>"
exit 1
fi
echo "Deploying $ENV environment..."
# Deploy VPC
echo "1. Deploying VPC..."
aws cloudformation create-stack \
--stack-name ${PROJECT}-${ENV}-vpc \
--template-body file://vpc.yaml \
--parameters file://parameters/${ENV}/vpc-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region $REGION
aws cloudformation wait stack-create-complete \
--stack-name ${PROJECT}-${ENV}-vpc \
--region $REGION
# Deploy EKS
echo "2. Deploying EKS (this takes 15-20 minutes)..."
aws cloudformation create-stack \
--stack-name ${PROJECT}-${ENV}-eks \
--template-body file://eks.yaml \
--parameters file://parameters/${ENV}/eks-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region $REGION
aws cloudformation wait stack-create-complete \
--stack-name ${PROJECT}-${ENV}-eks \
--region $REGION
# Deploy Bastion
echo "3. Deploying Bastion..."
aws cloudformation create-stack \
--stack-name ${PROJECT}-${ENV}-bastion \
--template-body file://bastion.yaml \
--parameters file://parameters/${ENV}/bastion-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region $REGION
aws cloudformation wait stack-create-complete \
--stack-name ${PROJECT}-${ENV}-bastion \
--region $REGION
# Deploy S3
echo "4. Deploying S3..."
aws cloudformation create-stack \
--stack-name ${PROJECT}-${ENV}-s3 \
--template-body file://s3.yaml \
--parameters file://parameters/${ENV}/s3-params.json \
--region $REGION
aws cloudformation wait stack-create-complete \
--stack-name ${PROJECT}-${ENV}-s3 \
--region $REGION
# Deploy CloudFront
echo "5. Deploying CloudFront (this takes 10-15 minutes)..."
aws cloudformation create-stack \
--stack-name ${PROJECT}-${ENV}-cloudfront \
--template-body file://cloudfront.yaml \
--parameters file://parameters/${ENV}/cloudfront-params.json \
--region $REGION
aws cloudformation wait stack-create-complete \
--stack-name ${PROJECT}-${ENV}-cloudfront \
--region $REGION
# Deploy Route53
echo "6. Deploying Route53..."
aws cloudformation create-stack \
--stack-name ${PROJECT}-${ENV}-route53 \
--template-body file://route53.yaml \
--parameters file://parameters/${ENV}/route53-params.json \
--region $REGION
aws cloudformation wait stack-create-complete \
--stack-name ${PROJECT}-${ENV}-route53 \
--region $REGION
echo "Deployment complete!"Save this as deploy.sh and run:
chmod +x deploy.sh
./deploy.sh dev # or prodConfigure kubectl to access your EKS cluster:
aws eks update-kubeconfig \
--name dev-eks-cluster \
--region us-west-2Connect using SSM Session Manager (no SSH key required):
# Get instance ID
INSTANCE_ID=$(aws cloudformation describe-stacks \
--stack-name myproject-dev-bastion \
--query 'Stacks[0].Outputs[?OutputKey==`BastionInstanceId`].OutputValue' \
--output text \
--region us-west-2)
# Connect
aws ssm start-session --target $INSTANCE_ID --region us-west-2Or via SSH (if you configured a key pair):
BASTION_IP=$(aws cloudformation describe-stacks \
--stack-name myproject-dev-bastion \
--query 'Stacks[0].Outputs[?OutputKey==`BastionPublicIP`].OutputValue' \
--output text \
--region us-west-2)
ssh -i your-key.pem ec2-user@$BASTION_IPGet your CloudFront URL:
aws cloudformation describe-stacks \
--stack-name myproject-dev-cloudfront \
--query 'Stacks[0].Outputs[?OutputKey==`DistributionDomainName`].OutputValue' \
--output text \
--region us-west-2If you created a new hosted zone, get the name servers:
aws cloudformation describe-stacks \
--stack-name myproject-dev-route53 \
--query 'Stacks[0].Outputs[?OutputKey==`HostedZoneNameServers`].OutputValue' \
--output text \
--region us-west-2Update your domain registrar to use these name servers.
To update an existing stack:
aws cloudformation update-stack \
--stack-name myproject-dev-vpc \
--template-body file://vpc.yaml \
--parameters file://parameters/dev/vpc-params.json \
--capabilities CAPABILITY_NAMED_IAM \
--region us-west-2Delete stacks in reverse order:
# Delete in reverse order
aws cloudformation delete-stack --stack-name myproject-dev-route53 --region us-west-2
aws cloudformation delete-stack --stack-name myproject-dev-cloudfront --region us-west-2
aws cloudformation delete-stack --stack-name myproject-dev-s3 --region us-west-2
aws cloudformation delete-stack --stack-name myproject-dev-bastion --region us-west-2
aws cloudformation delete-stack --stack-name myproject-dev-eks --region us-west-2
aws cloudformation delete-stack --stack-name myproject-dev-vpc --region us-west-2Note: Before deleting the S3 stack, ensure buckets are empty:
# Empty static content bucket
aws s3 rm s3://myproject-dev-static-content --recursive
# Empty user content bucket
aws s3 rm s3://myproject-dev-user-content --recursive| Feature | Dev | Prod |
|---|---|---|
| VPC CIDR | 10.0.0.0/16 | 10.1.0.0/16 |
| NAT Gateways | 1 (single AZ) | 3 (multi-AZ) |
| EKS API Endpoint | Public | Private |
| Node Capacity | SPOT instances | ON_DEMAND instances |
| Instance Types | t4g.medium | t4g.large |
| Node Scaling | 1-3 nodes | 3-10 nodes |
| S3 Versioning | Disabled | Enabled |
| S3 Lifecycle Rules | Disabled | Enabled (Glacier at 180d) |
| Log Retention | 7 days | 30 days |
Update the ProjectName parameter in all parameter files:
# Find and replace in all parameter files
find parameters -name "*.json" -exec sed -i '' 's/"myproject"/"your-project-name"/g' {} \;Update the region in all deployment commands and the RegionMap in bastion.yaml if using a different region.
- Request an ACM certificate in us-east-1 for your domain
- Update
cloudfront-params.json:{ "ParameterKey": "CustomDomainName", "ParameterValue": "cdn.yourdomain.com" }, { "ParameterKey": "ACMCertificateArn", "ParameterValue": "arn:aws:acm:us-east-1:123456789012:certificate/xxx" }
Update bastion-params.json:
{
"ParameterKey": "KeyName",
"ParameterValue": "your-ec2-keypair-name"
}- VPC: ~$32 (1 NAT Gateway)
- EKS: ~$73 (control plane) + ~$15 (2 t4g.medium SPOT nodes)
- Bastion: ~$3 (t4g.micro)
- S3: Variable (storage + requests)
- CloudFront: Variable (data transfer)
- Route53: ~$0.50 per hosted zone + query charges
- Total: ~$125/month + variable costs
- VPC: ~$96 (3 NAT Gateways)
- EKS: ~$73 (control plane) + ~$110 (3 t4g.large ON_DEMAND nodes)
- Bastion: ~$3 (t4g.micro)
- S3: Variable (storage + requests + lifecycle transitions)
- CloudFront: Variable (data transfer)
- Route53: ~$0.50 per hosted zone + query charges
- Total: ~$285/month + variable costs
- Restrict SSH Access: Update
AllowedSSHCIDRin bastion parameters to limit SSH access - Use Private EKS Endpoint: Enable in production (already configured)
- Enable MFA: For AWS accounts with CloudFormation permissions
- Rotate Credentials: Regularly rotate IAM credentials and SSH keys
- Review IAM Policies: Audit IAM roles for least privilege
- Enable CloudTrail: For audit logging of all API calls
- Enable GuardDuty: For threat detection
- Enable Config: For compliance monitoring
Check stack events:
aws cloudformation describe-stack-events \
--stack-name myproject-dev-vpc \
--region us-west-2Check node group status:
aws eks describe-nodegroup \
--cluster-name dev-eks-cluster \
--nodegroup-name dev-eks-cluster-node-group \
--region us-west-2Verify S3 bucket policy allows CloudFront OAI access.
Ensure name servers at domain registrar match Route53 hosted zone name servers.
This CloudFormation port maintains functional parity with the original Terragrunt/Terraform implementation. Key differences:
- State Management: CloudFormation manages state automatically (no S3 backend needed)
- Dependencies: Uses stack exports/imports instead of Terragrunt dependencies
- Syntax: YAML-based instead of HCL
- Modules: Templates are standalone (no module reuse)
To migrate existing infrastructure:
- Export Terraform state
- Import resources into CloudFormation (where supported)
- Or deploy new CloudFormation stacks alongside Terraform, migrate applications, then destroy Terraform resources
For issues or questions:
- AWS CloudFormation Docs: https://docs.aws.amazon.com/cloudformation/
- AWS CLI Docs: https://docs.aws.amazon.com/cli/
- EKS User Guide: https://docs.aws.amazon.com/eks/
This infrastructure code is provided as-is for educational and production use.