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.
- 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
/28
subnet 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"
}
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
create_vpn_policies = true
ike_policy_name = "xxx-ike-policy" # Name of the IKE Policy
ike_authentication_algorithm = "sha256" # Choose the relevant authentication algorithm
ike_encryption_algorithm = "aes256" # Choose the relevant encryption algorithm
ike_dh_group = 14 # Provide valid Diffie-Hellman group.
ipsec_policy_name = "xxx-ipsec-policy" # Name of the IPSec Policy
ipsec_authentication_algorithm = "sha256" # Choose the relevant authentication algorithm
ipsec_encryption_algorithm = "aes256" # Choose the relevant encryption algorithm
ipsec_pfs = "group_14" # Perfect Forward Secrecy (PFS) protocol value
# Create Connection to Remote Peer
vpn_gateway_connection_name = "xxx-vpn-conn" # VPN Connection name
preshared_key = "XXXXXX"
# Peer Configuration (remote VPN gateway)
peer_config = [
{
address = "X.X.X.X" # Remote Gateway IP address
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
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 = module.site_to_site_vpn.vpn_gateway_id
destination = "X.X.X.X" # Provide Remote CIDR
}
]
}
You need the following permissions to run this module.
- IAM services
- VPC Infrastructure services
Editor
platform access
- No service access
- Resource Group <your resource group>
Viewer
resource 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 |
create_vpn_policies | Whether to create a new IKE and IPSec policy. | bool |
false |
no |
dpd_action | Optional action to perform when the peer is unresponsive. Possible values are - 'restart', 'clear', 'hold', or 'none'. | string |
"restart" |
no |
dpd_check_interval | Optional interval in seconds between dead peer detection checks for peer responsiveness. | number |
2 |
no |
dpd_max_timeout | Optional time in seconds to wait before considering the peer unreachable. | number |
10 |
no |
enable_distribute_traffic | Optional flag for route-based VPN gateway connections to control traffic distribution across active tunnels. When true, traffic is load-balanced otherwise, it flows through the tunnel with the lower public IP. | bool |
false |
no |
establish_mode | Optional field to determine the IKE negotiation behavior for the VPN gateway connection. Use 'bidirectional' to allow both sides to initiate IKE negotiations and rekeying. Use 'peer_only' to restrict initiation and rekeying to the peer side. | string |
"bidirectional" |
no |
existing_ike_policy_id | ID of existing IKE policy to use instead of creating new one. | string |
null |
no |
existing_ipsec_policy_id | ID of existing IPSec policy to use instead of creating new one. | string |
null |
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 |
ike_authentication_algorithm | The authentication algorithm used in the IKE policy. Valid values: sha256, sha384, sha512. | string |
null |
no |
ike_dh_group | The Diffie-Hellman group to use. Valid values: 14 to 24, or 31. | number |
null |
no |
ike_encryption_algorithm | The encryption algorithm used in the IKE policy. Valid values: aes128, aes192, aes256. | string |
null |
no |
ike_key_lifetime | The key lifetime in seconds. Must be between 1800 and 86400. | number |
28800 |
no |
ike_policy_name | Name of the IKE policy to create. Applicable when create_vpn_policies is true | string |
null |
no |
ike_version | The IKE protocol version to use. Valid values: 1 or 2. | number |
2 |
no |
ipsec_authentication_algorithm | The authentication algorithm for the IPSec policy. Valid values: sha256, sha384, sha512, disabled. | string |
null |
no |
ipsec_encryption_algorithm | The encryption algorithm for the IPSec policy. Valid values: aes128, aes192, aes256, aes128gcm16, aes192gcm16, aes256gcm16. | string |
null |
no |
ipsec_key_lifetime | The key lifetime for the IPSec policy in seconds. Must be between 300 and 86400. | number |
3600 |
no |
ipsec_pfs | The Perfect Forward Secrecy (PFS) protocol for the IPSec policy. Valid values: disabled, group_2, group_5, group_14. | string |
null |
no |
ipsec_policy_name | Name of the IPSec policy to create. | string |
null |
no |
is_admin_state_up | Optional flag to control the administrative state of the VPN gateway connection. If set to false (default), the connection is shut down. Set to true to enable the connection. | bool |
false |
no |
local_config | Optional configuration for local IKE identities. Each entry in the list represents a VPN gateway member. For route-based VPN gateway each member must specify exactly 2 identities. For policy-based VPN gateway each member may provide at most 1 identity. | list(object({ |
[] |
no |
peer_config | Optional configuration for the remote peer VPN gateway. Includes peer address/FQDN, CIDRs, IKE identity type, and optional identity value. | list(object({ |
[] |
no |
preshared_key | Required to specify the authentication key of the VPN gateway for the network outside your VPC. Learn More | string |
n/a | yes |
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_gateway_connection_name | Name of the VPN connection. | string |
n/a | yes |
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 |
---|---|
ike_policy | Map of newly created IKE policy. |
ipsec_policy | Map of newly created IPSec policy. |
vpn_gateway_connection_id | Unique identifier of the VPN gateway connection. |
vpn_gateway_connection_mode | Mode of the VPN gateway connection: either 'policy' or 'route'. |
vpn_gateway_connection_name | Name of the VPN gateway connection. |
vpn_gateway_connection_status | Current status of the 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 | Resolved public IP address from either public_ip_address or public_ip_address2 . 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 | List of status reasons explaining the current connection state. |
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.