Sometimes happens, as it happened to us, that you have one or more services you want to share between your VPCs. For us, the case was for an ELK stack that we use internally to monitor the state of our infrastructure.
With this article we want to share our recipe to peer multiple VPCs with the help of the Ansible [1] automation tool.
The use case is clearly explained from the image below (courtesy of Amazon):
VPC A is the vpc you want to be shared and VPC B and VPC C are the VPCs you want to give access to but keeping them separated.
- First of all, you have to create your VPC B:
1 2 3 4 5 6 7 8 9 10 11 |
- name: Setting up VPC B ec2_vpc: state: present cidr_block: 10.0.0.0/16 resource_tags: { Name: "VPC_B" } subnets: - cidr: "10.0.1.0/24" resource_tags: { Name : 'VPC_B_subnet_0' } az: eu-west-1a internet_gateway: True register: vpc_b |
Note the register at the end, we will use that variable in the next sections.
- The second step is to gather all the information required to build the peering from VPC A:
1 2 3 4 5 |
- name: Getting VPC_A info ec2_vpc_net_facts: filters: "tag:Name": VPC_A register: vpc_a |
1 2 3 4 5 6 |
- name: Getting VPC_A info ec2_vpc_subnet_facts: filters: vpc-id: "{{ vpc_a.vpcs.0.id }}" availabilityZone: "eu-west-1a" register: vpc_a_subnet |
1 2 3 4 5 6 |
- name: Getting VPC_A info ec2_vpc_route_table_facts: filters: vpc-id: "{{ vpc_a.vpcs.0.id }}" association.main: "true" register: route_tables |
Notice we have registered also the route tables. Route tables will be used to teach AWS on how to route packages between peering networks.
- At this point, we have all the information required to setup the peering. Notice that this step at the time of writing this article is not supported from Ansible (2.1.2.0) and should be done with a command. A module ec2_vpc_peer will be released in Ansible 2.2 actually solving this problem.
1 2 3 |
- name: Setting up vpc peering command: aws ec2 create-vpc-peering-connection --vpc-id {{ vpc_b.vpc.id }} --peer-vpc-id {{ vpc_a.vpcs.0.id }} register: peering_raw |
- Unfortunately, using a command gives us a standard output as a response and hence we have to parse it as an Ansible object:
1 |
- set_fact: peering="{{ peering_raw.stdout | from_json }}" |
- Peering should be accepted to be operative and again Ansible doesn’t offer the necessary tool:
1 2 |
- name: Accepting vpc peering command: aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id {{ peering.VpcPeeringConnection.VpcPeeringConnectionId }} |
- Well done, peering established! But the tale not ends here, we have a couple more steps to do. Remember the route table registered before? Now it’s time to educate AWS on how to route our packages. The table below shows how the route table should be:
Route Table | Destination | Target |
---|---|---|
VPC A | 172.16.0.0/16 | Local |
10.0.0.0/16 | pcx-12121212 | |
192.168.0.0/16 | pcx-23232323 | |
VPC B | 10.0.0.0/16 | Local |
172.16.0.0/16 | pcx-12121212 | |
VPC C | 192.168.0.0/16 | Local |
172.16.0.0/16 | pcx-23232323 |
- This time Asible offers all we need:
1 2 3 4 5 6 7 8 9 10 11 12 |
- name: Setting up env vpc peering route ec2_vpc_route_table: vpc_id: "{{ vpc_a.vpc.id }}" tags: Name: "VPC_B_to_VPC_A" subnets: - "10.0.1.0/24" routes: - dest: 0.0.0.0/0 gateway_id: "{{ vpc_a.igw_id }}" - dest: "{{ vpc_a_subnet.subnets.0.cidr_block }}" vpc_peering_connection_id: "{{ peering.VpcPeeringConnection.VpcPeeringConnectionId }}" |
- The last step is a bit convoluted. Due to an Ansible bug [2] (at the time of writing this article on version 2.1.2.0) it’s not possible to upgrade the VPC A route table, so we should again resort to a command. This time we use shell cause we want to execute a small script in an atomic way (from the Ansible point of view):
1 2 3 4 5 6 |
- name: Setting up default vpc peering route shell: aws ec2 delete-route --route-table-id {{ route_tables.route_tables.0.id }} \ --destination-cidr-block "10.0.1.0/24" 2> /dev/null; \ aws ec2 create-route --route-table-id {{ route_tables.route_tables.0.id }} \ --destination-cidr-block "10.0.1.0/24" \ --vpc-peering-connection-id {{ peering.VpcPeeringConnection.VpcPeeringConnectionId }} |
- The last step is left as a task for the reader: you should repeat all of this for VPC C, alternatively you could introduce some sort of variable to handle these tasks parametrically.
We hope you enjoyed reading this article, leave a comment if you find it useful. Ciao!
[2] https://github.com/ansible/ansible-modules-extras/issues/1510