AWS Site-to-Site VPN with VGW
Build a hybrid cloud VPN connecting two VPCs using a Virtual Private Gateway.
Introduction
30 Second Summary
When a company moves to the cloud, their existing office servers and databases don't disappear overnight. They need a secure, encrypted tunnel connecting their physical data center to their cloud environment. This is the hybrid cloud connectivity problem that every enterprise faces.
In this project, you will build a complete Site-to-Site VPN connection between two AWS VPCs. One VPC simulates your cloud environment and the other simulates an on-premises data center. You'll configure all the components tested on the SAA-C03 exam and verify encrypted traffic flowing between both networks.
What You'll Build
A working hybrid cloud VPN architecture using a Virtual Private Gateway, a Customer Gateway device running strongSwan, and BGP dynamic routing.
By the end of this project, you'll have:
- A Virtual Private Gateway (VGW) attached to a cloud VPC with route propagation delivering on-premises routes automatically.
- A fully configured strongSwan VPN device on an EC2 instance with IPsec tunnels and BGP peering established.
- Verified bidirectional encrypted connectivity between your cloud and simulated on-premises networks, proving your VPN architecture works end to end.
- Secret Mission: Add a second Customer Gateway for redundant failover to protect against on-premises device failure.
Are there any prerequisites?
You'll need an AWS account with admin access and basic familiarity with VPCs, subnets, and route tables. All work is done in the AWS Console, so no additional local tools are required.
Before We Start
Before We Start...
Create the Cloud VPC and On-Premises VPC
A Site-to-Site VPN connects two separate networks over an encrypted tunnel. Before you can build that tunnel, you need the two networks it connects.
In this step, you'll create two VPCs in AWS. One represents your cloud environment and the other simulates an on-premises corporate data center. You'll also launch an EC2 instance in each network so you can test connectivity later.
In this step, get ready to:
- Create the Cloud VPC with a private subnet and a test EC2 instance.
- Create the On-Premises VPC with a public subnet and internet gateway.
- Launch the strongSwan EC2 instance with an Elastic IP in the on-premises network.
Create the Cloud VPC and private subnet
The Cloud VPC represents your AWS production environment. It uses a private subnet because real workloads should not be directly exposed to the internet.
- In the AWS Console, type VPC in the top search bar and select VPC from the results.
- On the VPC dashboard, click Create VPC.
- For Resources to create, select VPC only.
- For Name tag, enter cloud-vpc.
- For IPv4 CIDR block, select IPv4 CIDR manual input and enter 10.0.0.0/16.
- Leave all other settings at their defaults and click Create VPC.
Now create the private subnet inside this VPC.
- In the left navigation pane, click Subnets.
- Click Create subnet.
- For VPC ID, select cloud-vpc from the dropdown.
- For Subnet name, enter cloud-private-subnet.
- Choose any Availability Zone in your region.
- For IPv4 subnet CIDR block, enter 10.0.1.0/24.
- Click Create subnet.
Why a private subnet?
The Cloud VPC's subnet has no internet gateway and no public IP auto-assignment. This means instances in it are completely isolated from the internet. The only way to reach them will be through the VPN tunnel you build in the next steps.
Now launch a test instance in the Cloud VPC.
- In the top search bar, type EC2 and select EC2.
- On the EC2 Dashboard, click Launch instance.
- For Name, enter cloud-test-instance.
- For Application and OS Images, keep the default Amazon Linux 2023 AMI selected.
- For Instance type, select t2.micro.
- For Key pair, select an existing key pair or click Create new key pair and name it vpn-project-key.
- Under Network settings, click Edit.
- For VPC, select cloud-vpc.
- For Subnet, select cloud-private-subnet.
- For Auto-assign public IP, confirm it says Disable. This instance should have no public IP.
- Under Firewall (security groups), select Create security group. Name it cloud-instance-sg.
- Add an inbound rule: Type All ICMP - IPv4, Source 192.168.0.0/16. This allows ping traffic from the on-premises network through the VPN.
- Click Launch instance.
What is the ICMP rule for?
ICMP is the protocol behind the ping command. By allowing ICMP from 192.168.0.0/16 (the on-premises CIDR), you're preparing this instance to be reachable through the VPN tunnel when you verify connectivity in Step 4.
Create the On-Premises VPC with internet access
The On-Premises VPC simulates a corporate data center. It needs a public subnet with internet access because the strongSwan instance needs a public IP address to establish the VPN tunnel with AWS.
- Navigate back to the VPC console by typing VPC in the top search bar.
- Click Your VPCs in the left navigation, then click Create VPC.
- For Resources to create, select VPC only.
- For Name tag, enter onprem-vpc.
- For IPv4 CIDR block, select IPv4 CIDR manual input and enter 192.168.0.0/16.
- Click Create VPC.
Now create the public subnet.
- In the left navigation pane, click Subnets, then click Create subnet.
- For VPC ID, select onprem-vpc.
- For Subnet name, enter onprem-public-subnet.
- Choose the same Availability Zone you used for the cloud subnet.
- For IPv4 subnet CIDR block, enter 192.168.1.0/24.
- Click Create subnet.
Why must the CIDRs not overlap?
The Cloud VPC uses 10.0.0.0/16 and the On-Premises VPC uses 192.168.0.0/16. These are completely separate IP ranges. If the CIDRs overlapped, routing would be ambiguous and the VPN could not forward traffic between the two networks.
The on-premises subnet needs an Internet Gateway so the strongSwan instance can reach the internet.
- In the left navigation pane, click Internet gateways.
- Click Create internet gateway.
- For Name tag, enter onprem-igw.
- Click Create internet gateway.
- On the next page, click Actions, then Attach to VPC.
- Select onprem-vpc and click Attach internet gateway.
Now add a route so traffic destined for the internet goes through the gateway.
- In the left navigation pane, click Route tables.
- Find the route table associated with onprem-vpc (it will show onprem-vpc in the VPC column).
- Select it, then click the Routes tab at the bottom.
- Click Edit routes.
- Click Add route.
- For Destination, enter 0.0.0.0/0.
- For Target, select Internet Gateway, then select onprem-igw.
- Click Save changes.
What is an Internet Gateway?
An Internet Gateway connects a VPC to the public internet. By adding a route for 0.0.0.0/0 pointing to the IGW, any traffic destined for an IP outside the VPC gets forwarded to the internet.
The strongSwan instance needs this to establish IPsec tunnels with the AWS VPN endpoints, which have public IP addresses.
Launch the strongSwan instance with an Elastic IP
This EC2 instance will become your customer gateway device. It runs Ubuntu because the strongSwan VPN software is well-tested on Ubuntu, and AWS provides official configuration file downloads for this setup.
- First, allocate an Elastic IP. In the VPC console left navigation, click Elastic IPs.
- Click Allocate Elastic IP address.
- Keep the defaults and click Allocate.
- Note the allocated IP address. You will use this when creating the Customer Gateway in the next step.
Why an Elastic IP?
An Elastic IP is a static public IPv4 address that stays the same even if you stop and restart the instance. The Customer Gateway resource in AWS needs a fixed IP address to point to, so an Elastic IP ensures the VPN configuration remains valid.
Now launch the Ubuntu instance that will run strongSwan.
- Navigate to the EC2 console by typing EC2 in the top search bar.
- Click Launch instance.
- For Name, enter onprem-strongswan-instance.
- For Application and OS Images, click Ubuntu in the Quick Start section. Keep the default Ubuntu AMI.
- For Instance type, select t2.micro.
- For Key pair, select the same key pair you created earlier (vpn-project-key).
- Under Network settings, click Edit.
- For VPC, select onprem-vpc.
- For Subnet, select onprem-public-subnet.
- For Auto-assign public IP, select Disable. You will use the Elastic IP instead.
- Under Firewall (security groups), select Create security group. Name it onprem-strongswan-sg.
- Add an inbound rule: Type SSH, Source My IP. This allows you to SSH into the instance for configuration.
- Add another inbound rule: Type All ICMP - IPv4, Source 10.0.0.0/16. This allows ping from the Cloud VPC through the tunnel.
- Click Launch instance.
Now associate the Elastic IP with the new instance.
- Navigate back to the VPC console and click Elastic IPs in the left navigation.
- Select the Elastic IP you allocated earlier.
- Click Actions, then Associate Elastic IP address.
- For Instance, select onprem-strongswan-instance.
- Click Associate.
Don't see your instance in the dropdown?
Make sure the instance is in the Running state. It can take a minute or two after launch. Refresh the page and try again.
Also confirm you're in the same region where you launched the instance.
Help me associate my Elastic IP with my EC2 instance.
Verify your setup by navigating to the EC2 console and clicking Instances in the left navigation. You should see both cloud-test-instance and onprem-strongswan-instance in the Running state.
Your two networks are ready. Next up, you'll create the Virtual Private Gateway and Customer Gateway that form the AWS side of the VPN connection.
Create the Virtual Private Gateway and Customer Gateway
Your two VPCs are up and running with test instances in each. Now you need to build the bridge between them.
A Site-to-Site VPN requires three AWS components working together: a Virtual Private Gateway (VGW) on the AWS side, a Customer Gateway (CGW) resource pointing to your on-premises device, and a VPN connection tying them together. In this step, you will create all three and download the configuration file needed to set up the actual tunnel.
In this step, get ready to:
- Create a Virtual Private Gateway and attach it to your cloud VPC.
- Create a Customer Gateway resource pointing to your strongSwan instance.
- Create a Site-to-Site VPN connection with dynamic BGP routing and download the configuration file.
Create and attach the Virtual Private Gateway
The Virtual Private Gateway is the VPN concentrator on the AWS side of your connection. It attaches to your cloud VPC and handles all IPsec tunnel negotiation with your customer gateway device.
- In the AWS Console, open the VPC service.
- In the left navigation pane, choose Virtual private gateways.
- Click Create virtual private gateway.
- For Name tag, enter cloud-vgw.
- For Autonomous System Number (ASN), keep the default selection Amazon default ASN. This uses ASN 64512.
- Click Create virtual private gateway.
What is the Amazon default ASN?
An Autonomous System Number (ASN) identifies a network in BGP routing. AWS uses 64512 as the default private ASN for the VGW side. The on-premises side needs a different ASN so the two sides can distinguish each other during route exchanges.
Now attach the VGW to your cloud VPC.
- Select the cloud-vgw you just created.
- Click Actions, then choose Attach to VPC.
- For Available VPCs, select cloud-vpc.
- Click Attach to VPC.
The VGW state changes to Attached. This means the VPN concentrator is now live on the AWS side of your cloud VPC.
VGW stuck in Detached state?
Make sure you selected cloud-vpc (CIDR 10.0.0.0/16) and not the on-premises VPC. A VGW can only be attached to one VPC at a time.
If the Attach option is greyed out, check that the VGW state shows Available (not already attached elsewhere). Help me troubleshoot my VGW attachment
Create the Customer Gateway resource
The Customer Gateway resource is a pointer in AWS that represents your on-premises VPN device. It does not create any network path on its own. It simply tells AWS where to find your device (by IP address) and what BGP ASN your device uses.
- In the VPC console left navigation pane, choose Customer gateways.
- Click Create customer gateway.
- For Name tag, enter onprem-cgw.
- For BGP ASN, enter 65000. This is the ASN your strongSwan device will use.
- For IP address, enter the Elastic IP address you associated with your onprem-strongswan-instance in Step 1.
- Click Create customer gateway.
Where do I find my Elastic IP?
Switch to the EC2 console and select Elastic IPs in the left navigation. You will see the Elastic IP allocated in Step 1 with its associated instance listed. Copy the IPv4 address.
Alternatively, select your onprem-strongswan-instance in the EC2 Instances list. The Elastic IP address field in the instance details panel shows the value.
Why use ASN 65000 for the on-premises side?
AWS supports any ASN in the range 1 to 4,294,967,295 for a customer gateway. Private ASNs in the range 64,512 to 65,534 are commonly used for internal networks. You are using 65000 to keep it distinct from the VGW's Amazon default ASN of 64512. Both sides must have different ASNs for BGP peering to work.
Seeing an error when creating the Customer Gateway?
The most common issue is entering an invalid IP address. Double-check you are using the Elastic IP (the public address), not the private IP of the instance.
The IP address must be static and internet-routable. If you accidentally released your Elastic IP or it shows as unassociated, go back to Step 1 and allocate a new one. Help me fix my Customer Gateway creation error
Create the Site-to-Site VPN connection and download the configuration
The VPN connection ties the VGW and CGW together. AWS provisions two redundant IPsec tunnels automatically, each with its own outside public IP address and inside tunnel IP address for BGP peering.
- In the VPC console left navigation pane, choose Site-to-Site VPN connections.
- Click Create VPN connection.
- For Name tag, enter cloud-to-onprem-vpn.
- For Target gateway type, choose Virtual private gateway. Then select cloud-vgw from the dropdown.
- For Customer gateway, select Existing. Then choose onprem-cgw from the Customer gateway ID dropdown.
- For Routing options, choose Dynamic (requires BGP).
- Leave all other settings at their defaults.
- Click Create VPN connection.
It may take a few minutes for the VPN connection to be provisioned. Wait until the state shows Available.
Why two tunnels?
Each Site-to-Site VPN connection has two tunnels, each using a unique public IP address. This provides redundancy. If one tunnel goes down for maintenance or due to a failure, traffic automatically routes through the second tunnel.
Each tunnel has its own outside IP (the public endpoint), inside IP (the overlay address used for BGP peering), and pre-shared key for authentication. You will configure both in the next step.
Now download the configuration file you will use to set up strongSwan.
- Select your cloud-to-onprem-vpn connection.
- Click Download configuration.
- In the download dialog, set Vendor to Strongswan.
- Click Download. Save the file somewhere you can find it easily.
What is in the configuration file?
The downloaded file contains everything needed to configure your strongSwan customer gateway device:
- Pre-shared keys for authenticating each tunnel.
- Outside tunnel IP addresses (the public endpoints on the AWS side).
- Inside tunnel IP addresses (the /30 overlay addresses from the 169.254.0.0/16 range used for BGP peering).
- IKE and IPsec encryption settings (algorithms, DH groups, lifetimes).
Don't see Strongswan in the Vendor list?
Make sure you select the VPN connection first (checkbox on the left), then click Download configuration. The vendor list only appears after selecting a connection.
If Strongswan still does not appear, scroll through the vendor options. It may be listed as Strongswan (capital S). Help me find the strongSwan config download option
Your VPN infrastructure is now in place on the AWS side. Next up, you will SSH into your on-premises instance and configure strongSwan to bring these tunnels to life.
Configure strongSwan on the On-Premises EC2 Instance
You have all the AWS-side VPN components in place. The Virtual Private Gateway is attached, the Customer Gateway resource is created, and the VPN connection is provisioned with two tunnels. Now it is time to configure the actual VPN device.
In this step, you will turn your on-premises EC2 instance into a working customer gateway device by installing strongSwan for IPsec tunnels and FRRouting for BGP dynamic routing. Once configured, the tunnels will come up and routes will be exchanged automatically between both sides.
In this step, get ready to:
- Install strongSwan and FRRouting on your on-premises instance and disable source/destination checking.
- Configure the IPsec tunnels using settings from your downloaded VPN configuration file.
- Configure BGP peering via FRRouting and verify the session is established.
Install strongSwan, FRRouting, and disable source/destination checking
Before your EC2 instance can act as a VPN gateway, it needs the IPsec software to build encrypted tunnels and a routing daemon to exchange routes dynamically. It also needs an AWS-level setting changed so that it can forward traffic that is not addressed directly to it.
- SSH into your onprem-strongswan-instance using its Elastic IP.
- Update the package list and install strongSwan by running:
sudo apt update && sudo apt install strongswan -y
What is strongSwan?
strongSwan is open-source IPsec VPN software that handles the IKE negotiation and encrypted tunnel setup between your device and the AWS Virtual Private Gateway. AWS officially tests strongSwan configurations and provides downloadable config files for it.
- Install FRRouting for BGP support. Add the FRR repository and install the packages by running these commands:
curl -s https://deb.frrouting.org/frr/keys.gpg | sudo tee /usr/share/keyrings/frrouting.gpg > /dev/null
FRRVER="frr-stable"
echo deb '[signed-by=/usr/share/keyrings/frrouting.gpg]' https://deb.frrouting.org/frr $(lsb_release -s -c) $FRRVER | sudo tee -a /etc/apt/sources.list.d/frr.list
sudo apt update && sudo apt install frr frr-pythontools -y
Why FRRouting instead of Quagga?
FRRouting (FRR) is the actively maintained fork of Quagga. It provides production-grade BGP, OSPF, and IS-IS implementations with a Cisco-style CLI via vtysh. AWS sample architectures now reference FRR for BGP on Linux routers.
- Enable the BGP daemon in FRR by editing the daemons file:
sudo sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons
sudo systemctl restart frr
sudo systemctl enable frr
What does this command do?
FRR ships with all protocol daemons disabled except zebra. The sed command flips bgpd=no to bgpd=yes in /etc/frr/daemons, then the restart loads the BGP process.
- Enable IP forwarding so the instance can route traffic between networks:
sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sysctl -p
- Now disable source/destination checking on the instance in the AWS Console. Switch back to your browser with the AWS Console open.
- In the EC2 navigation pane, select Instances.
- Select your onprem-strongswan-instance.
- Click Actions, then Networking, then Change source/destination check.
- Select Stop for Source/destination checking.
- Click Save.
Why disable source/destination checking?
By default, EC2 drops any traffic where the instance is not the source or destination. Since your strongSwan instance will forward VPN traffic on behalf of other hosts in the on-premises network, this check must be disabled.
Without this change, the VPN tunnel will come up but traffic will be silently dropped.
Source/destination check option not appearing?
If the popup does not appear when you click the menu option, try selecting the instance's network interface directly. Go to Network Interfaces in the EC2 sidebar, select the ENI attached to your instance, then choose Actions and Change source/dest. check.
Help me disable source/destination checking
Configure the IPsec tunnels
Your downloaded VPN configuration file contains the pre-shared keys, tunnel outside IPs, and tunnel inside IPs that you need for this section. Open that file now and keep it visible.
- Switch back to your SSH session on the strongSwan instance.
- Open the IPsec configuration file for editing by running:
sudo nano /etc/ipsec.conf
- Replace the contents of the file with the following configuration. Substitute the placeholder values with the actual values from your downloaded VPN configuration file:
config setup
strictcrlpolicy=no
uniqueids=yes
conn Tunnel1
authby=secret
auto=start
left=%defaultroute
leftid=[[ONPREM_EIP="your on-premises Elastic IP"]]
right=[[TUNNEL1_OUTSIDE_IP="Tunnel 1 outside IP from VPN config file"]]
type=tunnel
leftsubnet=0.0.0.0/0
rightsubnet=0.0.0.0/0
ike=aes256-sha256-modp2048!
esp=aes256-sha256-modp2048!
keyexchange=ikev2
ikelifetime=28800s
lifetime=3600s
keyingtries=%forever
dpddelay=10s
dpdtimeout=30s
dpdaction=restart
mark=100
conn Tunnel2
authby=secret
auto=start
left=%defaultroute
leftid=[[ONPREM_EIP="your on-premises Elastic IP"]]
right=[[TUNNEL2_OUTSIDE_IP="Tunnel 2 outside IP from VPN config file"]]
type=tunnel
leftsubnet=0.0.0.0/0
rightsubnet=0.0.0.0/0
ike=aes256-sha256-modp2048!
esp=aes256-sha256-modp2048!
keyexchange=ikev2
ikelifetime=28800s
lifetime=3600s
keyingtries=%forever
dpddelay=10s
dpdtimeout=30s
dpdaction=restart
mark=200
What do these settings mean?
Each conn block defines one IPsec tunnel. left is your local side and right is the AWS VGW side. The ike and esp lines set the encryption algorithms: AES-256 for encryption, SHA-256 for integrity, and Diffie-Hellman group 14 (modp2048) for key exchange.
The keyexchange=ikev2 tells strongSwan to use IKE version 2 for negotiation. The ikelifetime=28800s (8 hours) and lifetime=3600s (1 hour) match AWS Phase 1 and Phase 2 defaults.
- Save and close the file (Ctrl+O, Enter, Ctrl+X in nano).
- Now configure the pre-shared keys. Open the secrets file by running:
sudo nano /etc/ipsec.secrets
- Add the following lines using the pre-shared keys from your downloaded VPN configuration file. Replace the placeholder IPs and keys with your actual values:
your-onprem-elastic-ip tunnel-1-outside-ip : PSK "your-tunnel-1-pre-shared-key"
your-onprem-elastic-ip tunnel-2-outside-ip : PSK "your-tunnel-2-pre-shared-key"
Where do I find these values?
In your downloaded VPN configuration file, look for the "IPSec Tunnel #1" and "IPSec Tunnel #2" sections. Each section lists the "Pre-Shared Key" value and the "Virtual Private Gateway" outside IP address. Use your Elastic IP as the first IP on each line.
- Save and close the file.
- Create the VTI (Virtual Tunnel Interface) for each tunnel. These interfaces carry the tunnel traffic and allow FRRouting to route over them. Run the following commands, replacing the placeholder IPs with values from your VPN configuration file:
# Create VTI for Tunnel 1
sudo ip link add Tunnel1 type vti local [[ONPREM_PRIVATE_IP="private IP of strongSwan instance"]] remote [[TUNNEL1_OUTSIDE_IP="Tunnel 1 outside IP"]] key 100
sudo ip addr add [[TUNNEL1_INSIDE_CGW_IP="Tunnel 1 inside IP for customer gateway (e.g. 169.254.x.x/30)"]] dev Tunnel1
sudo ip link set Tunnel1 up mtu 1419
# Create VTI for Tunnel 2
sudo ip link add Tunnel2 type vti local [[ONPREM_PRIVATE_IP="private IP of strongSwan instance"]] remote [[TUNNEL2_OUTSIDE_IP="Tunnel 2 outside IP"]] key 200
sudo ip addr add [[TUNNEL2_INSIDE_CGW_IP="Tunnel 2 inside IP for customer gateway (e.g. 169.254.x.x/30)"]] dev Tunnel2
sudo ip link set Tunnel2 up mtu 1419
What are VTI interfaces?
Virtual Tunnel Interfaces create a routable interface for each IPsec tunnel. The inside IP addresses (from the 169.254.0.0/16 range in your config file) are what BGP uses for peering. The key value must match the mark value in your ipsec.conf (100 for Tunnel1, 200 for Tunnel2).
- Disable reverse path filtering on the tunnel interfaces so traffic is not dropped:
sudo sysctl -w net.ipv4.conf.Tunnel1.rp_filter=0
sudo sysctl -w net.ipv4.conf.Tunnel2.rp_filter=0
sudo sysctl -w net.ipv4.conf.Tunnel1.disable_policy=1
sudo sysctl -w net.ipv4.conf.Tunnel2.disable_policy=1
- Start the strongSwan service to bring up the IPsec tunnels by running:
sudo ipsec restart
- Verify the tunnels are connecting by running:
sudo ipsec status
You should see both Tunnel1 and Tunnel2 listed. They may show as CONNECTING or ESTABLISHED. It is normal for one tunnel to take a minute to come up.
Tunnels stuck in CONNECTING state?
Double-check that the leftid in ipsec.conf matches your Elastic IP exactly, and that the right value matches the VGW's outside tunnel IP from your downloaded configuration file.
Also confirm your security group allows inbound UDP port 500 and UDP port 4500 from all sources (0.0.0.0/0). These ports are required for IKE negotiation and NAT traversal.
Help me troubleshoot my stuck IPsec tunnels
Configure BGP using FRRouting
The IPsec tunnels provide the encrypted path. Now you need BGP to dynamically exchange routes over those tunnels so each side knows how to reach the other network.
- Enter the FRRouting CLI by running:
sudo vtysh
- Enter configuration mode and set up BGP peering with the VGW. Replace the tunnel inside IP placeholders with the VGW-side inside IPs from your downloaded configuration file:
configure terminal
router bgp 65000
bgp router-id [[ONPREM_PRIVATE_IP="private IP of your strongSwan instance"]]
neighbor [[TUNNEL1_INSIDE_VGW_IP="Tunnel 1 VGW inside IP (e.g. 169.254.x.x)"]] remote-as 64512
neighbor [[TUNNEL2_INSIDE_VGW_IP="Tunnel 2 VGW inside IP (e.g. 169.254.x.x)"]] remote-as 64512
address-family ipv4 unicast
network 192.168.0.0/16
neighbor [[TUNNEL1_INSIDE_VGW_IP="Tunnel 1 VGW inside IP"]] activate
neighbor [[TUNNEL2_INSIDE_VGW_IP="Tunnel 2 VGW inside IP"]] activate
exit-address-family
exit
write memory
What does this BGP configuration do?
The router bgp 65000 line starts the BGP process using ASN 65000, which matches the ASN you specified when creating the Customer Gateway resource. The neighbor lines define the VGW as a peer using ASN 64512 (the Amazon default ASN).
The network 192.168.0.0/16 statement advertises the on-premises CIDR to the VGW. This tells AWS "to reach 192.168.0.0/16, send traffic through this VPN tunnel." The write memory command saves the configuration so it persists across restarts.
- Verify the BGP session status. Still inside vtysh, run:
show ip bgp summary
In the State/PfxRcd column, look for a number (like 1 or 2) next to at least one neighbor. A number means the session is Established and that many prefixes were received from the VGW.
If you see Active or Connect, wait 30-60 seconds and run the command again.
- Exit vtysh by typing:
exit
BGP neighbor stuck in Active state?
The most common cause is that the IPsec tunnel is not fully up. Run sudo ipsec status and confirm at least one tunnel shows ESTABLISHED before troubleshooting BGP.
Also verify the neighbor IP addresses are the VGW-side inside IPs (not the CGW-side IPs). Your downloaded config file lists both. The VGW-side IP is the one labeled as the "Virtual Private Gateway" inside address.
Help me troubleshoot my BGP peering issue
Your VPN tunnel is up and BGP is exchanging routes between the on-premises network and the AWS cloud. Next, you will configure the routing on both sides and verify end-to-end connectivity through the encrypted tunnel.
Configure Routing and Verify Connectivity
Your strongSwan instance is running and BGP sessions are established with the Virtual Private Gateway. The tunnels are up, but traffic still cannot flow between the two networks.
The missing piece is routing. Each VPC's route table needs to know how to forward traffic destined for the other network. In this step, you will enable route propagation so the cloud VPC automatically learns on-premises routes via BGP, add a static route in the on-premises VPC pointing back to the cloud, and then verify end-to-end encrypted connectivity.
In this step, get ready to:
- Enable route propagation on the cloud VPC route table.
- Add a static route in the on-premises VPC route table.
- Verify bidirectional connectivity through the VPN tunnel.
Enable route propagation on the cloud VPC route table
Route propagation allows a Virtual Private Gateway to automatically add routes it learns via BGP into your VPC route table. Without it, the cloud VPC has no idea that 192.168.0.0/16 exists on the other side of the tunnel.
- In the AWS Console, navigate to VPC and select Route tables in the left navigation pane.
- Find and select the route table associated with cloud-private-subnet (the main route table of cloud-vpc).
- Choose Actions, then Edit route propagation.
- Select the Enable checkbox next to cloud-vgw (your Virtual Private Gateway).
- Click Save.
What does route propagation do?
When you enable route propagation, the VGW automatically injects routes learned from BGP into the route table. Since your strongSwan instance is advertising 192.168.0.0/16 via BGP, this route appears in the cloud VPC route table with the VGW as the target.
You no longer need to manually maintain routes for VPN connections. As the on-premises network changes, BGP updates propagate automatically.
- Select the Routes tab on the same route table.
- Confirm you see a route with destination 192.168.0.0/16 and target cloud-vgw. The source column should show Propagated.
Don't see the propagated route?
Make sure the VPN tunnel status is UP and that BGP is in the Established state on your strongSwan instance. The route only propagates when the VPN connection status is UP.
Also verify you enabled propagation on the correct route table. The route table must be the one explicitly associated with cloud-private-subnet, not a different route table in the VPC.
Help me troubleshoot why my propagated route isn't appearing in the cloud VPC route table.
Add a route in the on-premises VPC route table
The on-premises VPC needs to know that traffic destined for 10.0.0.0/16 (the cloud VPC) should be sent through the strongSwan instance, which acts as the VPN gateway.
- In the Route tables section of the VPC console, select the route table associated with onprem-public-subnet.
- Select the Routes tab, then click Edit routes.
- Click Add route.
- For Destination, enter 10.0.0.0/16.
- For Target, select Instance, then choose onprem-strongswan-instance from the dropdown.
- Click Save changes.
Why a static route here instead of propagation?
The on-premises VPC does not have a VGW attached. It uses the strongSwan EC2 instance as its gateway device. Since there is no VGW on this side, route propagation is not available.
Instead, you add a static route that tells the route table to forward cloud-bound traffic (10.0.0.0/16) to the strongSwan instance's network interface. The instance then encrypts and tunnels it to the VGW.
Verify VPN status and bidirectional connectivity
Both route tables are now configured. Before testing connectivity, you need to ensure the security groups on both instances allow ICMP traffic (which is what ping uses).
- Navigate to EC2 in the AWS Console, then select Security Groups in the left navigation pane.
- Find the security group associated with cloud-test-instance and select it.
- Click Edit inbound rules.
- Click Add rule. For Type, select All ICMP - IPv4. For Source, enter 192.168.0.0/16.
- Add another rule. For Type, select SSH. For Source, enter 192.168.0.0/16.
- Click Save rules.
- Now find the security group associated with onprem-strongswan-instance and select it.
- Click Edit inbound rules.
- Click Add rule. For Type, select All ICMP - IPv4. For Source, enter 10.0.0.0/16.
- Click Save rules.
Now verify the VPN connection status in the console.
- Navigate to VPC, then select Site-to-Site VPN connections in the left navigation pane.
- Select cloud-to-onprem-vpn.
- Click the Tunnel details tab. Confirm that at least one tunnel shows a status of UP.
Now test connectivity from the on-premises side first.
- SSH into your on-premises instance by running this command (replace the Elastic IP with your own):
ssh -A -i [[PEMPATH="path to your .pem key file"]] ubuntu@[[ONPREM_EIP="your on-premises instance Elastic IP"]]
What does the -A flag do?
The -A flag enables SSH agent forwarding. This forwards your local SSH key through the on-premises instance so you can SSH into the cloud instance (through the VPN tunnel) without copying your key file onto the on-premises machine.
- From the on-premises instance, ping the cloud-test-instance using its private IP address:
ping -c 4 [[CLOUD_PRIVATE_IP="private IP of cloud-test-instance (e.g. 10.0.1.x)"]]
What should I see?
You should see four successful ICMP replies with round-trip times. The output looks similar to:
PING 10.0.1.x (10.0.1.x) 56(84) bytes of data.
64 bytes from 10.0.1.x: icmp_seq=1 ttl=254 time=5.23 ms
64 bytes from 10.0.1.x: icmp_seq=2 ttl=254 time=4.89 ms
...
4 packets transmitted, 4 received, 0% packet loss
If you see replies, traffic is flowing from the on-premises network through the IPsec tunnel to the cloud VPC. The latency is slightly higher than normal EC2-to-EC2 because the traffic is encrypted and routed through the VPN tunnel.
Now verify the reverse direction by connecting to the cloud instance through the VPN tunnel.
- From the on-premises instance, SSH to the cloud instance through the VPN:
ssh ec2-user@[[CLOUD_PRIVATE_IP="private IP of cloud-test-instance (e.g. 10.0.1.x)"]]
- From the cloud instance, ping the on-premises instance using its private IP:
ping -c 4 [[ONPREM_PRIVATE_IP="private IP of onprem-strongswan-instance (e.g. 192.168.1.x)"]]
You should see four successful ICMP replies, confirming bidirectional connectivity through the encrypted VPN tunnel.
- Type exit to return to the on-premises instance.
Ping not getting replies?
Check that the security groups on both instances allow All ICMP - IPv4 from the other VPC's CIDR range. Missing ICMP rules are the most common cause of failed pings.
If SSH to the cloud instance fails, verify the cloud instance's security group has an inbound SSH rule with source 192.168.0.0/16. Also confirm the on-premises route table has the 10.0.0.0/16 route targeting the strongSwan instance.
If you see Destination Host Unreachable, the issue is likely routing. Double-check both route tables and confirm the VPN tunnel status is UP.
Help me troubleshoot why my ping across the VPN tunnel is failing.
Your VPN is fully operational. Traffic between the two VPCs is encrypted, tunneled through IPsec, and routed dynamically via BGP. Next up, you will explore the tunnel details and exam-relevant concepts hiding inside this architecture.
Explore VPN Tunnel Details and Exam Concepts
Your VPN is live. Traffic is flowing securely between your cloud VPC and on-premises VPC through encrypted IPsec tunnels.
In this step, you will inspect the tunnel architecture that AWS provisions behind the scenes and test the redundancy model that makes Site-to-Site VPN connections highly available. These details appear frequently on the SAA-C03 exam.
In this step, get ready to:
- Examine VPN tunnel details including IKE versions, encryption algorithms, and Phase 1/2 lifetimes.
- Test tunnel failover by bringing down one tunnel and confirming traffic routes through the other.
- Review key exam concepts: VGW as concentrator, CGW as pointer, SA pairs, and route-based VPN.
Examine VPN connection tunnel details
AWS provisions two tunnels for every Site-to-Site VPN connection. Each tunnel has its own public IP address, encryption settings, and IKE negotiation parameters.
- Return to the AWS VPC Console.
- In the left navigation pane, click Site-to-Site VPN connections.
- Select your VPN connection (cloud-to-onprem-vpn).
- Click the Tunnel details tab.
You should see two tunnels listed, each with a unique Outside IP address. At least one tunnel shows a status of UP.
- Note the Outside IP address for each tunnel. These are the public endpoints that your customer gateway device connects to.
- Click on a tunnel row to expand its details, or select the VPN connection and click Tunnel options to view the full configuration.
- Examine the following settings for each tunnel:
What do these settings mean?
IKE (Internet Key Exchange) negotiation happens in two phases. Phase 1 establishes the IKE Security Association (SA) between the two endpoints. It authenticates both sides and agrees on encryption parameters.
Phase 2 creates the IPsec SA that encrypts the actual data traffic. Phase 2 lifetime (3,600 seconds) must always be less than Phase 1 lifetime (28,800 seconds). When Phase 2 expires, the tunnel renegotiates new keys without dropping the IKE SA.
Why two tunnels per connection?
AWS always provisions two tunnels with separate public IP addresses. If one tunnel goes down for maintenance or failure, traffic automatically routes to the other. This built-in redundancy means you never lose connectivity due to a single tunnel failure.
Test tunnel failover
The two-tunnel architecture is more than a configuration detail. You can prove it works by deliberately taking down one tunnel and confirming that traffic continues flowing through the other.
- First, identify which tunnel is currently active. In the Tunnel details tab, note which tunnel shows status UP. Record which one is Tunnel 1 (the first tunnel you configured in strongSwan).
- SSH into your on-premises strongSwan instance.
- Check the current strongSwan tunnel status by running:
sudo ipsec status
You should see both tunnel connections listed with their SA details.
- Bring down the first tunnel connection by running the following command (replace Tunnel1 with the connection name you used in your strongSwan configuration):
sudo ipsec down Tunnel1
What is this command doing?
The ipsec down command tells the strongSwan IKE daemon to terminate a specific connection. This tears down the IKE SA and IPsec SA for that tunnel, simulating a tunnel failure.
- Switch back to the AWS Console. In the Tunnel details tab, refresh the page. After a minute or two, Tunnel 1 should show status DOWN while Tunnel 2 remains UP.
- Now test connectivity through the remaining tunnel. From your cloud-test-instance (via Session Manager or a bastion), ping the on-premises instance private IP:
ping 192.168.1.x -c 4
Replace 192.168.1.x with your on-premises instance's actual private IP. You should still receive successful ping replies.
Traffic is now flowing exclusively through Tunnel 2. This proves the AWS redundancy model works as designed.
- Bring the first tunnel back up by running:
sudo ipsec up Tunnel1
Tunnel not showing DOWN in the console?
AWS can take 1-2 minutes to detect a tunnel is down. Refresh the Tunnel details tab after waiting. If Tunnel 1 still shows UP, verify you used the correct connection name from your strongSwan configuration.
Run sudo ipsec status to confirm the connection was actually terminated on your instance.
Help me troubleshoot why my VPN tunnel status isn't updating in the AWS Console after I ran ipsec down.
Review key exam concepts in context
Now that you have a working VPN with tested failover, let's map what you built to the concepts the SAA-C03 exam tests.
What is the Virtual Private Gateway?
A Virtual Private Gateway (VGW) is the VPN concentrator on the Amazon side of the Site-to-Site VPN connection. It handles all the IKE negotiation and IPsec encryption on behalf of your VPC. There is no separate charge for running a VGW.
In your project, cloud-vgw is attached to your cloud-vpc. It manages both tunnels and propagates routes learned via BGP into your route table.
What is the Customer Gateway resource?
The Customer Gateway (CGW) resource in AWS is just a pointer. It tells AWS the public IP address and BGP ASN of your on-premises device. It does not do any actual VPN processing.
The real work happens on your customer gateway device (in this project, the strongSwan EC2 instance). The CGW resource simply identifies where that device lives on the internet.
How many Security Associations does each tunnel have?
Each tunnel has one IKE SA (Phase 1) and one IPsec SA pair (Phase 2). The IPsec SA pair consists of one inbound SA and one outbound SA. With two tunnels per VPN connection, you have two unique SA pairs total (four SAs).
This is a common exam question. Remember: one IKE SA plus one IPsec SA pair per tunnel, two tunnels per connection.
What is route-based vs policy-based VPN?
AWS Site-to-Site VPN is a route-based solution. Traffic is routed into the tunnel based on route table entries, not on security policies matching source/destination pairs.
If you are using a policy-based VPN device, you must limit your configuration to a single security association (SA) per tunnel. This is because policy-based devices create one SA per policy rule, which conflicts with AWS expecting a single SA pair. This limitation is heavily tested on the exam.
- Review the summary of what you proved in this step:
Extra for Experts: Why does VGW throughput cap at 1.25 Gbps?
VPN throughput to a VGW is limited to 1.25 Gbps per tunnel, and ECMP (Equal-Cost Multi-Path) load balancing across tunnels is not supported with VGW. If you need higher throughput or ECMP, you must use a Transit Gateway instead. This architectural limit is why large-scale hybrid networks use TGW over VGW.
Secret mission
Add Redundant Customer Gateway for Failover
Your VPN has two tunnels for redundancy, but they both terminate on a single customer gateway device. What happens if that device fails? In this mission, you'll deploy a second strongSwan instance and VPN connection to protect against on-premises device failure.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses paid AWS resources that incur hourly charges, so leaving them running will cost money.
Cost warning
Your Site-to-Site VPN connections cost $0.05 per connection-hour each. With two VPN connections, that is $0.10/hr in VPN charges alone.
You also have public IPv4 address charges at $0.005 per IP per hour. Each VPN connection has 4 tunnel IPs, plus your 2 Elastic IPs. That adds approximately $0.05/hr in IP charges. The total cost of leaving everything running is roughly $0.15/hr or $3.60/day.
Resources you used:
- Site-to-Site VPN connection: cloud-to-onprem-vpn ($0.05/hr).
- Site-to-Site VPN connection: cloud-to-onprem-vpn-2 ($0.05/hr).
- Virtual Private Gateway: cloud-vgw (no charge for the VGW itself).
- Customer Gateway resources: onprem-cgw and onprem-cgw-2 (no direct charge).
- EC2 instances: cloud-test-instance, onprem-strongswan-instance, onprem-strongswan-instance-2 (t2.micro, free tier eligible if within first 12 months).
- Elastic IPs: 2 allocated ($0.005/hr each).
- VPCs: cloud-vpc and onprem-vpc (with associated subnets, route tables, and internet gateway).
Keep everything running
No action needed. Choose this if you are still actively experimenting with your VPN architecture or plan to continue building on it immediately.
- Your two VPN connections will continue costing approximately $0.10/hr combined.
- Public IPv4 charges for tunnel IPs and Elastic IPs add approximately $0.05/hr.
- EC2 instances continue running (free tier eligible for t2.micro if within your first 12 months).
- Note that onprem-strongswan-instance is currently stopped from the failover test. Start it again if you want both VPN connections active.
Pause - I'll come back to this later
Stop the EC2 instances to save compute costs. Note that VPN connection charges and Elastic IP charges continue even when instances are stopped.
- In the EC2 console, select cloud-test-instance, onprem-strongswan-instance, and onprem-strongswan-instance-2.
- Click Instance state, then Stop instance.
- Your VPN tunnels will go down when the strongSwan instances stop. The VPN connections remain in the "available" state and continue billing at $0.05/hr each.
- Elastic IPs remain allocated and continue billing at $0.005/hr each (whether associated with a running instance or not).
- When you return, start the instances and restart the strongSwan and FRRouting services to re-establish the tunnels.
Delete - I don't want to use this again
Remove all project resources to stop all charges. Follow these steps in order because some resources depend on others.
Delete the VPN connections first:
- In the VPC console, go to Site-to-Site VPN Connections in the left sidebar.
- Select cloud-to-onprem-vpn.
- Click Actions, then Delete VPN connection. Confirm the deletion.
- Repeat for cloud-to-onprem-vpn-2.
- Wait for both connections to show a state of Deleted before proceeding.
Detach and delete the Virtual Private Gateway:
- In the VPC console, go to Virtual private gateways in the left sidebar.
- Select cloud-vgw.
- Click Actions, then Detach from VPC. Confirm.
- Once detached, click Actions, then Delete virtual private gateway. Confirm.
Delete the Customer Gateway resources:
- In the VPC console, go to Customer gateways in the left sidebar.
- Select onprem-cgw.
- Click Actions, then Delete customer gateway. Confirm.
- Repeat for onprem-cgw-2.
Terminate the EC2 instances:
- In the EC2 console, go to Instances.
- Select all three instances: cloud-test-instance, onprem-strongswan-instance, and onprem-strongswan-instance-2.
- Click Instance state, then Terminate instance. Confirm.
Release the Elastic IPs:
- In the EC2 console, go to Elastic IPs under Network & Security in the left sidebar.
- Select both Elastic IPs you allocated for this project.
- Click Actions, then Release Elastic IP addresses. Confirm.
Delete both VPCs:
- In the VPC console, go to Your VPCs.
- Select cloud-vpc.
- Click Actions, then Delete VPC. This will also delete associated subnets and route tables. Confirm.
- Repeat for onprem-vpc. This will also remove the internet gateway, subnets, and route tables.
All charges will stop once these resources are fully deleted.
Nice Work!
Nice Work!
You've just built a production-grade hybrid connectivity architecture from scratch. Your two VPCs are now securely connected over encrypted IPsec tunnels, with BGP dynamic routing handling path selection automatically.
You've learned how to:
- Built a complete Site-to-Site VPN connection using a Virtual Private Gateway, Customer Gateway, and IPsec tunnels with IKE negotiation and pre-shared key authentication.
- Configured a customer gateway device running strongSwan with BGP dynamic routing via FRRouting, and enabled route propagation on the cloud VPC route table.
- Tested the two-tunnel redundancy model by verifying tunnel failover and understanding the IKE/IPsec security association pairs that secure each tunnel.
- Deployed a redundant customer gateway for on-premises device failover, proving that traffic continues without interruption when a VPN device goes down.
Ready to quiz yourself?