VPC Peering using Terraform
My first experience with Terraform was for sharing AMIs across accounts. Buoyed by the ease of building it out, I decided to try out completing a VPC peering connection request across 2 AWS accounts. If you’d like to understand the concept of VPC peering, and the various peering scenarios, read Jawad’s blog post here.
It’s assumed that the 2 VPCs that you need peered already have been created previously. If you have a need to create a VPC, you can check out our github repo for creating a VPC. We need to create the peering request from the peering owner VPC, accept the peering connection request in the accepter account and update the route tables in both the VPCs with entries for the peering connection from either side.
Some of the salient considerations to be kept in mind are
- Access Credentials are needed for both AWS accounts
- There may be multiple route tables in each VPC, and peering connection entries have to be updated in all of them
Since we have 2 accounts, I’ve created 2 variables namely owner_profile and accepter_profile to pass these at runtime, or as a .tfvars file. I have the option to hard-code credentials, but it is not a good security practice. Additionally, since we serve multiple customers and we will be re-using the code, variables are the way to go. I’ve also defined variables for both the VPCs in question.
When you do a cross-account peering connection request, you need the 12 digit account ID of the AWS account where the accepter VPC resides. If you’ve noticed, I have not defined this as a variable. While it’s not straightforward, it’s possible to get the account ID using the Amazon Resource Names (ARNs).
ARNs typically have a format as follows
Since we now have the VPC id of the accepter VPC, we can use it’s ARN to extract the account-id. The code below does exactly that. I am using the aws_vpc data source, and using the arn to extract the account-id. I have defined the accepter_account_id as a local value
Now that I have the information needed to raise a VPC peering request, I am completing the peering request initiation and acceptance as below. If you notice, I am using the profile variables to tag the peering connections as well. Tagging is a good practice, especially if you have multiple peering connections and it’ll help during any maintenance or network troubleshooting. We have a complete blogpost dedicated to tagging practices, and I highly recommend you check it out.
Now that the peering connection is created, we have to update the route table entries on both sides to send traffic via the peering connection. Given that a single VPC can have multiple route tables, and I wanted to code to work irrespective of the number of route tables each VPC has. I have created a loop using count to cycle through all the route tables and create the route entry to the other VPC via the peering connection ID. Note that the route tables are being updated with the peered VPC CIDR block. It is also possible to route specific subnets via the peering connection, but I have not done that here. This may be relevant in cases where you need to access some central servers such as Directory Service, Anti-virus server, in a Shared Services VPC as part of a landing zone. Some organisations may also host other servers in the Shared Services VPC which are not relevant for all the peered VPCs, and want to restrict access to specific subnets only.
I explained how to create VPC peering connections and update route tables. I also touched upon some concepts of Terraform like data sources, split local values, and loops. You can find the complete terraform code for the above at our github repository. Given how simple Terraform is, you can look forward to a few more posts from me on more complex use-cases.