Skip to content

Create an AWS EC2 instance with the AWS CLI - Step 1 - Launch Instance

Make sure you do this setup first:

  1. Setup macOS for AWS Cloud DevOps
  2. AWS Authentication

Steps:

  1. Launch an AWS EC2 instance (this post)
  2. Attach an instance role to allow S3 access
  3. Cleanup

Scripts are bash

Setup

Names

Assign resource names:

# VPC
vpc="vpc-ec2"

# Subnets
subnet_1="subnet-ec2-1"
subnet_2="subnet-ec2-2"

# Internet Gateway
internet_gateway="igw-ec2"

# Route Table
route_table="rtb-ec2"

# Security Group
security_group="security-ec2"

# instance
instance="instance-ec2"

# SSH access key
key="aws-ec2-key"

VPC

Create a VPC (Virtual Private Cloud):

aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16  \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value='$vpc'}]'

Subnets

Create 2 subnets:

vpc_id=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=$vpc | jq -r '.Vpcs[0].VpcId')

# 1st subnet
aws ec2 create-subnet \
  --vpc-id $vpc_id \
  --cidr-block 10.0.0.0/24 \
  --availability-zone us-west-2a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value='$subnet_1'}]'  

# 2nd subnet
aws ec2 create-subnet \
  --vpc-id $vpc_id \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-west-2a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value='$subnet_2'}]'  

Optionally modify the public IP addressing behavior of your subnet so that an instance launched into the subnet automatically receives a public IP address. Otherwise, you should associate an Elastic IP address with your instance after launch so that it's reachable from the Internet.

subnet_id=$(aws ec2 describe-subnets --filters Name=tag:Name,Values=$subnet_1 | jq -r '.Subnets[0].SubnetId')
aws ec2 modify-subnet-attribute --subnet-id $subnet_id --map-public-ip-on-launch

Internet Gateway

After you've created the VPC and subnets, you can make one of the subnets a public subnet by attaching an Internet gateway to your VPC, creating a custom route table, and configuring routing for the subnet to the Internet gateway.

Create

aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value='$internet_gateway'}]' 

Attach to VPC

vpc_id=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=$vpc | jq -r '.Vpcs[0].VpcId')

internet_gateway_id=$(aws ec2 describe-internet-gateways --filters Name=tag:Name,Values=$internet_gateway | jq -r '.InternetGateways[0].InternetGatewayId')

aws ec2 attach-internet-gateway --vpc-id $vpc_id --internet-gateway-id $internet_gateway_id

Route Table

Create:

vpc_id=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=$vpc | jq -r '.Vpcs[0].VpcId')

aws ec2 create-route-table \
  --vpc-id $vpc_id \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value='$route_table'}]' 

Associate with a subnet:

# 1st subnet
subnet_id=$(aws ec2 describe-subnets --filters Name=tag:Name,Values=$subnet_1 | jq -r '.Subnets[0].SubnetId')

route_table_id=$(aws ec2 describe-route-tables --filters Name=tag:Name,Values=$route_table | jq -r '.RouteTables[0].RouteTableId')

aws ec2 associate-route-table  --subnet-id $subnet_id --route-table-id $route_table_id

Create a route in the route table that points all traffic (0.0.0.0/0) to the Internet gateway:

route_table_id=$(aws ec2 describe-route-tables --filters Name=tag:Name,Values=$route_table | jq -r '.RouteTables[0].RouteTableId')
internet_gateway_id=$(aws ec2 describe-internet-gateways --filters Name=tag:Name,Values=$internet_gateway | jq -r '.InternetGateways[0].InternetGatewayId')

aws ec2 create-route \
  --route-table-id $route_table_id \
  --gateway-id $internet_gateway_id \
  --destination-cidr-block 0.0.0.0/0

Confirm route is active:

route_table_id=$(aws ec2 describe-route-tables --filters Name=tag:Name,Values=$route_table | jq -r '.RouteTables[0].RouteTableId')
aws ec2 describe-route-tables --route-table-id $route_table_id

Security Group

Create a security group in your VPC:

vpc_id=$(aws ec2 describe-vpcs --filters Name=tag:Name,Values=$vpc | jq -r '.Vpcs[0].VpcId')

aws ec2 create-security-group \
    --group-name $security_group \
  --description "Security group for instance access" \
  --vpc-id $vpc_id \
  --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value='$security_group'}]' 

Add a rule that allows SSH access from anywhere:

group_id=$(aws ec2 describe-security-groups --filters Name=tag:Name,Values=$security_group | jq -r '.SecurityGroups[0].GroupId')
aws ec2 authorize-security-group-ingress \
  --group-id $group_id \
  --protocol tcp --port 22 --cidr 0.0.0.0/0

EC2 Instance

List Amazon Linux images (via System Manager):

aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest --query "Parameters[].Name"

Launch instance:

subnet_id=$(aws ec2 describe-subnets --filters Name=tag:Name,Values=$subnet_1 | jq -r '.Subnets[0].SubnetId')
group_id=$(aws ec2 describe-security-groups --filters Name=tag:Name,Values=$security_group | jq -r '.SecurityGroups[0].GroupId')

aws ec2 run-instances \
  --subnet-id $subnet_id \
  --security-group-ids $group_id \
  --image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64 \
  --instance-type t2.micro \
  --count 1 \
  --key-name $key \
   --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value='$instance'}]'

Check instance status. Wait until it is running:

instance_id=$(aws ec2 describe-instances --filters Name=tag:Name,Values=$instance | jq -r '.Reservations[-1].Instances[-1].InstanceId')
aws ec2 describe-instances --instance-id $instance_id | jq -r '.Reservations[0].Instances[0].State'

Login into the instance:

instance_public_ip=$(aws ec2 describe-instances --filters Name=tag:Name,Values=$instance | jq -r '.Reservations[-1].Instances[-1].PublicIpAddress')
ssh -i ~/.ssh/$key ec2-user@$instance_public_ip

Next step: Attach an instance role to allow S3 access