The aws:ec2/vpnConnection:VpnConnection resource, part of the Pulumi AWS provider, establishes IPsec VPN tunnels between AWS and on-premises networks. This guide focuses on three connection configurations: Transit Gateway attachment for hub-and-spoke topologies, Virtual Private Gateway attachment for single-VPC connectivity, and private VPN routing over Direct Connect.
VPN connections require Customer Gateways representing on-premises endpoints and either a Transit Gateway or Virtual Private Gateway on the AWS side. The examples are intentionally small. Combine them with your own gateway infrastructure, routing configuration, and tunnel parameters.
Connect on-premises networks via Transit Gateway
Organizations building hub-and-spoke network topologies use Transit Gateway to centralize VPN connections, allowing multiple VPCs to share a single VPN connection to on-premises infrastructure.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.ec2transitgateway.TransitGateway("example", {});
const exampleCustomerGateway = new aws.ec2.CustomerGateway("example", {
bgpAsn: "65000",
ipAddress: "172.0.0.1",
type: "ipsec.1",
});
const exampleVpnConnection = new aws.ec2.VpnConnection("example", {
customerGatewayId: exampleCustomerGateway.id,
transitGatewayId: example.id,
type: exampleCustomerGateway.type,
});
import pulumi
import pulumi_aws as aws
example = aws.ec2transitgateway.TransitGateway("example")
example_customer_gateway = aws.ec2.CustomerGateway("example",
bgp_asn="65000",
ip_address="172.0.0.1",
type="ipsec.1")
example_vpn_connection = aws.ec2.VpnConnection("example",
customer_gateway_id=example_customer_gateway.id,
transit_gateway_id=example.id,
type=example_customer_gateway.type)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2transitgateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := ec2transitgateway.NewTransitGateway(ctx, "example", nil)
if err != nil {
return err
}
exampleCustomerGateway, err := ec2.NewCustomerGateway(ctx, "example", &ec2.CustomerGatewayArgs{
BgpAsn: pulumi.String("65000"),
IpAddress: pulumi.String("172.0.0.1"),
Type: pulumi.String("ipsec.1"),
})
if err != nil {
return err
}
_, err = ec2.NewVpnConnection(ctx, "example", &ec2.VpnConnectionArgs{
CustomerGatewayId: exampleCustomerGateway.ID(),
TransitGatewayId: example.ID(),
Type: exampleCustomerGateway.Type,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Ec2TransitGateway.TransitGateway("example");
var exampleCustomerGateway = new Aws.Ec2.CustomerGateway("example", new()
{
BgpAsn = "65000",
IpAddress = "172.0.0.1",
Type = "ipsec.1",
});
var exampleVpnConnection = new Aws.Ec2.VpnConnection("example", new()
{
CustomerGatewayId = exampleCustomerGateway.Id,
TransitGatewayId = example.Id,
Type = exampleCustomerGateway.Type,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2transitgateway.TransitGateway;
import com.pulumi.aws.ec2.CustomerGateway;
import com.pulumi.aws.ec2.CustomerGatewayArgs;
import com.pulumi.aws.ec2.VpnConnection;
import com.pulumi.aws.ec2.VpnConnectionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new TransitGateway("example");
var exampleCustomerGateway = new CustomerGateway("exampleCustomerGateway", CustomerGatewayArgs.builder()
.bgpAsn("65000")
.ipAddress("172.0.0.1")
.type("ipsec.1")
.build());
var exampleVpnConnection = new VpnConnection("exampleVpnConnection", VpnConnectionArgs.builder()
.customerGatewayId(exampleCustomerGateway.id())
.transitGatewayId(example.id())
.type(exampleCustomerGateway.type())
.build());
}
}
resources:
example:
type: aws:ec2transitgateway:TransitGateway
exampleCustomerGateway:
type: aws:ec2:CustomerGateway
name: example
properties:
bgpAsn: 65000
ipAddress: 172.0.0.1
type: ipsec.1
exampleVpnConnection:
type: aws:ec2:VpnConnection
name: example
properties:
customerGatewayId: ${exampleCustomerGateway.id}
transitGatewayId: ${example.id}
type: ${exampleCustomerGateway.type}
The connection links your Customer Gateway to a Transit Gateway using the customerGatewayId and transitGatewayId properties. The type property must be “ipsec.1”, the only VPN type AWS currently supports. Transit Gateway automatically propagates routes to attached VPCs, enabling centralized connectivity.
Attach VPN to a single VPC with static routes
Single-VPC deployments often attach VPN connections directly to a Virtual Private Gateway, particularly when the on-premises device doesn’t support BGP dynamic routing.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const vpc = new aws.ec2.Vpc("vpc", {cidrBlock: "10.0.0.0/16"});
const vpnGateway = new aws.ec2.VpnGateway("vpn_gateway", {vpcId: vpc.id});
const customerGateway = new aws.ec2.CustomerGateway("customer_gateway", {
bgpAsn: "65000",
ipAddress: "172.0.0.1",
type: "ipsec.1",
});
const main = new aws.ec2.VpnConnection("main", {
vpnGatewayId: vpnGateway.id,
customerGatewayId: customerGateway.id,
type: "ipsec.1",
staticRoutesOnly: true,
});
import pulumi
import pulumi_aws as aws
vpc = aws.ec2.Vpc("vpc", cidr_block="10.0.0.0/16")
vpn_gateway = aws.ec2.VpnGateway("vpn_gateway", vpc_id=vpc.id)
customer_gateway = aws.ec2.CustomerGateway("customer_gateway",
bgp_asn="65000",
ip_address="172.0.0.1",
type="ipsec.1")
main = aws.ec2.VpnConnection("main",
vpn_gateway_id=vpn_gateway.id,
customer_gateway_id=customer_gateway.id,
type="ipsec.1",
static_routes_only=True)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
vpc, err := ec2.NewVpc(ctx, "vpc", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
vpnGateway, err := ec2.NewVpnGateway(ctx, "vpn_gateway", &ec2.VpnGatewayArgs{
VpcId: vpc.ID(),
})
if err != nil {
return err
}
customerGateway, err := ec2.NewCustomerGateway(ctx, "customer_gateway", &ec2.CustomerGatewayArgs{
BgpAsn: pulumi.String("65000"),
IpAddress: pulumi.String("172.0.0.1"),
Type: pulumi.String("ipsec.1"),
})
if err != nil {
return err
}
_, err = ec2.NewVpnConnection(ctx, "main", &ec2.VpnConnectionArgs{
VpnGatewayId: vpnGateway.ID(),
CustomerGatewayId: customerGateway.ID(),
Type: pulumi.String("ipsec.1"),
StaticRoutesOnly: pulumi.Bool(true),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var vpc = new Aws.Ec2.Vpc("vpc", new()
{
CidrBlock = "10.0.0.0/16",
});
var vpnGateway = new Aws.Ec2.VpnGateway("vpn_gateway", new()
{
VpcId = vpc.Id,
});
var customerGateway = new Aws.Ec2.CustomerGateway("customer_gateway", new()
{
BgpAsn = "65000",
IpAddress = "172.0.0.1",
Type = "ipsec.1",
});
var main = new Aws.Ec2.VpnConnection("main", new()
{
VpnGatewayId = vpnGateway.Id,
CustomerGatewayId = customerGateway.Id,
Type = "ipsec.1",
StaticRoutesOnly = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.VpnGateway;
import com.pulumi.aws.ec2.VpnGatewayArgs;
import com.pulumi.aws.ec2.CustomerGateway;
import com.pulumi.aws.ec2.CustomerGatewayArgs;
import com.pulumi.aws.ec2.VpnConnection;
import com.pulumi.aws.ec2.VpnConnectionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var vpc = new Vpc("vpc", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var vpnGateway = new VpnGateway("vpnGateway", VpnGatewayArgs.builder()
.vpcId(vpc.id())
.build());
var customerGateway = new CustomerGateway("customerGateway", CustomerGatewayArgs.builder()
.bgpAsn("65000")
.ipAddress("172.0.0.1")
.type("ipsec.1")
.build());
var main = new VpnConnection("main", VpnConnectionArgs.builder()
.vpnGatewayId(vpnGateway.id())
.customerGatewayId(customerGateway.id())
.type("ipsec.1")
.staticRoutesOnly(true)
.build());
}
}
resources:
vpc:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
vpnGateway:
type: aws:ec2:VpnGateway
name: vpn_gateway
properties:
vpcId: ${vpc.id}
customerGateway:
type: aws:ec2:CustomerGateway
name: customer_gateway
properties:
bgpAsn: 65000
ipAddress: 172.0.0.1
type: ipsec.1
main:
type: aws:ec2:VpnConnection
properties:
vpnGatewayId: ${vpnGateway.id}
customerGatewayId: ${customerGateway.id}
type: ipsec.1
staticRoutesOnly: true
The vpnGatewayId property attaches the VPN connection to a specific VPC through its Virtual Private Gateway. Setting staticRoutesOnly to true disables BGP and requires you to define routes manually using companion VpnConnectionRoute resources. This mode works with devices that don’t support BGP.
Route VPN traffic over Direct Connect
Enterprises with Direct Connect can route VPN traffic over private connectivity instead of the public internet, improving security and reducing latency for hybrid cloud workloads.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const exampleGateway = new aws.directconnect.Gateway("example", {
name: "example_ipsec_vpn_example",
amazonSideAsn: "64512",
});
const exampleTransitGateway = new aws.ec2transitgateway.TransitGateway("example", {
amazonSideAsn: 64513,
description: "example_ipsec_vpn_example",
transitGatewayCidrBlocks: ["10.0.0.0/24"],
});
const exampleCustomerGateway = new aws.ec2.CustomerGateway("example", {
bgpAsn: "64514",
ipAddress: "10.0.0.1",
type: "ipsec.1",
tags: {
Name: "example_ipsec_vpn_example",
},
});
const exampleGatewayAssociation = new aws.directconnect.GatewayAssociation("example", {
dxGatewayId: exampleGateway.id,
associatedGatewayId: exampleTransitGateway.id,
allowedPrefixes: ["10.0.0.0/8"],
});
const example = aws.ec2transitgateway.getDirectConnectGatewayAttachmentOutput({
transitGatewayId: exampleTransitGateway.id,
dxGatewayId: exampleGateway.id,
});
const exampleVpnConnection = new aws.ec2.VpnConnection("example", {
customerGatewayId: exampleCustomerGateway.id,
outsideIpAddressType: "PrivateIpv4",
transitGatewayId: exampleTransitGateway.id,
transportTransitGatewayAttachmentId: example.apply(example => example.id),
type: "ipsec.1",
tags: {
Name: "example_ipsec_vpn_example",
},
});
import pulumi
import pulumi_aws as aws
example_gateway = aws.directconnect.Gateway("example",
name="example_ipsec_vpn_example",
amazon_side_asn="64512")
example_transit_gateway = aws.ec2transitgateway.TransitGateway("example",
amazon_side_asn=64513,
description="example_ipsec_vpn_example",
transit_gateway_cidr_blocks=["10.0.0.0/24"])
example_customer_gateway = aws.ec2.CustomerGateway("example",
bgp_asn="64514",
ip_address="10.0.0.1",
type="ipsec.1",
tags={
"Name": "example_ipsec_vpn_example",
})
example_gateway_association = aws.directconnect.GatewayAssociation("example",
dx_gateway_id=example_gateway.id,
associated_gateway_id=example_transit_gateway.id,
allowed_prefixes=["10.0.0.0/8"])
example = aws.ec2transitgateway.get_direct_connect_gateway_attachment_output(transit_gateway_id=example_transit_gateway.id,
dx_gateway_id=example_gateway.id)
example_vpn_connection = aws.ec2.VpnConnection("example",
customer_gateway_id=example_customer_gateway.id,
outside_ip_address_type="PrivateIpv4",
transit_gateway_id=example_transit_gateway.id,
transport_transit_gateway_attachment_id=example.id,
type="ipsec.1",
tags={
"Name": "example_ipsec_vpn_example",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directconnect"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2transitgateway"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
exampleGateway, err := directconnect.NewGateway(ctx, "example", &directconnect.GatewayArgs{
Name: pulumi.String("example_ipsec_vpn_example"),
AmazonSideAsn: pulumi.String("64512"),
})
if err != nil {
return err
}
exampleTransitGateway, err := ec2transitgateway.NewTransitGateway(ctx, "example", &ec2transitgateway.TransitGatewayArgs{
AmazonSideAsn: pulumi.Int(64513),
Description: pulumi.String("example_ipsec_vpn_example"),
TransitGatewayCidrBlocks: pulumi.StringArray{
pulumi.String("10.0.0.0/24"),
},
})
if err != nil {
return err
}
exampleCustomerGateway, err := ec2.NewCustomerGateway(ctx, "example", &ec2.CustomerGatewayArgs{
BgpAsn: pulumi.String("64514"),
IpAddress: pulumi.String("10.0.0.1"),
Type: pulumi.String("ipsec.1"),
Tags: pulumi.StringMap{
"Name": pulumi.String("example_ipsec_vpn_example"),
},
})
if err != nil {
return err
}
_, err = directconnect.NewGatewayAssociation(ctx, "example", &directconnect.GatewayAssociationArgs{
DxGatewayId: exampleGateway.ID(),
AssociatedGatewayId: exampleTransitGateway.ID(),
AllowedPrefixes: pulumi.StringArray{
pulumi.String("10.0.0.0/8"),
},
})
if err != nil {
return err
}
example := ec2transitgateway.GetDirectConnectGatewayAttachmentOutput(ctx, ec2transitgateway.GetDirectConnectGatewayAttachmentOutputArgs{
TransitGatewayId: exampleTransitGateway.ID(),
DxGatewayId: exampleGateway.ID(),
}, nil)
_, err = ec2.NewVpnConnection(ctx, "example", &ec2.VpnConnectionArgs{
CustomerGatewayId: exampleCustomerGateway.ID(),
OutsideIpAddressType: pulumi.String("PrivateIpv4"),
TransitGatewayId: exampleTransitGateway.ID(),
TransportTransitGatewayAttachmentId: pulumi.String(example.ApplyT(func(example ec2transitgateway.GetDirectConnectGatewayAttachmentResult) (*string, error) {
return &example.Id, nil
}).(pulumi.StringPtrOutput)),
Type: pulumi.String("ipsec.1"),
Tags: pulumi.StringMap{
"Name": pulumi.String("example_ipsec_vpn_example"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var exampleGateway = new Aws.DirectConnect.Gateway("example", new()
{
Name = "example_ipsec_vpn_example",
AmazonSideAsn = "64512",
});
var exampleTransitGateway = new Aws.Ec2TransitGateway.TransitGateway("example", new()
{
AmazonSideAsn = 64513,
Description = "example_ipsec_vpn_example",
TransitGatewayCidrBlocks = new[]
{
"10.0.0.0/24",
},
});
var exampleCustomerGateway = new Aws.Ec2.CustomerGateway("example", new()
{
BgpAsn = "64514",
IpAddress = "10.0.0.1",
Type = "ipsec.1",
Tags =
{
{ "Name", "example_ipsec_vpn_example" },
},
});
var exampleGatewayAssociation = new Aws.DirectConnect.GatewayAssociation("example", new()
{
DxGatewayId = exampleGateway.Id,
AssociatedGatewayId = exampleTransitGateway.Id,
AllowedPrefixes = new[]
{
"10.0.0.0/8",
},
});
var example = Aws.Ec2TransitGateway.GetDirectConnectGatewayAttachment.Invoke(new()
{
TransitGatewayId = exampleTransitGateway.Id,
DxGatewayId = exampleGateway.Id,
});
var exampleVpnConnection = new Aws.Ec2.VpnConnection("example", new()
{
CustomerGatewayId = exampleCustomerGateway.Id,
OutsideIpAddressType = "PrivateIpv4",
TransitGatewayId = exampleTransitGateway.Id,
TransportTransitGatewayAttachmentId = example.Apply(getDirectConnectGatewayAttachmentResult => getDirectConnectGatewayAttachmentResult.Id),
Type = "ipsec.1",
Tags =
{
{ "Name", "example_ipsec_vpn_example" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.directconnect.Gateway;
import com.pulumi.aws.directconnect.GatewayArgs;
import com.pulumi.aws.ec2transitgateway.TransitGateway;
import com.pulumi.aws.ec2transitgateway.TransitGatewayArgs;
import com.pulumi.aws.ec2.CustomerGateway;
import com.pulumi.aws.ec2.CustomerGatewayArgs;
import com.pulumi.aws.directconnect.GatewayAssociation;
import com.pulumi.aws.directconnect.GatewayAssociationArgs;
import com.pulumi.aws.ec2transitgateway.Ec2transitgatewayFunctions;
import com.pulumi.aws.ec2transitgateway.inputs.GetDirectConnectGatewayAttachmentArgs;
import com.pulumi.aws.ec2.VpnConnection;
import com.pulumi.aws.ec2.VpnConnectionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var exampleGateway = new Gateway("exampleGateway", GatewayArgs.builder()
.name("example_ipsec_vpn_example")
.amazonSideAsn("64512")
.build());
var exampleTransitGateway = new TransitGateway("exampleTransitGateway", TransitGatewayArgs.builder()
.amazonSideAsn(64513)
.description("example_ipsec_vpn_example")
.transitGatewayCidrBlocks("10.0.0.0/24")
.build());
var exampleCustomerGateway = new CustomerGateway("exampleCustomerGateway", CustomerGatewayArgs.builder()
.bgpAsn("64514")
.ipAddress("10.0.0.1")
.type("ipsec.1")
.tags(Map.of("Name", "example_ipsec_vpn_example"))
.build());
var exampleGatewayAssociation = new GatewayAssociation("exampleGatewayAssociation", GatewayAssociationArgs.builder()
.dxGatewayId(exampleGateway.id())
.associatedGatewayId(exampleTransitGateway.id())
.allowedPrefixes("10.0.0.0/8")
.build());
final var example = Ec2transitgatewayFunctions.getDirectConnectGatewayAttachment(GetDirectConnectGatewayAttachmentArgs.builder()
.transitGatewayId(exampleTransitGateway.id())
.dxGatewayId(exampleGateway.id())
.build());
var exampleVpnConnection = new VpnConnection("exampleVpnConnection", VpnConnectionArgs.builder()
.customerGatewayId(exampleCustomerGateway.id())
.outsideIpAddressType("PrivateIpv4")
.transitGatewayId(exampleTransitGateway.id())
.transportTransitGatewayAttachmentId(example.applyValue(_example -> _example.id()))
.type("ipsec.1")
.tags(Map.of("Name", "example_ipsec_vpn_example"))
.build());
}
}
resources:
exampleGateway:
type: aws:directconnect:Gateway
name: example
properties:
name: example_ipsec_vpn_example
amazonSideAsn: '64512'
exampleTransitGateway:
type: aws:ec2transitgateway:TransitGateway
name: example
properties:
amazonSideAsn: '64513'
description: example_ipsec_vpn_example
transitGatewayCidrBlocks:
- 10.0.0.0/24
exampleCustomerGateway:
type: aws:ec2:CustomerGateway
name: example
properties:
bgpAsn: 64514
ipAddress: 10.0.0.1
type: ipsec.1
tags:
Name: example_ipsec_vpn_example
exampleGatewayAssociation:
type: aws:directconnect:GatewayAssociation
name: example
properties:
dxGatewayId: ${exampleGateway.id}
associatedGatewayId: ${exampleTransitGateway.id}
allowedPrefixes:
- 10.0.0.0/8
exampleVpnConnection:
type: aws:ec2:VpnConnection
name: example
properties:
customerGatewayId: ${exampleCustomerGateway.id}
outsideIpAddressType: PrivateIpv4
transitGatewayId: ${exampleTransitGateway.id}
transportTransitGatewayAttachmentId: ${example.id}
type: ipsec.1
tags:
Name: example_ipsec_vpn_example
variables:
example:
fn::invoke:
function: aws:ec2transitgateway:getDirectConnectGatewayAttachment
arguments:
transitGatewayId: ${exampleTransitGateway.id}
dxGatewayId: ${exampleGateway.id}
The outsideIpAddressType property set to “PrivateIpv4” routes VPN traffic over Direct Connect rather than the public internet. The transportTransitGatewayAttachmentId references the Direct Connect Gateway attachment, obtained through a data source. This configuration requires a Direct Connect Gateway associated with your Transit Gateway.
Beyond these examples
These snippets focus on specific VPN connection features: Transit Gateway and Virtual Private Gateway attachment, static routing and BGP configuration, and private VPN over Direct Connect. They’re intentionally minimal rather than complete hybrid network architectures.
The examples reference pre-existing infrastructure such as Customer Gateways (on-premises VPN endpoints), Transit Gateways or Virtual Private Gateways, and VPCs or Direct Connect Gateways for private VPN. They focus on establishing the VPN connection rather than provisioning the surrounding network infrastructure.
To keep things focused, common VPN patterns are omitted, including:
- Tunnel-specific configuration (inside CIDR blocks, pre-shared keys)
- IKE and IPsec parameters (phase 1/2 encryption, DH groups, lifetimes)
- Dead Peer Detection and tunnel lifecycle controls
- Tunnel bandwidth selection (standard vs large)
- CloudWatch logging configuration (tunnel1LogOptions, tunnel2LogOptions)
These omissions are intentional: the goal is to illustrate how each connection type is wired, not provide drop-in hybrid network modules. See the VPN Connection resource reference for all available configuration options.
Let's configure AWS Site-to-Site VPN Connections
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Gateway Types & Setup
tunnelBandwidth). VPN Gateway is the traditional option but doesn’t support these features. Choose Transit Gateway for modern deployments requiring higher throughput or IPv6.outsideIpAddressType to PrivateIpv4 and provide transportTransitGatewayAttachmentId pointing to your Direct Connect Gateway attachment. This requires a Transit Gateway with an associated Direct Connect Gateway.staticRoutesOnly to true for devices that don’t support BGP. Note that this property is immutable after creation.Tunnel Configuration & CIDR Requirements
tunnel1InsideCidr and tunnel2InsideCidr. For IPv6 (Transit Gateway only), use a /126 CIDR block from the fd00::/8 range.standard (up to 1.25 Gbps per tunnel) or large (up to 5 Gbps per tunnel) for tunnelBandwidth. This option is only available with Transit Gateway and cannot be used with VPN Gateway or when enableAcceleration is true.enableAcceleration, staticRoutesOnly, tunnelBandwidth, tunnelInsideIpVersion, type, and vpnConcentratorId. Plan these carefully during initial setup.Security & Authentication
presharedKeyStorage as SecretsManager to store them in AWS Secrets Manager instead of the default Standard storage.presharedKeyArn output always returns a Secrets Manager ARN, but keys are only actually stored there if you set presharedKeyStorage to SecretsManager. Without this setting, keys remain in the Site-to-Site VPN service.Tunnel Lifecycle & Behavior
tunnel1StartupAction or tunnel2StartupAction to start. By default (value add), your customer gateway device must initiate the IKE negotiation.tunnel1Phase1LifetimeSeconds) ranges from 900 to 28,800 seconds. Phase 2 lifetime (tunnel1Phase2LifetimeSeconds) ranges from 900 to 3,600 seconds. These apply to both tunnels.Using a different cloud?
Explore networking guides for other cloud providers: