Site to Site AWS VPN – Using Only Windows Servers

Introduction

Do you rely solely on Windows servers in your environment and lack access to third-party networking equipment? Are you looking to establish a site-to-site VPN connection to your AWS environment but unsure how to do so with your existing setup? If so, fear not, because it’s possible to achieve this with just a Windows Server acting as a router. In this blog post, we’ll guide you through the steps needed to establish a secure connection between your LAN and AWS, enabling bidirectional communication between your servers and the cloud platform.

Prerequisites

  • Windows Server to be used as a router
    • I am using Server Operating System 2019
  • An AWS account
  • An AWS IAM object with adequate rights
  • An AWS VPC with an EC2 instance for testing connectivity
    • I am using Terraform to create all AWS objects

AWS Tasks

Create VPC

resource "aws_vpc" "vpc" {
    cidr_block = "192.168.0.0/16"
}

Create Subnets

#Private Subnet in AZ-A
resource "aws_subnet" "prisub1" {
cidr_block = 192.168.0.0/24
vpc_id = aws_vpc.vpc.id
availability_zone = data.aws_availability_zones.available.names[0]
}

#Private Subnet in AZ-B
resource "aws_subnet" "prisub2" {
cidr_block = 192.168.1.0/24
vpc_id = aws_vpc.vpc.id
availability_zone = data.aws_availability_zones.available.names[1]
}

Create and Attach Route Table

resource "aws_route_table" "routetableprivate" {
vpc_id = aws_vpc.vpc.id
}

resource "aws_route_table_association" "prisub1" {
subnet_id = aws_subnet.prisub1.id
route_table_id = aws_route_table.routetableprivate.id
}

resource "aws_route_table_association" "prisub2" {
subnet_id = aws_subnet.prisub2.id
route_table_id = aws_route_table.routetableprivate.id
}

resource "aws_vpn_gateway_route_propagation" "routepropagation" {
  vpn_gateway_id = aws_vpn_gateway.vgw.id
  route_table_id = aws_route_table.routetableprivate.id
}
# this will enable routing to on-premise CIDR via propagation upon successful connection to the VPN

Create and Attach Virtual Private Gateway

resource "aws_vpn_gateway" "vgw" {
vpc_id = aws_vpc.vpc.id
}

resource "aws_vpn_gateway_attachment" "vgw_attachment" {
  vpc_id         = aws_vpc.vpc.id
  vpn_gateway_id = aws_vpn_gateway.vgw.id
}

Create Customer Gateway

resource "aws_customer_gateway" "cgw" {
  bgp_asn    = 65000
  ip_address = "20.85.247.126" #this is your public IP address you will obtain from your Windows Server 
  type       = "ipsec.1"
}

Create Site to Site VPN

resource "aws_vpn_connection" "vpn" {
  vpn_gateway_id      = aws_vpn_gateway.vgw.id
  customer_gateway_id = aws_customer_gateway.cgw.id
  type                = "ipsec.1"
  static_routes_only  = true
  tunnel1_preshared_key = "abc123xyz987" 
  #this can be anything you want and will be used when configuring the VPN on the Windows Server
}

resource "aws_vpn_connection_route" "remote" {
  destination_cidr_block = "10.0.0.0/24" #this is your LAN CIDR where your Windows Server sits
  vpn_connection_id      = aws_vpn_connection.vpn.id
}

output "tunnel1IP" {
  value = aws_vpn_connection.vpn.tunnel1_address
  #this will be the AWS gateway which will be used when configuring the VPN on the Windows Server
}

Create Test EC2

data "aws_ssm_parameter" "linux" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}

resource "aws_security_group" "sg-private" {
  name        = "allow_onprem"
  vpc_id      = aws_vpc.vpc.id

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["10.0.0.0/24"]
  }
  
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "privateLinux" {
    ami = "${data.aws_ssm_parameter.linux.value}"
    instance_type = "t3.medium"
    subnet_id = aws_subnet.prisub1.id
    vpc_security_group_ids = [aws_security_group.sg-private.id]
}

output "privateLinuxIP" {
    value = aws_instance.privateLinux.private_ip
}

Windows Server Tasks

These tasks can be done via PowerShell.

Install Routing Services

Install-WindowsFeature -Name Routing -IncludeManagementTools

Install-RemoteAccess -VpnType VpnS2S

$tunnel1IP = <input the tunnel IP address terraform outputs>
$psk = 'abc123xyz987'
Add-VpnS2SInterface -Name AWS1 -Destination $tunnel1IP -Protocol IKEv2 -AuthenticationMethod PSKOnly -SharedSecret $psk -IPv4Subnet 192.168.0.0/16:100

restart-service RemoteAccess; start-sleep 15; Connect-VpnS2SInterface -Name AWS1 -PassThru

Install and Configure Remote Access with IPSec

Install-RemoteAccess -VpnType VpnS2S

$tunnel1IP = <input the tunnel IP address terraform outputs>
$psk = 'abc123xyz987'
Add-VpnS2SInterface -Name AWS1 -Destination $tunnel1IP -Protocol IKEv2 -AuthenticationMethod PSKOnly -SharedSecret $psk -IPv4Subnet 192.168.0.0/16:100

restart-service RemoteAccess; start-sleep 15; Connect-VpnS2SInterface -Name AWS1 -PassThru

Verification

As AWS never initiates a connection, you will have to initiate the connection over the Site to Site VPN. An easy way to achieve this is by pinging the test AWS instance we created via Terraform. The private IP address for the EC2 instance has been outputted when running Terraform.

ping a.b.c.d -t #continuous ping; replace a.b.c.d with the private IP address of the test EC2 instance

Confirm Inbound and Outbound connection

Get-NetIPsecQuickModeSA

You should see both, Inbound and Outbound connections from your server to AWS.

To take this one step further, you can set the default gateway for other machines in your LAN to the IP Address of your Windows Server acting as a router to AWS so that you can communicate from our LAN servers to AWS, and vice versa.

Conclusion

With Windows Server Operating Systems, establishing a Site to Site IPSec VPN tunnel to AWS is easy and allows you to efficiently direct traffic through a Windows Server functioning as a router. This solution is ideal for creating a fast and straightforward lab environment that allows you to test Site to Site VPN connectivity and dependencies that rely on a Site to Site VPN connection.

Leave a Comment

Your email address will not be published. Required fields are marked *