This is Part 1 of a 3-part series on Deploy Docling to AWS ECS infrastructure.
AWS VPC Infrastructure Setup Guide
Overview
This guide provides step-by-step instructions for creating a secure Virtual Private Cloud (VPC) infrastructure on AWS using the AWS CLI. A VPC enables you to provision a logically isolated section of the AWS Cloud where you can launch AWS resources in a virtual network that you define.
Prerequisites
- AWS CLI installed and configured with appropriate credentials
- Basic understanding of networking concepts (CIDR blocks, subnets)
- Appropriate IAM permissions for VPC and EC2 operations
Resource Tagging Strategy
Throughout this tutorial, we implement a consistent tagging strategy for all resources. This approach ensures:
- Easy resource identification and tracking
- Simplified cost allocation
- Better resource organization and management
Standard tags used:
-
Name
: Descriptive identifier for the resource -
Environment
: Development stage (e.g., Dev, Staging, Production) -
Purpose
: Project or application identifier
1. Virtual Private Cloud (VPC) Setup
Create the VPC
Create a VPC with a /16 CIDR block, providing approximately 65,536 IP addresses:
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=DoclingVPC},{Key=Environment,Value=Dev}]'
Note: The CIDR block 10.0.0.0/16
means all resources within this VPC will have IP addresses starting with 10.0.x.x
, where the first two octets remain constant.
Store VPC ID for Future Reference
VPC_ID=$(aws ec2 describe-vpcs \
--filters Name=tag-key,Values=Name \
--query "Vpcs[?Tags[?Key=='Name' && Value=='DoclingVPC']].VpcId" \
--output text)
Apply Additional Tags
Create a tags.json
file:
{
"Tags": [
{
"Key": "Purpose",
"Value": "DoclingSetup"
}
]
}
Apply the tags to the VPC:
aws ec2 create-tags --resources $VPC_ID --cli-input-json file://tags.json
Verify VPC Creation
aws ec2 describe-vpcs \
--filters Name=tag-key,Values=Purpose \
--query "Vpcs[].[VpcId,CidrBlock,State]" \
--output table
2. Subnet Configuration
Subnets segment your VPC into smaller networks. We'll create both public and private subnets following AWS best practices.
Create Private Subnet
Deploy a private subnet in availability zone us-east-1b
:
aws ec2 create-subnet \
--vpc-id $VPC_ID \
--cidr-block 10.0.4.0/24 \
--availability-zone us-east-1b \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet-1b}]'
Create Public Subnet
Deploy a public subnet in availability zone us-east-1a
:
aws ec2 create-subnet \
--vpc-id $VPC_ID \
--cidr-block 10.0.3.0/24 \
--availability-zone us-east-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet-1a}]'
Note: Each /24 subnet provides 256 IP addresses (though AWS reserves 5 IPs per subnet for internal use).
Retrieve Subnet IDs
# Get Private Subnet ID
PRIVATE_SUBNET=$(aws ec2 describe-subnets \
--filters Name=tag-value,Values=PrivateSubnet-1b \
--query "Subnets[0].SubnetId" \
--output text)
# Get Public Subnet ID
PUBLIC_SUBNET=$(aws ec2 describe-subnets \
--filters Name=tag-value,Values=PublicSubnet-1a \
--query "Subnets[0].SubnetId" \
--output text)
Apply Tags to Subnets
aws ec2 create-tags --resources $PUBLIC_SUBNET --cli-input-json file://tags.json
aws ec2 create-tags --resources $PRIVATE_SUBNET --cli-input-json file://tags.json
Verify Subnet Configuration
aws ec2 describe-subnets \
--filters Name=tag-key,Values=Purpose \
--query "Subnets[].[SubnetId,CidrBlock,AvailabilityZone]" \
--output table
3. Internet Gateway Configuration
An Internet Gateway (IGW) enables communication between your VPC and the internet.
Create Internet Gateway
IGW_ID=$(aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=DoclingIGW}]' \
--query "InternetGateway.InternetGatewayId" \
--output text)
Apply Tags
aws ec2 create-tags --resources $IGW_ID --cli-input-json file://tags.json
Attach Internet Gateway to VPC
aws ec2 attach-internet-gateway \
--internet-gateway-id $IGW_ID \
--vpc-id $VPC_ID
Verify Internet Gateway
aws ec2 describe-internet-gateways \
--filters Name=tag-key,Values=Purpose \
--query "InternetGateways[].[InternetGatewayId,Attachments[0].VpcId,Attachments[0].State]" \
--output table
4. Route Table Configuration
Route tables determine where network traffic is directed. AWS creates a main route table automatically with each VPC, but best practice dictates creating custom route tables for better security control.
Create Public Route Table
PUBLIC_ROUTE_TABLE_ID=$(aws ec2 create-route-table \
--vpc-id $VPC_ID \
--query "RouteTable.RouteTableId" \
--output text)
Add Internet Route
Configure the route table to direct internet-bound traffic through the Internet Gateway:
aws ec2 create-route \
--route-table-id $PUBLIC_ROUTE_TABLE_ID \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id $IGW_ID
Associate Public Subnet with Route Table
PUBLIC_SUBNET_ASSOCIATION_ID=$(aws ec2 associate-route-table \
--route-table-id $PUBLIC_ROUTE_TABLE_ID \
--subnet-id $PUBLIC_SUBNET \
--query "AssociationId" \
--output text)
Verify Route Table Configuration
aws ec2 describe-route-tables \
--route-table-ids $PUBLIC_ROUTE_TABLE_ID \
--query "RouteTables[].[RouteTableId,Routes[].DestinationCidrBlock,Associations[].SubnetId]" \
--output table
Security Best Practices
Main Route Table: Never add internet routes to the main route table. This ensures new subnets don't accidentally become public.
Subnet Isolation: Keep private subnets truly private by not associating them with route tables containing internet gateway routes.
Multi-AZ Deployment: For production environments, deploy subnets across multiple availability zones for high availability.
Network ACLs: Consider implementing Network Access Control Lists for additional subnet-level security.
AWS IAM Roles and Instance Profiles
AWS IAM operates on three fundamental components:
- Trust Relationship - Defines which entities can assume a role
- Permissions - Specifies what actions the role can perform
- Temporary Credentials - Provides time-limited access tokens for role assumption
IAM Implementation Process
- Create Trust Policy - Define which AWS services can assume the role
- Create Role - Establish the role with the trust policy
- Attach Permissions - Grant specific permissions to the role
- Create Instance Profile - Package the role for EC2 instances (when needed)
- Associate Resources - Link the role or instance profile to AWS resources
You may want to dive into the concepts here.
EC2 IAM Configuration
Trust Policy for EC2
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
Create EC2 Instance Role
# Create the role
aws iam create-role \
--role-name ec2_instance_role \
--assume-role-policy-document file://ec2-trust-policy.json \
--tags Key=Name,Value=EC2InstanceRole
# Add additional tags
aws iam tag-role \
--role-name ec2_instance_role \
--cli-input-json file://tags.json
# Attach managed policy
aws iam attach-role-policy \
--role-name ec2_instance_role \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
Create Instance Profile
# Create instance profile
aws iam create-instance-profile \
--instance-profile-name ec2_instance_role-profile \
--tags Key=Name,Value=EC2InstanceRoleProfile
# Add tags to instance profile
aws iam tag-instance-profile \
--instance-profile-name ec2_instance_role-profile \
--cli-input-json file://tags.json
# Associate role with instance profile
aws iam add-role-to-instance-profile \
--role-name ec2_instance_role \
--instance-profile-name ec2_instance_role-profile
ECS IAM Configuration
Trust Policy for ECS Tasks
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ecs-tasks.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
ECS Task Execution Role
The task execution role is required for ECS to pull container images and write logs on your behalf.
# Create ECS task execution role
ECS_TASK_EXEC_ROLE=$(aws iam create-role \
--role-name ecs_task_exec_role \
--assume-role-policy-document file://ecs-trust-policy.json \
--tags Key=Name,Value=ECSTaskExecutionRole \
--query "Role.RoleName" \
--output text)
# Add tags
aws iam tag-role \
--role-name $ECS_TASK_EXEC_ROLE \
--cli-input-json file://tags.json
# Attach AWS managed policy for task execution
aws iam attach-role-policy \
--role-name $ECS_TASK_EXEC_ROLE \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
ECS Task Role (Optional)
The task role provides permissions for your application code running inside the container.
Note: This role can be omitted if your application doesn't need AWS API access. Test without it first to determine if it's necessary.
# Create ECS task role (if needed)
ECS_ROLE=$(aws iam create-role \
--role-name ecs_task_role \
--assume-role-policy-document file://ecs-trust-policy.json \
--tags Key=Name,Value=ECSTaskRole \
--query "Role.RoleName" \
--output text)
# Add tags
aws iam tag-role \
--role-name $ECS_ROLE \
--cli-input-json file://tags.json
# Attach application-specific policies as needed
# aws iam attach-role-policy --role-name $ECS_ROLE --policy-arn <policy-arn>
Summary
You now have the essential IAM & networking foundation for our AWS ECS deployment.
Next Steps: In the next part of this series, we'll configure the EC2 infrastructure that will use these roles to run your containerized applications.
Top comments (0)