Skip to content

terraform-ibm-modules/terraform-ibm-site-to-site-vpn

Site to Site VPN Module

Graduated (Supported) pre-commit latest release Renovate enabled semantic-release

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.

Overview

terraform-ibm-site-to-site-vpn

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

Key Components

VPN Gateway

  • 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.

VPN Policies

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.

VPN Connections

  • 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.

Route Management

  • 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.

Important Considerations

Network specific

  • 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.

Security specific

  • 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.

Known Limitations

  • 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.

Usage

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
    }
  ]
}

Required IAM access policies

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

Requirements

Name Version
terraform >= 1.9.0
ibm >= 1.80.3, < 2.0.0
time >= 0.9.1, < 1.0.0

Modules

Name Source Version
vpn_policies ./modules/vpn_policies n/a
vpn_routes ./modules/vpn_routing n/a

Resources

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

Inputs

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({
cidrs = optional(list(string))
ike_identities = list(object({
type = string
value = optional(string)
}))
}))
[] 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({
address = optional(string)
fqdn = optional(string)
cidrs = optional(list(string))
ike_identity = list(object({
type = string
value = optional(string)
}))
}))
[] 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({
name = string
zone = string
destination = string
next_hop = string
action = optional(string, "deliver")
advertise = optional(bool, false)
priority = optional(number, 2)
}))
[] 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

Outputs

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.

Contributing

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.