# Configure VPC via AWS CLI

Welcome!  In today's example, we will utilize some AWS CLI commands to provision a VPC and related networking components.  The AWS CLI allows you to provision and manage cloud infrastructure all from the command line, this can help streamline your cloud management and improve efficiency.  Lets get started!

* Our task today will be for the following scenario:
    
* Provision a small VPC of 2046 IP's for a client application that has a web server and DB server.  The client would like 1024 ip address reserved for future use and would like to make use of a public and private subnet.
    

---

## AWS CLI

> The AWS Command Line Interface (AWS CLI) is a unified tool to manage your AWS services. With just one tool to download and configure, you can control multiple AWS services from the command line and automate them through scripts.

* The AWS CLI allows us to provision and manage our cloud infrastructure via the command prompt in your terminal program.
    

## Setup

* For this example, we will utilize Cloud9 as our development environment.  If using an alternative option, you will need to download the AWS CLI.  Instructions can be found at: [https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
    
* Command Line Reference can be found at: [https://docs.aws.amazon.com/cli/latest/reference/](https://docs.aws.amazon.com/cli/latest/reference/)
    

---

## Plan Architecture

> A *subnet CIDR reservation* is a range of IPv4 or IPv6 addresses that you set aside so that AWS can't assign them to your network interfaces. This enables you to specify IPv4 or IPv6 prefixes for use with your network interfaces.

* We will plan our subnet CIDR blocks so that there are no overlapping IP addresses based on client specifications.
    

```bash
VPC Size: Small /21 (2,046 Ip's)
Subnets:
  1024 IP address reserved (/22)	
  1 Public Subnets of 510 (/23)
  1 Private Subnets of 510 (/23)
Internet Gateway
NAT Gateway
Route Tables
```

\*Visual of our subnet CIDR blocks:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440568393/e6a10f1c-6621-4472-a3f8-56f44d9accc7.png align="center")

---

## Cloud9

> AWS Cloud9 is a cloud-based integrated development environment (IDE) that lets you write, run, and debug your code with just a browser. It includes a code editor, debugger, and terminal.

* In the top left of the AWS console in the search bar, type Clou9 and click Cloud9 in the Services drop-down.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440624016/852e0c50-108b-4a3e-b91e-39bb6a404811.png align="center")

* We will name our environment CLIResourcesEnv and utilize all the default options.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440640059/5ccee854-953d-47be-9644-d488b241b16d.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440650325/d1d3ef93-790d-4b28-a115-c512f3e36a51.png align="center")

* Click Create
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440662039/ce4ee719-ee5e-4105-beec-5f5bfc08d97f.png align="center")

* After the environment is created launch the IDE in another tab
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440724439/b0ea63e0-0294-483b-a6fe-976dc639889d.png align="center")

* Upon successful launch, you will be presented with a welcome screen.  Click the "+" in a new tab and select New Terminal.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440738147/0f5ac67a-2580-4b62-8923-cbd3b67f55c1.png align="center")

* From our terminal, we will proceed with the commands below:
    

---

## AWS CLI Commands

> The AWS CLI uses a multipart structure on the command line that must be specified in this order: The base call to the AWS program. The top-level command, typically corresponds to an AWS service supported by the AWS CLI. The subcommand specifies which operation to perform. General AWS CLI options or parameters required by the operation.

**aws &lt;**`command`**&gt; &lt;**`subcommand`**&gt; \[**`options and parameters`**\]**

* Before moving into provisioning our infrastructure, let's go over a few helpful commands/options - otherwise, move over to the Provision Infrastructure section:
    

### Help With Commands

```bash
AWS has a vast array of commands, to list all available commands utilize:

aws help

To see documentation for a specific command:
aws <command> help 
aws ec2 help
```

### Tagging Resources on Creation

```bash
In order to tag resources on creation you would utilize the --tag-specifications parameter

Here are a few examples of top level commands:

Instance - aws ec2 run-instances
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=MyEC2 Instance}]'

Volume - aws ec2 create-volume
-tag-specifications 'ResourceType=volume,Tags=[{Key=purpose,Value=production}]'

VPC - aws ec2 create-vpc
--tag-specifications 'ResourceType=vpc, Tags=[{Key=Name,Value=EMR-VPC}]'
```

### Tagging existing Resources

```bash
In order to tag resources that already exist you would utilize the following command:

aws ec2 create-tags --resources <resourceID> --tags Key=Stack,Value=production
```

