Build Your Own Default Amazon VPC (Virtual Private Cloud) Using Ansible
Tags: aws, vpc, ansible, cloud
Published: 2022-04-27 15:09:36

Just like when we have an on-premise model for our infrastructure, we also need a network for our cloud infrastructure either public or private. Yes, we can build a secure and isolated private network. If you have a plan to use AWS resources or let's say you want to host your servers using EC2 instances! Then you can create your own network for them or on AWS it's called a Virtual Private Cloud (VPC), instead of using the default one.

More about VPC, click [here](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html)!

In this section, we will create a VPC to connect our EC2 instances placed in different AZs and give them an internet connection. From this scenario, we will need:

1. VPC in a region (me: ap-southeast-3);
    
2. Subnet on each AZ (3 in total);
    
3. Internet gateway;
    
4. Route table;
    
5. Security group.
    

![VPC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vapibl8s6lhlzwd5p2ib.png)

Then, I won't go through the console but I'll use Ansible instead. Why? If you have ever seen my previous posts, you should know why :)

Alright! Just like my previous posts, we will use localhost as the target host cause here we don't touch EC2 instances yet. Make sure you have installed:

1. [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [set at least one credential](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html);
    
2. [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html);
    
3. Ansible collection for AWS by running `ansible-galaxy collection install amazon.aws` and `ansible-galaxy collection install community.aws`.
    

**Note**\*: You can replace all the details below with your own values if you already prepared them.

**Inventory**: host.yml

```yaml
---

localhost:
  hosts:
    127.0.0.1:
```

**Playbook**: vpc.yml

```yaml
- name: vpc
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
```

## 1\. Create a VPC

```yaml
    - name: create vpc
      amazon.aws.ec2_vpc_net:
        name: custom_vpc
        cidr_block: 10.0.0.0/16
        region: ap-southeast-3
      register: vpc
```

## 2\. Create Subnets

Make sure all subnets are included in the same VPC network range but in different networks between subnets)

* Availability Zone A
    

```yaml
    - name: create subnet for first az
      amazon.aws.ec2_vpc_subnet:
        vpc_id: "{{ vpc.vpc.id }}"
        state: present
        az: ap-southeast-3a
        cidr: 10.0.1.0/28
      register: az1_apse3
```

* Availability Zone B
    

```yaml
    - name: create subnet for second az
      amazon.aws.ec2_vpc_subnet:
        vpc_id: "{{ vpc.vpc.id }}"
        state: present
        az: ap-southeast-3b
        cidr: 10.0.2.0/28
      register: az2_apse3
```

* Availability Zone C
    

```yaml
    - name: create subnet for third az
      amazon.aws.ec2_vpc_subnet:
        vpc_id: "{{ vpc.vpc.id }}"
        state: present
        az: ap-southeast-3c
        cidr: 10.0.3.0/28
      register: az3_apse3
```

**Note**\*: The `vpc` variable is only available or defined when all related tasks are executed concurrently at once.

## 3\. Create Internet Gateway

```yaml
    - name: create internet gateway
      amazon.aws.ec2_vpc_igw:
        vpc_id: "{{ vpc.vpc.id }}"
        state: present
      register: igw
```

## 4\. Create Route Table

When we create a VPC, a (main) route table will be created along with it but it only creates a local route. Then, to get an internet connection we should add a route with a quad-zero route as the destination for an unspecified address (anywhere) through Internet Gateway.

**Note**\*: You can choose which subnets will be given an internet connection that acts as a public subnet.

```yaml
    - name: create custom route table
      amazon.aws.ec2_vpc_route_table:
        vpc_id: "{{ vpc.vpc.id }}"
        region: ap-southeast-3
        subnets:
          - "{{ az1_apse3.subnet.id }}"
          - "{{ az2_apse3.subnet.id }}"
          - "{{ az3_apse3.subnet.id }}"
        routes:
          - dest: 0.0.0.0/0
            gateway_id: "{{ igw.gateway_id }}"
```

## 5\. Create Security Group

If you have already decided whether any ports will be allowed for our EC2 instances, add them under the new VPC because the default one is placed under the default VPC. For example, I'll host a web server using an EC2 instance. So, I'll allow port 22 to remote the host and 80 to access the web server.

```yaml
    - name: create security group
      amazon.aws.ec2_group:
        name: ssh-web
        description: allow ssh and http
        vpc_id: "{{ vpc.vpc.id }}"
        region: ap-southeast-3
        rules:
          - proto: tcp
            ports: 22
            cidr_ip: 0.0.0.0/0
          - proto: tcp
            ports: 80
            cidr_ip: 0.0.0.0/0
```

**Run the playbook!**

```bash
$ ansible-playbook -i host.yml vpc.yml

PLAY [vpc] **************************************************************************************************************************************************************

TASK [create vpc] *******************************************************************************************************************************************************
changed: [127.0.0.1]

TASK [create subnet for first az] ***************************************************************************************************************************************
changed: [127.0.0.1]

TASK [create subnet for second az] **************************************************************************************************************************************
changed: [127.0.0.1]

TASK [create subnet for third az] ***************************************************************************************************************************************
changed: [127.0.0.1]

TASK [create internet gateway] ******************************************************************************************************************************************
changed: [127.0.0.1]

TASK [create custom route table] ****************************************************************************************************************************************
changed: [127.0.0.1]

TASK [create security group] ********************************************************************************************************************************************
changed: [127.0.0.1]

PLAY RECAP **************************************************************************************************************************************************************
127.0.0.1                  : ok=7    changed=7    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

Let's check!

```bash
$ aws ec2 describe-vpcs --query 'Vpcs[?Tags[?Value==`custom_vpc`]].{VPC:VpcId, CIDR:CidrBlock}'
[
    {
        "VPC": "vpc-0a6bbb5ca26b09679",
        "CIDR": "10.0.0.0/16"
    }
]
```

```bash
$ aws ec2 describe-subnets --query 'Subnets[?VpcId==`vpc-0a6bbb5ca26b09679`].{AZ:AvailabilityZone, CIDR:CidrBlock, SubnetID:SubnetId}'
[
    {
        "AZ": "ap-southeast-3c",
        "CIDR": "10.0.3.0/28",
        "SubnetID": "subnet-00b4e72d63a2125de"
    },
    {
        "AZ": "ap-southeast-3a",
        "CIDR": "10.0.1.0/28",
        "SubnetID": "subnet-0276d466994fa3087"
    },
    {
        "AZ": "ap-southeast-3b",
        "CIDR": "10.0.2.0/28",
        "SubnetID": "subnet-07bb6501337e4f87b"
    }
]
```

**Note**\*: Since VPC is not used yet and it doesn't cause availability risks or bandwidth constraints on our network traffic, we won't be billed for what we have created above. Don't worry! If you want to delete them all, we will do it at the end of this series cause we still need them for our EC2 instances next.

That's it for the VPC! We will use this VPC to launch EC2 instances. Let's move to the next post!

**References:**

* https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_vpc_net_module.html

* https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_vpc_subnet_module.html

* https://docs.ansible.com/ansible/devel/collections/amazon/aws/ec2_vpc_route_table_module.html

* https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_vpc_igw_module.html

* https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_group_module.html