This module automates the provisioning of a site-to-site VPN. For more information, see About site-to-site VPN in the IBM Cloud docs.
This Terraform module provisions a complete Site‑to‑Site VPN solution on IBM Cloud VPC, including VPN gateways, connections, policies, routing, and (optional) route advertisement.
For more information refer here
- Creates the VPN gateway instance in specified subnet.
- Supports both policy-based and route-based VPN configurations.
- High availability with multiple gateway members across zones.
- Public IP address automatically assigned for external connectivity.
IKE Policy :
- Internet Key Exchange policy for Phase 1 negotiation.
- Configurable authentication algorithms (SHA-1, SHA-256, SHA-384, SHA-512).
- Configurable encryption algorithms (AES-128, AES-192, AES-256, 3DES).
- Configurable Diffie-Hellman groups (2, 5, 14, 15, 16, 17, 18, 19, 20, 21).
- IKE version support (IKEv1, IKEv2).
IPSec Policy :
- Internet Protocol Security policy for Phase 2 negotiation.
- Configurable authentication and encryption algorithms.
- Perfect Forward Secrecy (PFS) support.
- Use custom policy if default does not meet peer requirements.
Note:
- When using existing policy IDs (both IKE and IPSec), ensure that the policy resides in the same region as the VPN Gateway.
- Within a given region, policy names must be unique. Two policies with the same name cannot coexist in the same region.
- Establishes IPSec tunnels between local and peer gateways.
- Supports multiple connections per gateway for redundancy.
- Dead Peer Detection (DPD) configuration.
- Local and peer subnet definitions.
- Custom routes in VPC routing tables for directing traffic through VPN tunnels.
- Route advertisement capabilities for dynamic routing.
- Integration with VPC routing tables.
- Support for both static and dynamic routing.
- VPC must be created and configured before deploying the VPN gateway.
- Subnets must exist in the target zones where VPN gateways will be deployed.
- Local and peer network CIDR blocks must not overlap.
- Ensure proper network segmentation and IP address planning.
- Verify that the peer VPN gateway supports IPSec protocols.
- Pre-shared key (PSK) must be configured and shared between both endpoints.
- IKE and IPSec policies must be compatible between local and peer gateways.
- Proper authentication methods must be established.
- Security groups and NACLs must allow VPN traffic.
Please refer Planning considerations for VPN gateways for more information.
- IBM permits only one route‑based VPN gateway per zone per VPC. For zone fault tolerance, deploy one VPN gateway per zone.
- VPN gateway names must be unique within the VPC.
- Gateway requires
/28subnet and cannot share with other VPC. - If peer VPN gateway lacks a public IP, use FQDN identity in VPC.
- Peer subnets of a VPN gateway connection cannot overlap.
- Peer address type is immutable — once set as FQDN or IP, it cannot be changed.
- Route-based mode allows distribute_traffic = true to enable active‑active tunnels; policy‑based does not.
- If peer is behind NAT, use
establish_mode = "peer_only"and supply FQDN and identity overrides because identities must match expected values on negotiation. - Creating a route in an ingress routing table with a VPN gateway connection as the next hop is not supported.
Please refer Known issues for VPN gateways for more information.
Tunnel status may remain DOWN for a while after deployment, with delays observed before it shows as UP.
terraform {
required_version = ">= 1.9.0"
required_providers {
ibm = {
source = "IBM-Cloud/ibm"
version = "X.Y.Z" # Lock into a provider version that satisfies the module constraints
}
}
}
locals {
region = "us-south"
ike_policy_config = {
name = "xxx-ike-policy" # Name of the IKE Policy
authentication_algorithm = "sha256" # Choose the relevant authentication algorithm
encryption_algorithm = "aes256" # Choose the relevant encryption algorithm
dh_group = 14 # Provide valid Diffie-Hellman group.
}
ipsec_policy_config = {
name = "xxx-ipsec-policy" # Name of the IPSec Policy
encryption_algorithm = "aes256" # Choose the relevant encryption algorithm
authentication_algorithm = "sha256" # Choose the relevant authentication algorithm
pfs = "group_14" # Perfect Forward Secrecy (PFS) protocol value
}
}
provider "ibm" {
ibmcloud_api_key = "XXXXXXXXXX" # replace with apikey value
region = local.region
}
module "site_to_site_vpn" {
source = "terraform-ibm-modules/site-to-site-vpn/ibm"
version = "X.X.X" # Replace "X.X.X" with a release version to lock into a specific release
resource_group_id = "65xxxxxxxxxxxxxxxa3fd"
create_vpn_gateway = true
tags = var.tags
vpn_gateway_name = "xxxxx" # Name of the VPN Gateway
vpn_gateway_subnet_id = "s..12" # Subnet id where VPN Gateway will be created
vpn_gateway_mode = "route" # Can be route or policy
# Policies
create_ike_policy = true
create_ipsec_policy = true
ike_policy_config = local.ike_policy_config
ipsec_policy_config = local.ipsec_policy_config
# VPN Connections
vpn_connections = [
{
name = "xxx-vpn-conn" # VPN Connection name
peer_address = "X.X.X.X" # Remote VPN gateway IP
preshared_key = "XXXXXX"
# Peer Configuration (remote VPN gateway)
peer_config = [
{
address = "X.X.X.X" # Remote Gateway IP address
cidrs = [X.X.X.X] # Provide CIDRs (Required for Policy based VPN)
ike_identity = [
{
type = "ipv4_address"
value = "X.X.X.X" # Remote Gateway IP address
}
]
}
]
# Local Configuration
local_config = [
{
cidrs = ["10.10.0.0/16"] # Local VPC CIDRs
# Minimum of 2 IKE Identities are required for Route based VPN and atmost 1 for Policy based VPN
ike_identities = [
{
type = "ipv4_address"
value = module.vpn_gateway.vpn_gateway_public_ip # Use the VPN gateway id
},
{
type = "ipv4_address"
value = module.vpn_gateway.vpn_gateway_public_ip # Use the VPN gateway id
}
]
}
]
}
]
# Routing table and Routes creation
create_route_table = true
routing_table_name = "xxx-rt" # Name of Routing Table
accept_routes_from_resource_type = ["vpn_gateway"]
route_attach_subnet = true
route_subnet_id = "s...123" # Subnet id where VPN Gateway is created
# Add routes
create_routes = true
vpc_id = "vpc-xxxx" # Provide VPC Id.
routes = [
{
name = "example-vpn-route-1"
vpn_gateway_name = "xxxxx" # Name of the VPN Gateway
zone = "zone-1"
next_hop = null # This will be resolved using Connection name
vpn_connection_name = "xxxx" # Name of the VPN Connection
destination = "X.X.X.X" # Provide Remote CIDR
}
]
}
Please refer the state migration document for more information.
You need the following permissions to run this module.
- IAM services
- VPC Infrastructure services
Editorplatform access
- No service access
- Resource Group <your resource group>
Viewerresource group access
- VPC Infrastructure services
| Name | Version |
|---|---|
| terraform | >= 1.9.0 |
| ibm | >= 1.80.3, < 2.0.0 |
| time | >= 0.9.1, < 1.0.0 |
| Name | Source | Version |
|---|---|---|
| vpn_policies | ./modules/vpn_policies | n/a |
| vpn_routes | ./modules/vpn_routing | n/a |
| Name | Type |
|---|---|
| ibm_is_vpn_gateway.vpn_gateway | resource |
| ibm_is_vpn_gateway_connection.vpn_site_to_site_connection | resource |
| time_sleep.wait_for_gateway_creation | resource |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| accept_routes_from_resource_type | List of resource types allowed to create routes in this table. | list(string) |
[] |
no |
| advertise_routes_to | Ingress sources to which routes should be advertised. | list(string) |
[] |
no |
| create_route_table | Whether to create a new route table. | bool |
false |
no |
| create_routes | Whether to create VPN routes. | bool |
false |
no |
| create_vpn_gateway | Whether to create a new VPN Gateway. Set to false to use an existing gateway. | bool |
true |
no |
| existing_route_table_id | ID of existing route table to use. | string |
null |
no |
| existing_vpn_gateway_id | ID of existing VPN Gateway to use. Required if create_vpn_gateway is false and vpn_gateway_name is not provided. | string |
null |
no |
| resource_group_id | The ID of the resource group to use where you want to create the VPN gateway. | string |
n/a | yes |
| route_attach_subnet | Whether to attach subnet to the VPN route table. | bool |
false |
no |
| route_direct_link_ingress | Allow routing from Direct Link. | bool |
false |
no |
| route_internet_ingress | Allow routing from Internet. | bool |
false |
no |
| route_subnet_id | Subnet ID to attach to the routing table. | string |
null |
no |
| route_transit_gateway_ingress | Allow routing from Transit Gateway. | bool |
false |
no |
| route_vpc_zone_ingress | Allow routing from other zones within the VPC. | bool |
false |
no |
| routes | List of routes to create. | list(object({ |
[] |
no |
| routing_table_name | Name of the routing table to create. | string |
null |
no |
| tags | List of Tags for the resource created | list(string) |
null |
no |
| vpc_id | VPC ID where routes will be created. | string |
null |
no |
| vpn_connections | List of VPN connections to attach to the VPN gateway. | list(object({ |
[] |
no |
| vpn_gateway_mode | Specifies the VPN configuration mode for IBM Cloud VPN for VPC. Use 'route' for a static, route-based IPsec tunnel or 'policy' for a policy-based tunnel to connect your VPC to another private network. | string |
"route" |
no |
| vpn_gateway_name | Name of the VPN gateway. Only required if creating a new VPN Gateway. | string |
null |
no |
| vpn_gateway_subnet_id | The ID of the subnet where the VPN gateway will reside in. | string |
null |
no |
| Name | Description |
|---|---|
| vpn_connection_policies | IKE and IPSec policy details. |
| vpn_gateway_connection_ids | Map of VPN gateway connection IDs, keyed by connection name. |
| vpn_gateway_connection_modes | Map of VPN gateway connection modes: either 'policy' or 'route'. |
| vpn_gateway_connection_statuses | Map of current statuses for each VPN gateway connection, either 'up' or 'down'. |
| vpn_gateway_crn | CRN of the VPN gateway. |
| vpn_gateway_id | ID of the VPN gateway. |
| vpn_gateway_members | List of VPN gateway members. |
| vpn_gateway_public_ip | The IP address assigned to the VPN gateway. Learn more |
| vpn_gateway_public_ip_2 | The Second Public IP address assigned to the VPN gateway member. Learn more |
| vpn_gateway_status | Overall health state of the VPN gateway. Refer here for more information. |
| vpn_gateway_vpc_info | Information about the VPC associated with the VPN gateway. |
| vpn_routes | VPN Routing information. |
| vpn_status_reasons | Map of status reasons explaining the current connection state per connection. |
You can report issues and request features for this module in GitHub issues in the module repo. See Report an issue or request a feature.
To set up your local development environment, see Local development setup in the project documentation.