Last Updated on November 25, 2022
Using separate AWS accounts provides strong separation of resources, which is great until the point you need cross-account access from a VPC in one account to another. In this article you’ll learn 3 ways to setup a secure connection across accounts, with full working examples you can try out yourself.
Why do we need cross-account VPC access?
A Virtual Private Cloud (VPC) is a private network which you create in the AWS cloud. You can deploy whatever resources you want into it, such as EC2 instances or ECS containers.
By default, resources you create within the same VPC can communicate with each other, assuming that security groups and access control lists are correctly setup. Conversely, resources deployed into separate VPCs cannot communicate with each other since there’s no route for the traffic to flow.
VPCs work like this by design, as they’re a separate isolated private network. You can of course open them up to access other AWS services and the internet, but that’s something you have to explicitly do.
Another isolation mechanism is the AWS account. By default, an AWS account cannot access resources from a different account.
Some reasons organisations create separate accounts include:
- to isolate production and non-production resources
- to isolate resources for separate business units
- to simplify billing for separate business units
Large organisations may have hundreds of AWS accounts. At some point it’s likely that access will be required between accounts. In this article we’re going to concentrate explicitly on accessing VPCs between accounts, or more explicitly resources deployed into those VPCs, such as EC2 instances.
So why might a company want to do that? Here are some potential reasons.
- services deployed by a business unit in one account need to access services deployed in another (e.g. microservice architecture)
- services in a testing account may need to access services in a production account
- a company needs to provide access to services to another company, without exposing the service on the public internet
An example cross-account requirement
In the rest of this article we’ll explore 3 approaches for allowing access from an EC2 instance in one account to another EC2 instance in another account.
The setup assumes:
- we’ve got 2 accounts Account A (the provider account) and Account B (the consumer account)
- the 2 accounts have VPCs with different CIDR blocks
- account A VPC CIDR =
- account B VPC CIDR =
- account A VPC CIDR =
- account A is running an EC2 instance called Instance A, which exposes some data over HTTP port 80
- account B is running an EC2 instance called Instance B, which needs to access the data from instance A in account A
- the data must remain with the AWS network and not go onto the public internet
The following 3 options all assume this simple basic setup.
Option 1: VPC peering connection cross-account access
If two VPCs are peered, it means they have a network connection between them. With a VPC peering connection setup, instances in the VPC can talk to instances in the other, as if they were on the same network.
The peering connection works both ways between the VPCs and you can peer VPCs in the same AWS account or separate accounts.
Follow these steps to setup a peering connection between VPCs in different accounts.
Step 1: create the VPC peering connection
In the VPC dashboard of account A select Peering Connections then Create Peering Connection.
- for VPC (Requester) select the VPC you want to connect
- under Select another VPC to peer with we’re going to provide the details of the VPC in the other AWS account. Select Another account and enter the account B account id.
- if your other account is in a different region, under Region select Another Region and choose the region
- for VPC ID (Accepter) enter the VPC id of the VPC in account B
- click Create Peering Connection.
VPC CIDR for VPC peering connections
The VPC CIDR is the range of private IP address which can be allocated within the VPC. In order to create a peering connection between two VPCs, the CIDR block of the 2 accounts cannot overlap. For example:
- A VPC with CIDR
10.0.0.0/16cannot be peered with another VPC with CIDR
- A VPC with CIDR
10.0.0.0/16can be peered with a VPC with CIDR
Step 2: accept the VPC peering connection
The peering connection must now be accepted in account B. In the VPC dashboard in account B, under Peering Connections the new connection should be shown in a Pending Acceptance status. It may take a few minutes for the connection to appear.
Select the connection then under Actions select Accept Request, then Yes, Accept.
Once you’ve done this, the peering connection should go into the Active state in both accounts.
Step 3: setup route tables to route traffic to VPC peering connection
In a VPC a route table controls the target for a particular IP destination. For internal traffic, which is traffic with a destination IP address within the VPC, the target is local. When requests are made from one VPC to another using a different IP range (remember the IP range must be different to use a peering connection), we can route traffic that falls in that range to the VPC peering connection.
In account A, in the VPC dashboard select Route Tables, then select the route table associated with the subnet into which your EC2 instance is deployed. Select the Routes tab to show the actual routes. In a public subnet, this will look like this.
- you can see the local route for any traffic with a destination inside this VPC
- any other traffic is routed to the internet via an internet gateway
We’re going to add a 3rd route, for any traffic with a destination of the VPC in account B, with a target of the VPC peering connection.
Select Edit routes, then Add route. For the Destination enter the CIDR for the VPC is account B. You can find this on the VPC details page under IPv4 CIDR. Under Target select Peering Connection, then select the peering connection we just created. Select Save routes.
Now we need to do a similar process in account B. In the VPC dashboard for account B go to Route Tables, select the route table for the subnet where your EC2 instance is deployed, select the Routes tab, Edit routes, then Add route. For the destination enter the CIDR of the VPC in account A, then for the target select the peering connection. Finally, select Save Routes.
Step 4: test the VPC peering connection
Now for the fun part! We’re going to use the VPC peering connection to make a request between the two EC2 instances.
In account A go to the EC2 dashboard, select the instance you want to connect to, then copy the Private IPv4 address which we’ll need to establish the connection.
In account B, start a session in the EC2 instance you want to connect from. Depending on your setup, you can use Session Manager, SSH, or EC2 Instance Connect. Make a curl request to the private IP address
If you receive the expected response, then you’re successfully made a request to another AWS account using a VPC peering connection! ✅
Did you setup the instance security group inbound rules correctly? the instance you’re trying to connect to must have an inbound rule allowing access from the IP address of the EC2 instance you’re connecting from.
Option 2: VPC endpoint service (PrivateLink) cross-account access
A VPC endpoint is a connection from your VPC to a specific service provided by AWS or by someone else. The VPC endpoint is exposed as a private IP address within your VPC, accessible using a private DNS name. VPC endpoints are most commonly used to make AWS API requests from a VPC, without going onto the public internet.
The same technology, called PrivateLink, can be used to create a VPC endpoint allowing a connection from one VPC to a network load balancer (NLB) in another VPC. That other VPC can be in the same or a different AWS account.
- the VPC endpoint is one-directional, meaning you can only send a request from account B to account A
- it’s exposed in the VPC of account B as an elastic network interface with a DNS name associated with it. That means you can make a request to a domain name which will be resolved to a private IP address within your VPC.
- that request to the private IP will then be sent through to a network load balancer in another VPC
Sounds like magic? To understand this better, let’s get into the steps of how to setup a VPC endpoint.
Step 1: create a network load balancer
Whatever EC2 instance you want to expose to the other VPC must be served from behind an NLB. An NLB is a layer 4 load balancer which forwards TCP/IP traffic to any registered targets.
From the EC2 dashboard in account A go to Load Balancers, select Create Load Balancer, then select Create next to Network Load Balancer.
- give the load balancer a sensible name (e.g. simple-load-balancer)
- for the Scheme select Internal
- under VPC choose the VPC where the instance you want to expose is deployed
- under Mappings pick the availability zones and subnets you want the load balancer to be connected to (you can select all of them or just the one where your EC2 instance is deployed)
- leave IPv4 address and Private IPv4 address as the defaults
Now we have to create a listener, which in my case will listen on port 80, and a target group for it to forward traffic to. A target group is just a place where you can register individual instances or IP addresses which the load balancer will balance traffic between.
Select Create target group and a separate Specify group details page will open. Enter these details.
- for target type pick Instances
- for Target group name enter a sensible name (e.g. simple-target-group)
- for Protocol you must leave it as TCP in order to connect the target group with an NBL
- enter the correct Port
- under VPC select the VPC where your instance is deployed
Now you’re on the Register Targets page where you can pick which instances you want to include in this target group. Select the instance you want to make available, select Include as pending below, then select Create target group.
Back on the Create Network Load Balancer page under Default action hit the refresh icon then choose the new target group.
Finally, click Create load balancer.
Now wait for your load balancer to reach the active state.
In the EC2 console go to Target Groups, select the target group you just created, then select Targets. Hopefully you should see that you have a single target with a healthy status.
If your target group looks like the image above, you’re good to carry on. If not, see troubleshooting at the end of this section.
Step 2: create a VPC endpoint service in the provider account
Now we’ll create a VPC endpoint service, which is the service which points at our network load balancer which other VPCs will be able to connect into. We need to create it in the same account as the network load balancer we want to expose, in this case account A.
In the VPC dashboard select Endpoint Services then Create Endpoint Service. Select the NLB you just created then click Create service.
Wait for the VPC endpoint to have an Available status. Select it, go to Actions, then select Add principals to whitelist.
Here we can add the ARN of the account to which we want to provide access, using the format
arn:aws:iam::<aws-account-id>:root. Once you’ve entered the value, select Add to Whitelisted principals.
Before we move to the next step, go to the VPC endpoint service details page and copy the Service name which we’ll need later on.
VPC endpoint service vs. VPC endpoint
To avoid any confusion, let’s make sure we’re clear on these terms:
- a VPC endpoint service is created in the provider account (account A) and it forwards requests to an NLB in that same VPC. It is ready to receive endpoint connection requests from VPC endpoints in VPCs in other AWS accounts.
- a VPC endpoint is created in the consumer account to connect to the VPC endpoint service
Step 3: create a VPC endpoint in the consumer account
In the account which needs access to the EC2 instance, account B, go to the VPC dashboard and select Endpoints then Create Endpoint.
- under Service category choose Find service by name
- enter the service name of the VPC endpoint service you created in the previous step
- select Verify to validate the service name
- select the VPC where the EC2 instance you want to connect from is deployed
- under Security group select or create a security group which allows inbound access from the EC2 instance you want to connect from
- select Create endpoint
The VPC endpoint should have a pending acceptance status, which means we need to accept the request in account A. Back in account A’s VPC dashboard, go to Endpoint Services, select the endpoint service, then select Endpoint Connections where you should see the pending connection. Select it, then go to Actions and choose Accept endpoint connection request.
Confirm the acceptance on the popup that appears, then wait for the endpoint to move from Pending to Available.
Back in account B, under your endpoint details there should be a list of several DNS names. Copy the first one, which allows you to connect to the VPC endpoint from any availability zone.
Step 4: test the VPC endpoint connection
With all that setup out the way, let’s put this endpoint to the test!
In account B, start a session in the instance from which you want to access the instance in account A. Enter the command
curl <vpc-endpoint-dns-name> using the DNS name you copied in the previous step.
Another successful cross-account request! This time, using a VPC endpoint. ✅
If your request fails, consider these troubleshooting options.
- NLB connection working? create a new temporary EC2 instance in account A and make a request to the NLB. If this fails, there’s an issue with the NLB or security groups of the instances.
- VPC endpoint working? if you think the NLB is working correctly, ensure the security group attached to the VPC endpoint in account B allows inbound access from the EC2 instance you’re making the request from.
Option 3: Transit gateway cross-account access
The AWS Transit Gateway is a cloud router, which connects multiple VPCs and even on-premises networks through a central hub. One of the main benefits is that if you have multiple VPCs which need to be interconnected, then each VPC needs just a single connection to the transit gateway rather than one to each other VPC.
Transit gateway by default only allows VPCs from the same AWS account to be attached. For our cross-account scenario, we’ll have to use another AWS service called the Resource Access Manager (RAM). RAM lets you share certain resources between AWS accounts. Sharing the transit gateway with another AWS account means that VPCs from that account can be attached to it.
Much like with the VPC peering connection, requests between VPCs connected to a transit gateway can be made in both directions.
Here are the steps to follow to setup a cross-account VPC connection using transit gateway.
Step 1: create a Transit Gateway
From the VPC dashboard in account A, go to Transit Gateways then select Create Transit Gateway. You can optionally give the transit gateway a name, keep all the default settings, then select Create Transit Gateway. Wait for it to reach the available state.
Step 2: share the Transit Gateway using Resource Access Manager
Now we’re going to share the transit gateway with account B. Go to the Resource Access Manager dashboard, then select Create a resource share.
- give the share a name (e.g. transit-gateway-share)
- under Select resource type choose Transit Gateways and select the transit gateway you just created
- under Principals add the account id of the consumer account you want to share the transit gateway with, then click Add
- select Create resource share
Now let’s jump into account B, and go to the Resource Access Manager dashboard.
Under Shared with me, select Resource shares and you should see a pending resource share. Select the name to go into the details page, then select Accept resource share and confirm this action on the popup that appears.
You should now have a transit gateway resource share with a Status of Active. Cool!
Step 3: attach both VPCs to the Transit Gateway
Now that both AWS accounts have access to the transit gateway, we can attach both VPCs to it.
Still in account B, go to the VPC dashboard and select Transit Gateway Attachments then Create Transit Gateway Attachment. For Transit Gateway ID pick the transit gateway we just gained access to via the resource share. For VPC ID select the VPC that contains the instance from which you want to connect to account A, then select Create attachment.
Let’s jump back into Account A, where we’ll have to accept this connection and also setup the connection with the VPC in account A. Go to the VPC dashboard and select Transit Gateway Attachments. Select the attachment with a pending acceptance state, and go to Actions then choose Accept. Confirm the acceptance on the popup that appears.
Still in account A, Click Create Transit Gateway Attachment, then for Transit Gateway ID select the transit gateway, for the VPC ID select the VPC with the instance you want to connect to, then select Create attachment.
After a short time, on the Transit Gateway Attachments screen you should have two attachments in the available state.
Step 4: setup the route tables
The final thing to do here is setup the route tables in both accounts to route traffic bound for the other VPC via the transit gateway.
In account A, from the VPC dashboard select Route Tables. Select the route table associated with the subnet containing the instance you want to provide access to, select the Routes tab, then select Edit routes. Select Add route, then enter the CIDR for the VPC in account B which you can get from the VPC details page. For the Target select Transit Gateway, then choose the transit gateway you just created. Click Save Routes.
Now switch to account B where we’ll edit the route table in a similar way. Go the VPC dashboard, select Route Tables, then choose the route table associated with the subnet where the instance you want to connect from is deployed. Select the Routes tab, Edit routes, then Add route. For the Destination enter the CIDR for the VPC in account A, and for the Target once again select Transit Gateway and choose your transit gateway. Select Save Routes.
Step 5: test the connection
That’s all the heavy lifting done, now it’s time to see this transit gateway in action! We’ll make a request from the instance in account B to the instance in account A, using the private IP address of the account A instance.
In account A go to the EC2 dashboard, select the instance you want to connect to, then copy the Private IPv4 addresses.
Back in account B start a session in the instance you want to connect from, then run
Nice! So we just made a request from an EC2 instance in one account to an instance in another account using a shared transit gateway. ✅
If you have any problems, the same points from the VPC peering troubleshooting apply.
You’ve just learnt 3 ways to do cross-account access between AWS VPCs. To decide which option is best for your situation, consider the following points.
|VPC Peering||VPC Endpoint||Transit Gateway|
|Pre-requisites||No-overlapping CIDR block between VPCs||Network load balancer||No-overlapping CIDR block between VPCs.|
Shared transit gateway through Resource Access Manager.
|Maximum throughput||No limit||10 Gbps (40 Gbps burst)||50 Gbps burst per VPC|
|Cost||No hourly cost|
Same region cross-AZ data transfer costs (pricing)
Data transfer cost (pricing)
Network load balancer cost (pricing)
|Hourly cost per attachment|
Data transfer cost (pricing)