Automating with Ansible: Building a VPC
Networking on AWS made easy!
In this article we’re looking at using Ansible for automating the configuration of cloud networking in an AWS VPC. If you’re not sure what you’re doing here, maybe peek at the introduction. The scope of the automation we will build will handily configure all of the following:
- VPC and Subnets: create the VPC itself, along with public and private subnets across three availability zones: a, b, and c
- Internet Gateway: configure a gateway for our public resources to access the internet
- NAT Gateway: configure a NAT gateway to allow our private resources to access the public internet
- VPC Route Tables: define the routing to make our subnets public or private (route public traffic using either the public or NAT gateway)
- Security Groups: define some useful security groups for limiting communication only within the VPC, and/or to allow SSH or HTTP/S traffic from the public internet
- Private DNS: create a private Route53 hosted zone for resolution of resources within the VPC
Take note this article is not here to explain how these AWS resources work, or even how to configure them, but specifically how to automate their configuration with Ansible. Let’s get started!
VPC and Subnets
Configure hosts and group vars
We’re going to start by defining an Ansible host for our VPC. This host will act as a “logical host” (as in it is not an actual host that we can connect to to run commands) that will represent all the VPC configuration. So in our inventory we define a vpc
group with a single vpc.ansibled
(the name is just a name, nothing special) host, and then place this vpc
group into a high-level “project” group called project.ansibled
.
Now let’s define the variables we need when configuring the VPC and subnets. Globally, in group_vars/all.yml
, we just want to define that by default we don’t want to attempt an SSH connection to our hosts, and just run Ansible tasks locally (almost all of our automation will be AWS cloud and serverless):
Our project.ansibled
group is going to do some heavy lifting and supply high-level definitions such as the VPC name and our AWS credentials. All our hosts we will place in this group so that this configuration is available when Ansible is executing. So in group_vars/project.ansibled.yml
:
Next we define some particulars of our VPC itself: the IP address block for the VPC, security groups, and subnet configuration. These we will define as host vars of our vpc.ansibled
host, because we want them to be specific to this host, and other hosts (when we get around to them), won’t need to reference these definitions themselves.
Protect sensitive information with Ansible Vault
You might be wondering why the aws_access_key
and aws_secret_key
vars that store our IAM credentials look like that. Given that we’re going to commit our automation to a repository, we need to make sure this sensitive information isn’t visible as plain-text — enter Ansible Vault, a feature of Ansible that allows us to encrypt files and strings, making them safe for version control.
To generate these encrypted strings that we can decrypt at runtime, first we write an encryption password to a (git-ignored, or preferably not even in the repo directory) file:
echo "my_vault_pass" > ~/ansibled.vault
Second, feed our plain-text value to the ansible-vault
program, specifying our password file, and out pops an encrypted string that we can safely store in our Ansible vars!
Later, when we want to execute our automation, we simply specify our vault password file, or specify that Ansible should prompt us for it:
# prompt the user for the Vault password
ansible-playbook -i ansibled.inventory vpc.yml --ask-vault-pass# read the Vault password from file
ansible-playbook -i ansibled.inventory vpc.yml --vault-password-file ~/ansibled.vault
Tasks
Our Ansible tasks (the “code”) will all live under a tasks/
directory, and under a tasks/vpc/
subdirectory for all our tasks related to creating our VPC. Our playbook will then dynamically include these task lists at runtime, allowing us to organise our tasks to create modular blocks of “code”.
The first stage of our VPC automation will concern itself with the following steps:
- create the VPC
- create the VPC subnets
- create the VPC security groups
- create the Route53 private zone for the VPC
With our main VPC components in place we can now configure the routing and gateways for our VPC:
- create internet gateway
- create NAT gateway (and update VPC DNS)
- create route table for private subnets
- create route table for public subnets
Playbook
Now that we’ve written some tasks to build our VPC, we just need to tie it together with a playbook. We simply target the vpc
group, populate our environment with our AWS credential details, and use the include_tasks
directive to pull in our VPC tasks. Easy!
Get your facts straight
The last piece of the puzzle is to provide an easy way for other parts of our automation to access and utilise the details of the VPC infrastructure we’ve just put up. For example, we will want to able to easily lookup the IDs of our VPC subnets by the human-readable names we assigned them (private-a
, public-b
, etc.), just like we did when setting up our route tables above. So, we create a “facts” task list in tasks/vpc/facts.yml
:
This “facts” task list for our VPC can now be included by other playbooks to peek at AWS and discover some important information about our VPC!
And… Action!
Now to automatically build our VPC, simply execute Ansible:
# prompt the user for the Vault password
ansible-playbook -i ansibled.inventory vpc.yml --ask-vault-pass# read the Vault password from file
ansible-playbook -i ansibled.inventory vpc.yml --vault-password-file ansibled.vault
Finally, grab a coffee while that runs :) Happy automating!
I love automation. This series of articles, Automation with Ansible, is the documenting of some of the Ansible bits ‘n bobs that make my life easier when managing software infrastructure.
Check it all out on GitHub, or the other entries in the series:
- Automation with Ansible: Introduction
- Automation with Ansible: Building a VPC (this article)
- Automation with Ansible: AWS Elasticsearch
- Automation with Ansible: Aurora RDS Clusters
- Automation with Ansible: Logentries