AWS VPC peering in CloudformationThu, 02 Apr 2020
I was in the process of migrating a mobile backend application into a custom Amazon VPC. Unfortunately, the mobile client was directly connected to a single EC2 instance public IP in a default VPC 🤬. The mobile team couldn't force the update for all the clients, therefore I could not possibly terminate the old instance and redirect all the traffic to a new load balancer. I needed to "slowly" migrate to the new architecture piece by piece. To make the matter worse, the database and the redis cache where all running in that single EC2 server 😵.
So, the first thing to do, was to move out the database and the cache into their own instance, but these had to be placed inside the new VPC and still be able to communicate with the EC2 instance in the default VPC. The "final temporary" architecture would look something like this:
How is this possible to achieve? Well AWS offer VPC Peering to allow VPC-to-VPC communication. A VPC peering connection simply is a networking connection between two VPCs that enables you to route traffic between them using private IP addresses. In the AWS terminology we have a requester VPC (custom, which will request for peering connection) and an accepter VPC (default, which will accept the connection).
To send private IP traffic from your instance to an instance in the accepter VPC, you must add a route to the route table that is associated with your subnet in which your instance resides. The route points to the CIDR block of the accepter VPC. In my case the communication was happening in between the default and custom VPC, so I put everything in one template as it was temporary. If you have two custom VPCs you should make two distinct templates.
In Cloudformation, the route that points to the accepter would be the following:
ToAccepterVPCRoute: Type: AWS::EC2::Route Properties: DestinationCidrBlock: !Ref AccepterVPCCIDR # Custom VPC CIDR block or subnet RouteTableId: !Ref RequesterVPCRouteTable # Route table in the default VPC VpcPeeringConnectionId: !Ref VPCPeeringConnection
ToRequesterVPCRoute: Type: AWS::EC2::Route Properties: DestinationCidrBlock: !Ref RequesterVPCCIDR # Default VPC CIDR block or subnet RouteTableId: !Ref AccepterVPCRouteTable # Route table in the custom VPC VpcPeeringConnectionId: !Ref VPCPeeringConnection
And of course we must create the VPC peering connection itself, but only on one side:
VPCPeeringConnection: # From the requester side Type: AWS::EC2::VPCPeeringConnection Properties: VpcId: !Ref VPC PeerVpcId: !Ref AccepterVPC # The custom VPC
Even though we have specified only one peering resource, the connection is not one sided, both VPCs' services can receive and send requests to each others, but only if the route tables are configured accordingly.
You need to associate respectively the route tables from the two VPCs with the appropriate subnets in which your resources you want to connect reside. Let's say your RDS instance is in a private subnet A, then you need a route table associated with subnet A, this table will have a route which will point to the other VPC CIDR block.
RequesterVPCRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC
RequesterVPCSubnetARouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RequesterVPCRouteTable SubnetId: !Ref PrivateSubnetA
You should to the same thing for the other VPC.
AccepterVPCRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref AccepterVPC
AccepterVPCSubnetARouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref AccepterVPCRouteTable SubnetId: !Ref PrivateSubnetInTheAccepterVPC
One more interesting thing, as in my case, if you want to connect the ALB with the EC2 instance in the default VPC through private IP, you will need to set the parameter
TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Port: !Ref EC2InAccepterVPCPort Protocol: HTTP Targets: - Id: !Ref EC2InAccepterVPCPrivateIp AvailabilityZone: all Port: !Ref EC2InAccepterVPCPort TargetType: ip VpcId: !Ref VPC
I hope you got something from this tutorial! Certainly to achieve this it took me a while as the Cloudformation tutorials are really rare these days 🤔 . Anyway I have made a template out of everything so you can check the various parts assembled together.