In this tutorial, we are going to create a VPC using Ansible in AWS. Our VPC will include a router, subnet, IGW, Security Group and definitely an EC2 instance.
This is the topology we would create. (I have mentioned the Ansible Module so as to make it easier)
Prerequisites
- IAM User with the required permission.
- Boto installed. (Ansible uses the Boto Python library to handle AWS management)
If you are planning to improve your IAM security, please read my guide on it.
1. Creating a custom Role
We would first create an AWS VPC Role.
ansible-galaxy init aws-vpc
We would be using the two files below from our aws-vpc role.
- tasks - main.yml - vars -main.yml
Variables
We will place the variables in the vars/main.yml file. This allows the role to be easily reusable. Modify the variables depending on your requirement but replace your AWS Access and Secret key.
--- #vars/main.yml aws_access_key: "" aws_secret_key: "" region: "us-east-1" # VPC vpc_cidr: 10.10.0.0/24 vpc_name: "Ansible VPC" # Subnet subnet_name: "Ansible Subnet" subnet_cidr: 10.10.0.0/26 # Internet Gateway Name igw_name: "Traffic IGW" securitygroup_name: "Ansible Security Group" ec2_tag: "WebServer" #The local path to which we would save our EC2 Private Key ec2_key_directory: "/home/ansible/roles/aws-vpc/" keypair_name: "ec2_key_pair"
Do not store your AWS credentials as a variable! Follow the best practice
2. Creating the VPC
Our VPC will include the following components.
- VPC
- Subnet
- Router
- IGW (Internet Gateway)
- Security Group
- EC2 Instance
a) VPC
To create a VPC, we have to use the ec2_vpc_net module. We will register the module returned data in the “vpc” variable.
- name: create VPC ec2_vpc_net: name: "{{ vpc_name }}" cidr_block: "{{ vpc_cidr }}" region: "{{ region }}" state: present aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" register: vpc
b) Creating a subnet and associating it with an Internet Gateway
Now that we have successfully created a VPC. We would need to create a subnet and an IGW. We need an IGW so that our public subnet can access the internet.
In our subnet, we have set map_public to “YES”. This means instances created in this subnet is associated with a public IP address.
- name: associate subnet to the VPC ec2_vpc_subnet: state: present vpc_id: "{{ vpc_id }}" region: "{{ region }}" cidr: "{{ subnet_cidr }}" aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" map_public: yes resource_tags: Name: "{{ subnet_name }}" register: subnet - name: create IGW ec2_vpc_igw: vpc_id: "{{ vpc_id }}" region: "{{ region }}" aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" state: "present" tags: Name: "{{ igw_name }}" register: igw
c) Routing traffic to IGW and creating a security group
Now, we would need to route the traffic to the IGW via the route table and create a security group.
- name: Route IGW ec2_vpc_route_table: vpc_id: "{{ vpc_id }}" region: "{{ region }}" aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" subnets: - "{{ subnet.subnet.id }}" routes: - dest: 0.0.0.0/0 gateway_id: "{{ igw.gateway_id }}" tags: Name: "{{ route_name }}" # update the CIDR address in the SSH port section. - name: Create Security Group ec2_group: name: Web DMZ description: DMZ Security Group vpc_id: "{{ vpc_id }}" region: "{{ region }}" aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" rules: - proto: tcp ports: - 80 cidr_ip: 0.0.0.0/0 - proto: tcp ports: - 22 cidr_ip: 0.0.0.0/0 register: security_group
d) Creating an EC2 Key Pair and an EC2 instance
This is our last step, we will create an EC2 Key Pair and an EC2 instance.
Key points:
- if you already have an EC2 key pair, skip the EC2 key pair and update the key_name with the name of the key pair.
- exact_count is important! It determines the number of instances is created.
- Image ID can be found on AWS Marketplace.
- name: create a new ec2 key pair ec2_key: aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}" name: ec2_keypair region: "{{ region }}" register: keypair - name: Copy EC2 Private Key locally so it can be later on used to SSH into the instance copy: content="{{ keypair.key.private_key }}" dest={{ ec2_key_directory }}key.ppk when: keypair.changed == true - name: Create EC2 server ec2: image: ami-467ca739 wait: yes instance_type: t2.micro region: "{{ region }}" group_id: "{{ security_group.group_id }}" vpc_subnet_id: "{{ subnet.subnet.id }}" key_name: "{{ keypair.key.name }}" count_tag: Name: apacheserver exact_count: 1 aws_access_key: "{{ aws_access_key }}" aws_secret_key: "{{ aws_secret_key }}"
This creates a simple VPC but creating a complex VPC is still achievable with Ansible, as it provides all the necessary modules for a VPC creation in the AWS.
If you are provisioning your servers using Ansible, it would be good to have the AWS resource creation in Ansible as-well compared to CloudFormation. If the lack of GUI is a concern, have a look at Ansible Tower. Ansible Tower is a web-based interface which lets you manage and control Ansible roles.
While Ansible is a great tool, I highly recommend looking into Terraform or CloudFormation to manage cloud resources. For example, Terraform has a module to create AWS VPC. How you use automation to provision cloud resources is a question that you might be often asked in a DevOps interview.
If you think something is missing in the post, please leave it as a comment!