AWS Deployment Guide
Complete guide for deploying the Todos application to AWS using Infrastructure as Code with AWS CDK.
ποΈ Infrastructure Overview
The infrastructure creates a completely private AWS environment with:
- Private VPC: No public subnets or internet gateways
- ECS Fargate: Serverless container hosting
- Amazon Keyspaces: Managed Cassandra database
- Security Groups: Restrictive network controls
- Zero public access: Application accessible only within your AWS account
π Security Architecture
βββββββββββββββββββββββββββββββββββββββββββ
β Your AWS Account β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Private VPC β β
β β β β
β β βββββββββββββββ βββββββββββββ β β
β β βPrivate Subnetβ βPrivate Subββ β
β β β β β ββ β
β β β βββββββββββ β β ββ β
β β β βECS Task β β β ββ β
β β β βNative β β β ββ β
β β β βImage β β β ββ β
β β β βββββββββββ β β ββ β
β β βββββββββββββββ ββββββββββββββ β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Amazon Keyspaces β β
β β (Managed Cassandra) β β
β βββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββ
No Public Internet Access
π Quick Deployment
Prerequisites
- AWS CLI configured with appropriate permissions
- Node.js 18+ for AWS CDK
- Java 17+ and Maven
- Docker for native image building
# Install AWS CDK
npm install -g aws-cdk
# Verify prerequisites
aws sts get-caller-identity
java --version
docker --version
Step-by-Step Deployment
1. Build Native Image
# From project root
./mvnw clean install
# This creates the native Docker image: todos-application:native
docker images | grep todos-application
2. Configure Environment
# Set your AWS account and region
export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
export CDK_DEFAULT_REGION=us-east-1 # or your preferred region
# Verify configuration
echo "Account: $CDK_DEFAULT_ACCOUNT"
echo "Region: $CDK_DEFAULT_REGION"
3. Bootstrap CDK (First Time Only)
cd infrastructure
cdk bootstrap
# This creates the CDK staging bucket and IAM roles
4. Deploy Infrastructure
# Deploy all stacks
cdk deploy --all
# Or deploy individually for debugging
cdk deploy TodosNetworkStack
cdk deploy TodosKeyspacesStack
cdk deploy TodosEcsStack
5. Verify Deployment
# Check stack status
cdk list
# View outputs
aws cloudformation describe-stacks \
--stack-name TodosKeyspacesStack \
--query 'Stacks[0].Outputs'
# Check ECS service
aws ecs describe-services \
--cluster todos-cluster \
--services todos-service
π Infrastructure Components
Network Stack (TodosNetworkStack
)
Creates the secure network foundation:
// VPC with private subnets only
Vpc.Builder.create(this, "TodosVpc")
.maxAzs(2)
.subnetConfiguration(List.of(
SubnetConfiguration.builder()
.name("TodosPrivateSubnet")
.subnetType(SubnetType.PRIVATE_ISOLATED) // No internet access
.cidrMask(24)
.build()
))
.build();
Security Features:
- β No public subnets
- β No internet gateway
- β No NAT gateway
- β Private DNS resolution only
Database Stack (TodosKeyspacesStack
)
Creates managed Cassandra database:
// Keyspace with tables matching domain model
CfnKeyspace keyspace = CfnKeyspace.Builder.create(this, "TodosKeyspace")
.keyspaceName("todos")
.build();
// Tables: checklist and todo
// Point-in-time recovery enabled
// No TTL (data persists)
Features:
- β Serverless scaling
- β Point-in-time recovery
- β Encryption at rest
- β AWS managed patches
Application Stack (TodosEcsStack
)
Deploys the native image container:
// Fargate service in private subnets
FargateService.Builder.create(this, "TodosService")
.cluster(cluster)
.taskDefinition(taskDefinition)
.assignPublicIp(false) // Private only
.securityGroups(List.of(securityGroup))
.build();
Configuration:
- β Native image deployment
- β Health checks enabled
- β CloudWatch logging
- β IAM least privilege
- β Environment variables (no secrets)
π§ Access Patterns
Since the application runs in private subnets, access requires:
Option 1: AWS Systems Manager Session Manager
# Find running task
TASK_ARN=$(aws ecs list-tasks \
--cluster todos-cluster \
--query 'taskArns[0]' \
--output text)
# Connect to container
aws ecs execute-command \
--cluster todos-cluster \
--task $TASK_ARN \
--container TodosContainer \
--interactive \
--command "/bin/sh"
# Test API from inside container
curl http://localhost:8181/actuator/health
Option 2: VPC Peering/VPN
# If you have VPC connectivity:
curl http://PRIVATE_IP:8181/
Option 3: Bastion Host (Not Recommended)
# Add a bastion host in public subnet (reduces security)
# SSH tunnel to access application
π Monitoring & Observability
CloudWatch Integration
The deployment automatically configures:
# View application logs
aws logs describe-log-groups \
--log-group-name-prefix "/ecs/todos"
# Tail logs in real-time
aws logs tail /ecs/todos-application --follow
# View metrics
aws cloudwatch get-metric-statistics \
--namespace AWS/ECS \
--metric-name CPUUtilization \
--dimensions Name=ServiceName,Value=todos-service \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-01T23:59:59Z \
--period 300 \
--statistics Average
Health Checks
# ECS health check endpoint
GET /actuator/health
# Response example:
{
"status": "UP",
"components": {
"cassandra": {
"status": "UP",
"details": {
"version": "4.0.0"
}
}
}
}
π° Cost Optimization
Resource Costs (us-east-1)
Service | Cost Model | Estimated Monthly |
---|---|---|
ECS Fargate | $0.04048/hour (0.25 vCPU, 512MB) | ~$30 |
Keyspaces | Pay-per-request | $0-50 (usage dependent) |
VPC | No cost (private only) | $0 |
CloudWatch Logs | $0.50/GB ingested | $1-5 |
Total | Β | $31-85/month |
Cost Reduction Strategies
# Scale service to zero when not needed
aws ecs update-service \
--cluster todos-cluster \
--service todos-service \
--desired-count 0
# Scale back up
aws ecs update-service \
--cluster todos-cluster \
--service todos-service \
--desired-count 1
# Delete log groups if not needed
aws logs delete-log-group \
--log-group-name /ecs/todos-application
π§Ή Cleanup
Complete Removal
cd infrastructure
# Destroy all infrastructure
cdk destroy --all
# Confirm stacks are deleted
aws cloudformation list-stacks \
--stack-status-filter DELETE_COMPLETE
Selective Cleanup
# Remove application only (keep database)
cdk destroy TodosEcsStack
# Remove database only
cdk destroy TodosKeyspacesStack
# Remove network (must be last)
cdk destroy TodosNetworkStack
π§ Troubleshooting
Common Issues
1. Task Not Starting
# Check ECS events
aws ecs describe-services \
--cluster todos-cluster \
--services todos-service \
--query 'services[0].events[0:5]'
# Check task definition
aws ecs describe-task-definition \
--task-definition todos-task
2. Database Connection Issues
# Verify Keyspaces endpoint
nslookup cassandra.us-east-1.amazonaws.com
# Check IAM permissions
aws iam get-role --role-name TodosTaskRole
3. Image Pull Issues
# Verify native image exists
docker images | grep todos-application:native
# Check ECR if using private registry
aws ecr describe-repositories
Debug Commands
# CDK debugging
cdk diff TodosEcsStack
cdk synth --all > cdk-output.yaml
# CloudFormation events
aws cloudformation describe-stack-events \
--stack-name TodosEcsStack \
--query 'StackEvents[0:10]'
# ECS task logs
aws logs get-log-events \
--log-group-name /ecs/todos-application \
--log-stream-name "ecs/TodosContainer/TASK-ID"
π Security Best Practices
Implemented Security Measures
- β Network Isolation: Private VPC with no internet access
- β Least Privilege IAM: Minimal required permissions
- β No Hardcoded Secrets: Environment-based configuration
- β Encryption: Data encrypted at rest and in transit
- β Security Groups: Restrictive network rules
- β Managed Services: AWS handles security patches
Additional Security Recommendations
# Enable VPC Flow Logs
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids $VPC_ID \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name VPCFlowLogs
# Enable AWS Config for compliance
aws configservice put-configuration-recorder \
--configuration-recorder name=default \
--recording-group allSupported=true
# Set up CloudTrail for audit logging
aws cloudtrail create-trail \
--name todos-audit-trail \
--s3-bucket-name your-audit-bucket
π GitHub Actions CI/CD Pipeline
The project includes automated deployment via GitHub Actions that triggers on pushes to the master branch.
Pipeline Overview
The CI/CD pipeline consists of two jobs:
- Build Job: Compiles, tests, and builds the native image
- Deploy Job: Deploys infrastructure to AWS using CDK
AWS OIDC Authentication Setup
To enable secure deployment without long-term credentials, set up AWS OIDC:
1. Create OIDC Identity Provider
# Create OIDC provider for GitHub Actions
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1 \
--client-id-list sts.amazonaws.com
2. Create IAM Role for GitHub Actions
# Create trust policy for GitHub Actions
cat > github-actions-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:YOUR_USERNAME/todos:ref:refs/heads/master"
}
}
}
]
}
EOF
# Create the IAM role
aws iam create-role \
--role-name GitHubActionsTodosDeployment \
--assume-role-policy-document file://github-actions-trust-policy.json
3. Attach Required Permissions
# Attach necessary policies for CDK deployment
aws iam attach-role-policy \
--role-name GitHubActionsTodosDeployment \
--policy-arn arn:aws:iam::aws:policy/PowerUserAccess
# Note: For production, use more restrictive permissions
GitHub Environment Configuration
Configure the following as GitHub repository variables and secrets:
Repository Variables
Navigate to Settings > Environments > production and add:
Variable | Value | Description |
---|---|---|
AWS_ACCOUNT_ID | 123456789012 | Your AWS account ID |
AWS_REGION | us-east-1 | Target AWS region |
AWS_ROLE_ARN | arn:aws:iam::123456789012:role/GitHubActionsTodosDeployment | IAM role ARN |
Environment Protection Rules
- Go to Settings > Environments > production
- Enable Required reviewers (optional)
- Add Deployment branches rule for
master
branch only
Pipeline Features
- β Secure Authentication: No long-term AWS credentials stored
- β Environment Protection: Requires approval for production deployments
- β Artifact Management: Build artifacts passed between jobs
- β Verification: Post-deployment health checks
- β Rollback Ready: CDK diff shows changes before deployment
Triggering Deployments
Deployments trigger automatically on pushes to master:
# Make changes and push to master
git add .
git commit -m "Update application"
git push origin master
# Monitor deployment in GitHub Actions tab
Manual Deployment
You can also trigger deployments manually:
# From the GitHub Actions tab
# Select "ci-build" workflow
# Click "Run workflow" on master branch
Monitoring Deployments
View deployment progress:
- GitHub Actions: Real-time logs and status
- AWS CloudFormation: Stack deployment events
- ECS Console: Service health and task status
- CloudWatch: Application logs and metrics
# Monitor via CLI
aws cloudformation describe-stack-events \
--stack-name TodosEcsStack \
--query 'StackEvents[0:10]'
# Check service status
aws ecs describe-services \
--cluster todos-cluster \
--services todos-service
Next Steps
- API Reference - Test the deployed API
- Testing Guide - Run integration tests against AWS
- GitHub Actions Setup - Additional OIDC configuration details
- Main Documentation - Return to project overview