### List Tagged Resources

```bash
In order to list instances with a specified tag you would utilize the following:

aws ec2 describe-instances
```

---

### Filtering Output

> The AWS Command Line Interface (AWS CLI) has both server-side and client-side filtering that you can use individually or together to filter your AWS CLI output. Server-side filtering is processed first and returns your output for client-side filtering.

> Server-side filtering is supported by the API, and you usually implement it with a --filter parameter. The service only returns matching results which can speed up HTTP response times for large data sets.

> Client-side filtering is supported by the AWS CLI client using the --query parameter. This parameter has capabilities that server-side filtering might not have.

```bash
To filter output of the AWS CLI commands, you can utilize the --filter and --query parameters

To filter the output of our previous command, we can filter for instances by tags.

aws describe-instances --filters Name=tag:Stack,Values=production

Another example is to list all ec2 instances by name tag, value production and only list the instance ID.

aws ec2 describe-instances –-filters "Name=tag:Name,Values=Production*" -–query “Reservations[].Instances[].InstanceId"
```

* For additional information about filtering AWS CLI output visit: [https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html)
    

## Provision Infrastructure

*In the following examples of output for the CLI commands, please note that the output JSON examples contain fabricated numbers to hide sensitive data.*

```bash
1. Create VPC
2. Create Private Subnet
3. Create Public Subnet
4. Create & Attach IGW
5. Create Route Tables
6. Create Route to IGW
7. Associate Route Table to Public Subnet
8. Create EIP
9. Create & Attach NAT Gateway
10. Create Route to NAT Gateway
11. Associate Main Route table with Private Subnet
```

### Create VPC

```bash
aws ec2 create-vpc --cidr-block 10.21.0.0/21
```

* You will see output for the VPC information in JSON format, be sure to copy the VPC ID.  Your output should look like this:
    

```bash
{
    "Vpc": {
        "VpcId": "vpc-032dd6def047a79ba", 
        "InstanceTenancy": "default", 
        "CidrBlockAssociationSet": [
            {
```

### Create Private Subnet

```bash
aws ec2 create-subnet --vpc-id vpc-032dd6def047a79ba --cidr-block 10.21.4.0/23 --availability-zone us-east-1c
```

```bash
{
    "Subnet": {
        "MapPublicIpOnLaunch": false, 
        "AvailabilityZoneId": "use1-az1", 
        "AvailableIpAddressCount": 507, 
        "DefaultForAz": false, 
        "SubnetArn": "arn:aws:ec2:us-east-1:123456789012:subnet/subnet-0856ce74b80881407", 
        "Ipv6CidrBlockAssociationSet": [], 
        "VpcId": "vpc-032dd6def047a79ba", 
        "State": "available", 
        "AvailabilityZone": "us-east-1c", 
        "SubnetId": "subnet-0856ce74b80881407", 
        "OwnerId": "123456789012", 
        "CidrBlock": "10.21.4.0/23", 
        "AssignIpv6AddressOnCreation": false
    }
}
```

### Create Public Subnet

```bash
aws ec2 create-subnet --vpc-id vpc-032dd6def047a79ba --cidr-block 10.21.6.0/23 --availability-zone us-east-1a
```

```bash
{
    "Subnet": {
        "MapPublicIpOnLaunch": false, 
        "AvailabilityZoneId": "use1-az4", 
        "AvailableIpAddressCount": 507, 
        "DefaultForAz": false, 
        "SubnetArn": "arn:aws:ec2:us-east-1:123456789012:subnet/subnet-081db35b9523672e4", 
        "Ipv6CidrBlockAssociationSet": [], 
        "VpcId": "vpc-032dd6def047a79ba", 
        "State": "available", 
        "AvailabilityZone": "us-east-1a", 
        "SubnetId": "subnet-081db35b9523672e4", 
        "OwnerId": "123456789012", 
        "CidrBlock": "10.21.6.0/23", 
        "AssignIpv6AddressOnCreation": false
    }
}
```

### Create & Attach Internet Gateway

```bash
Create IGW
aws ec2 create-internet-gateway 

Attach IGW
aws ec2 attach-internet-gateway --internet-gateway-id igw-0609e8f7d8992299d --vpc-id vpc-032dd6def047a79ba 

List IGW's
aws ec2 describe-internet-gateways
```

```bash
{
    "InternetGateway": {
        "OwnerId": "123456789012", 
        "Tags": [], 
        "Attachments": [], 
        "InternetGatewayId": "igw-0609e8f7d8992299d"
    }
}
```

### Create Route Tables

```bash
aws ec2 create-route-table --vpc-id vpc-032dd6def047a79ba
```

```bash
{
    "RouteTable": {
        "Associations": [], 
        "RouteTableId": "rtb-0286ceef8e6c79e6a", 
        "VpcId": "vpc-032dd6def047a79ba", 
        "PropagatingVgws": [], 
        "Tags": [], 
        "Routes": [
            {
                "GatewayId": "local", 
                "DestinationCidrBlock": "10.21.0.0/21", 
                "State": "active", 
                "Origin": "CreateRouteTable"
            }
        ], 
        "OwnerId": "123456789012"
    }
}
```

### Create Route to Internet Gateway

```bash
aws ec2 create-route --route-table-id rtb-0286ceef8e6c79e6a --destination-cidr-block "0.0.0.0/0" --gateway-id igw-0609e8f7d8992299d
```

```bash
{
    "Return": true
}
```

### Associate Route Table with Public Subnet

```bash
aws ec2 associate-route-table --route-table-id rtb-0286ceef8e6c79e6a --subnet-id subnet-081db35b9523672e4
```

```bash
{
    "AssociationState": {
        "State": "associated"
    }, 
    "AssociationId": "rtbassoc-0271477d251570f34"
}
```

### Create EIP

```bash
aws ec2 allocate-address
```

```bash
{
    "Domain": "vpc", 
    "PublicIpv4Pool": "amazon", 
    "PublicIp": "3.89.82.128", 
    "AllocationId": "eipalloc-0b4d1f49ac84bd3cb", 
    "NetworkBorderGroup": "us-east-1"
}
```

### Create NAT Gateway

```bash
aws ec2 create-nat-gateway --subnet-id subnet-081db35b9523672e4 --allocation-id eipalloc-0b4d1f49ac84bd3cb
```

```bash
{
    "NatGateway": {
        "NatGatewayAddresses": [
            {
                "AllocationId": "eipalloc-0b4d1f49ac84bd3cb"
            }
        ], 
        "VpcId": "vpc-032dd6def047a79ba", 
        "State": "pending", 
        "NatGatewayId": "nat-0bae2eb0279e932c4", 
        "ConnectivityType": "public", 
        "SubnetId": "subnet-081db35b9523672e4", 
        "CreateTime": "2023-03-03T04:03:33.000Z"
    }, 
    "ClientToken": "8860c570-0223-4495-8b57-b11eb0b37a62"
}
```

### Find Main Route Table for VPC

* We will use the Main Route table for our Private Subnet
    

```bash
aws ec2 describe-route-tables - Lists Route Tables

Using Filters and Query to find Main Route Table for VPC
aws ec2 describe-route-tables --filters "Name=association.main,Values=true" "Name=vpc-id,Values=vpc-032dd6def047a79ba" --query=RouteTables[*].RouteTableId
```

```bash
[
    "rtb-08b1f6162233740a2"
]
```

### Create a Route to NAT Gateway

```bash
aws ec2 create-route --route-table-id rtb-08b1f6162233740a2 --destination-cidr-block "0.0.0.0/0" --gateway-id nat-0bae2eb0279e932c4
```

```bash
{
    "Return": true
}
```

### Associate Route Table with Private Subnet

```bash
aws ec2 associate-route-table --route-table-id rtb-08b1f6162233740a2 --subnet-id subnet-0856ce74b80881407
```

```bash
{
    "AssociationState": {
        "State": "associated"
    }, 
    "AssociationId": "rtbassoc-001e9874105260813"
}
```

* If we head to the VPC Dashboard in the AWS Console we can see a resource map of the infrastructure we created via the CLI.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440840999/df5877b5-54e8-41b6-a587-b3454af3e6a4.png align="center")

---

### Remove Infrastructure

* If you have followed along with this example, be sure to remove the infrastructure that may accrue charges, notably the Elastic IP Address
    
* Via the VPC Dashboard you can either delete the NAT Gateway or disassociate the EIP and then release the Elastic IP Address.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1691440892645/261b6f46-af2f-43f5-bdd5-21eaea1f8473.png align="center")

![](https://www.theawsdev.com/content/images/2023/03/image-4.png align="left")
