Virtual private networks

VPN as a Service is an OpenStack networking extension that provides VPN services for your project. Currently this service is restricted to IPsec based VPNs.

A worked example

In the following examples we will construct a VPN between the Hamilton region (nz-hlz-1) and the Porirua region (nz-por-1) of our project. We will assume that in both regions we have an identical network setup that looks like:

  • A network called private-net.

  • A subnet called private-subnet.

  • A router to the internet called border-router.

The only differences between the two setups will be the external IP address on the router and the CIDR of the private subnets.

We will illustrate how to create the the VPN using the following approaches:

  • Using the Openstack command line tools.

  • With a bash script.

  • From the cloud dashboard

Requirements

In order to set up a VPN, we need to identify some key information:

  • Router name

  • Router IP address

  • Subnet name

  • Subnet CIDR range

  • Remote peer router IP

  • Remote peer subnet CIDR range

  • A secret pre shared key

While we will be using the names of the router and subnet it is important to note that these are not required to be unique so if your creating multiple VPN connections it may be more appropriate to use the UUID values for these elements in order to avoid ambiguity when running commands.

Note

IPSec relies on symmetrical encryption where both sides use the same private key. This key is known as a Pre Shared Key (PSK). You should ensure that you manage this key appropriately, so for example be sure that it is not committed to your configuration management system source control in plain text.

Warning

The Pre Shared Key should be between 20 to 40 characters long and consist of alphanumeric characters only. The Pre Shared Key must not contain the ‘&’ character.

The first thing we need to do prior to creating our VPN is to gather the relevant information, as mentioned above, for our existing network elements. We will create the first half of our VPN in the Hamilton region.

To get the subnet’s CIDR run the following command.

$ echo $OS_REGION_NAME
nz-hlz-1

$ openstack subnet list --name private-subnet -c Name -f value -c Subnet -f value -c ID -f value  -f table
+--------------------------------------+----------------+-------------+
| ID                                   | Name           | Subnet      |
+--------------------------------------+----------------+-------------+
| 1d701353-f120-413d-b33f-xxxxxxxxxxxx | private-subnet | 10.0.0.0/24 |
+--------------------------------------+----------------+-------------+

Next let’s find the required router information.

$ openstack router show border-router -c id -f value -c external_gateway_info -f value -f json
{
  "external_gateway_info": {
    "network_id": "993e826c-74c2-4b44-ad6f-xxxxxxxxxxxx",
    "enable_snat": true,
    "external_fixed_ips": [
      {
        "subnet_id": "f44f9716-a08c-4972-909d-xxxxxxxxxxxx",
        "ip_address": "10.10.8.3"
      },
      {
        "subnet_id": "7cae5aac-2d01-4cba-a171-xxxxxxxxxxxx",
        "ip_address": "2404:130:4040:8::16"
      }
    ]
  },
  "id": "ddd82b49-8bae-4a25-ae94-xxxxxxxxxxxx"
}

From the JSON data, the router IP address is the IPv4 value associated with the ip_address key within the external_gateway_info.

As we are creating a VPN that connects our Catalyst Cloud project across two regions, the remote reer router IP and remote peer subnet CIDR range will be the values associated with the subnet and router in the other region.

In this case we need to find the router IP and the subnet CIDR from the network located in the Porirua region. You can determine these in the same way as shown above while connected to the other region.

$ echo $OS_REGION_NAME
nz-por-1

$ openstack subnet list --name private-subnet -c Name -f value -c Subnet -f value -f table
+----------------+---------------+
| Name           | Subnet        |
+----------------+---------------+
| private-subnet | 10.20.30.0/24 |
+----------------+---------------+


$ openstack router show border-router -c external_gateway_info -f value -c interfaces_info -f value -f json
{
  "external_gateway_info": {
    "network_id": "849ab1e9-7ac5-4618-8801-xxxxxxxxxxxx",
    "enable_snat": true,
    "external_fixed_ips": [
      {
        "subnet_id": "aef23c7c-6c53-4157-8350-xxxxxxxxxxxx",
        "ip_address": "150.242.40.137"
      },
      {
        "subnet_id": "e8064b07-ac94-4172-91a1-xxxxxxxxxxxx",
        "ip_address": "2404:130:4020:8000::7637"
      }
    ]
  }
}

The values we need from the above output are:

  • remote peer router IP : 150.242.40.137

  • remote peer subnet CIDR : 10.20.30.0/24

If you are setting up a VPN to a different peer, then the remote peer router IP will be the publicly accessible IPv4 address of that router, while the remote peer subnet CIDR range will be the subnet behind that router whose traffic you wish to route via the VPN to access the local subnet.

Note

If you are connecting to a remote peer that is not a Catalyst Cloud router, you may need to modify some of the parameters used in the following steps.

By now you should have the required values so you can proceed to create a VPN.

There are four steps to creating a VPN:

  • Create a VPN Service

  • Create a VPN IKE Policy

  • Create a VPN IPSec Policy

  • Create a VPN Endpoint Group for the local subnet

  • Create a VPN Endpoint Group for the peer CIDR

  • Create a VPN IPSec Site Connection

This example will cover setting up one half of the VPN in the Hamilton region.

First let’s create a VPN Service called vpn_service.

$ openstack vpn service create \
--router border-router \
vpn_service
+----------------+--------------------------------------+
| Field          | Value                                |
+----------------+--------------------------------------+
| Description    |                                      |
| ID             | 99d8f06c-8cd8-44d6-9337-xxxxxxxxxxxx |
| Name           | vpn_service                          |
| Project        | 630116938c82479cxxxxxx3912c1d09c     |
| Router         | ddd82b49-8bae-4a25-ae94-xxxxxxxxxxxx |
| State          | True                                 |
| Status         | PENDING_CREATE                       |
| Subnet         | None                                 |
| external_v4_ip | 10.10.8.3                            |
| external_v6_ip | 2404:130:4040:8::16                  |
| project_id     | 630116938c82479cxxxxxx3912c1d09c     |
+----------------+--------------------------------------+

Then create a VPN IKE policy called ike_policy.

$ openstack vpn ike policy create \
--auth-algorithm sha1 \
--encryption-algorithm aes-256 \
--phase1-negotiation-mode main \
--pfs group14 \
--ike-version v1 \
--lifetime units=seconds,value=14400 \
ike_policy
+-------------------------------+--------------------------------------+
| Field                         | Value                                |
+-------------------------------+--------------------------------------+
| Authentication Algorithm      | sha1                                 |
| Description                   |                                      |
| Encryption Algorithm          | aes-256                              |
| ID                            | d64b4355-576f-4f68-989d-xxxxxxxxxxxx |
| IKE Version                   | v1                                   |
| Lifetime                      | {'units': 'seconds', 'value': 14400} |
| Name                          | ike_policy                           |
| Perfect Forward Secrecy (PFS) | group14                              |
| Phase1 Negotiation Mode       | main                                 |
| Project                       | 630116938c82479cxxxxxx3912c1d09c     |
| project_id                    | 630116938c82479cxxxxxx3912c1d09c     |
+-------------------------------+--------------------------------------+

Then create a VPN IPSec policy called ipsec_policy.

$ openstack vpn ipsec policy create \
--transform-protocol esp \
--auth-algorithm sha1 \
--encryption-algorithm aes-256 \
--encapsulation-mode tunnel \
--pfs group14 \
--lifetime units=seconds,value=3600 \
ipsec_policy
+-------------------------------+--------------------------------------+
| Field                         | Value                                |
+-------------------------------+--------------------------------------+
| Authentication Algorithm      | sha1                                 |
| Description                   |                                      |
| Encapsulation Mode            | tunnel                               |
| Encryption Algorithm          | aes-256                              |
| ID                            | 54367ef5-9e76-4827-888e-xxxxxxxxxxxx |
| Lifetime                      | {'units': 'seconds', 'value': 3600}  |
| Name                          | ipsec_policy                         |
| Perfect Forward Secrecy (PFS) | group14                              |
| Project                       | 630116938c82479cxxxxxx3912c1d09c     |
| Transform Protocol            | esp                                  |
| project_id                    | 630116938c82479cxxxxxx3912c1d09c     |
+-------------------------------+--------------------------------------+

Then create an Endpoint Group for the local subnet called local_endpoint_group.

 $ openstack vpn endpoint group create --type subnet --value private-subnet local_endpoint_group
 +-------------+------------------------------------------+
 | Field       | Value                                    |
 +-------------+------------------------------------------+
 | Description |                                          |
 | Endpoints   | ['1d701353-f120-413d-b33f-xxxxxxxxxxxx'] |
 | ID          | 5d972e8d-e7a0-45ea-8d91-xxxxxxxxxxxx     |
 | Name        | local_endpoint_group                     |
 | Project     | 630116938c82479cxxxxxx3912c1d09c         |
 | Type        | subnet                                   |
 | project_id  | 630116938c82479cxxxxxx3912c1d09c         |
 +-------------+------------------------------------------+

Then create an Endpoint Group for the remote peer CIDR called *peer_endppoint_group*.
$ openstack vpn endpoint group create --type cidr --value 10.20.30.0/24 peer_endpoint_group
+-------------+--------------------------------------+
| Field       | Value                                |
+-------------+--------------------------------------+
| Description |                                      |
| Endpoints   | ['10.20.30.0/24']                    |
| ID          | f34578dc-aae8-4c02-abeb-xxxxxxxxxxxx |
| Name        | peer_endpoint_group                  |
| Project     | 630116938c82479cxxxxxx3912c1d09c     |
| Type        | cidr                                 |
| project_id  | 630116938c82479cxxxxxx3912c1d09c     |
+-------------+--------------------------------------+

Note

You can provide multiple --value arguments if you want to tunnel more than one CIDR range.

Finally we create a VPN IPSec site connection called vpn_site_connection. This command makes use of the resources created in the last five steps.

$ openstack vpn ipsec site connection create \
--initiator bi-directional \
--vpnservice vpn_service \
--ikepolicy ike_policy \
--ipsecpolicy ipsec_policy \
--dpd action=restart,interval=15,timeout=150 \
--peer-address 150.242.40.137 \
--peer-id 150.242.40.137 \
--local-endpoint-group local_endpoint_group \
--peer-endpoint-group peer_endpoint_group \
--psk supersecretpsk \
vpn_site_connection
+--------------------------+-------------------------------------------------------+
| Field                    | Value                                                 |
+--------------------------+-------------------------------------------------------+
| Authentication Algorithm | psk                                                   |
| Description              |                                                       |
| ID                       | 8b47f318-d91a-4040-9156-xxxxxxxxxxxx                  |
| IKE Policy               | d64b4355-576f-4f68-989d-xxxxxxxxxxxx                  |
| IPSec Policy             | 54367ef5-9e76-4827-888e-xxxxxxxxxxxx                  |
| Initiator                | bi-directional                                        |
| Local Endpoint Group ID  | 5d972e8d-e7a0-45ea-8d91-xxxxxxxxxxxx                  |
| Local ID                 |                                                       |
| MTU                      | 1500                                                  |
| Name                     | vpn_site_connection                                   |
| Peer Address             | 150.242.40.137                                        |
| Peer CIDRs               |                                                       |
| Peer Endpoint Group ID   | f34578dc-aae8-4c02-abeb-xxxxxxxxxxxx                  |
| Peer ID                  | 150.242.40.137                                        |
| Pre-shared Key           | supersecretpsk                                        |
| Project                  | 630116938c82479cxxxxxx3912c1d09c                      |
| Route Mode               | static                                                |
| State                    | True                                                  |
| Status                   | PENDING_CREATE                                        |
| VPN Service              | 99d8f06c-8cd8-44d6-9337-xxxxxxxxxxxx                  |
| dpd                      | {'action': 'restart', 'interval': 15, 'timeout': 150} |
| project_id               | 630116938c82479cxxxxxx3912c1d09c                      |
+--------------------------+-------------------------------------------------------+

You have now stood up one end of the VPN. This process should be repeated at the other end using the same configuration options and PSK. Once both sides of the VPN are configured, the peers should automatically detect each other and bring up the VPN. When the VPN is up, the status will change to ACTIVE.

The Catalyst Cloud team have created a bash script that simplifies the procedure for creating a VPN. In order to run the script you will need to know the following information for each region you will be creating a VPN endpoint for. Details on how to obtain this information can be found in the Command Line example.

  • router name

  • router external IP address

  • subnet name

  • subnet CIDR range

This script will require no modification when setting up region to region VPNs. If you are using it to connect a Catalyst Cloud router to a non Catalyst Cloud router, you may need to change some configuration options.

This script currently only supports single CIDR ranges. If you are wanting to tunnel multiple ranges then it will require some modification.

You can download the latest version of this script using the following command:

$ wget https://raw.githubusercontent.com/catalyst-cloud/catalystcloud-docs/master/source/network/_scripts/create-vpn.sh

Below is an example of the script being used to create a region to region
VPN on the Catalyst Cloud:
./create-vpn.sh
----------------------------------------------------------
This script will setup a VPN in your project.
You can select either:
a single region that will connect to an external site
or
a site-to-site vpn between 2 regions for the same project
----------------------------------------------------------

1) single
2) site-to-site
Select the VPN option you require or type 'q' to quit: 2

-------------------------------------------------------
Select the regions for your site-to-site VPN endpoints
-------------------------------------------------------

1) Hamilton
2) Porirua
3) Wellington
Select region 1 for the site-to-site VPN or type 'q' to quit: 1

1) Hamilton
2) Porirua
3) Wellington
Select region 2 for the site-to-site VPN or type 'q' to quit: 2

Please enter the name of your Hamilton router:
border-router
Please enter the name of your Hamilton subnet:
private-subnet
nz-por-1
Please enter the name of your Porirua router:
border-router
Please enter the name of your Porirua subnet:
private-subnet
Please enter your pre shared key:
supersecretkey
Please enter the Hamilton router ip address
103.197.61.206
Please enter the Hamilton CIDR range
192.168.3.0/24

Please enter the Porirua router ip address
150.242.41.251
Please enter the Porirua CIDR range
192.168.2.0/24

--------------------------------------------------------
Proceeding to create VPN with the following credentials:
Region name = Hamilton
region_1_router_name = border-router
region_1_subnet_name = private-subnet
region_1_router_ip = 103.197.61.206
region_1_subnet = 192.168.3.0/24
region_1_peer_router_ip = 150.242.41.251
region_1_peer_subnet = 192.168.2.0/24

Region name = Porirua
region_2_router_name = border-router
region_2_subnet_name = private-subnet
region_2_router_ip = 150.242.41.251
region_2_subnet = 192.168.2.0/24
region_2_peer_router_ip = 103.197.61.206
region_2_peer_subnet = 192.168.3.0/24

pre_shared_key = supersecretkey
--------------------------------------------------------

creating endpoint for Hamilton
+----------------+--------------------------------------+
| Field          | Value                                |
+----------------+--------------------------------------+
| Description    |                                      |
| ID             | 4c5faf25-dada-44c7-a7d4-xxxxxxxxxxxx |
| Name           | vpn_service                          |
| Project        | 83100bf293c94607xxxxxxa959ac0218     |
| Router         | 34ea00e7-74bc-4f9f-b270-xxxxxxxxxxxx |
| State          | True                                 |
| Status         | PENDING_CREATE                       |
| Subnet         | 5ea2199a-1a1e-40c5-a4cd-xxxxxxxxxxxx |
| external_v4_ip | 103.197.61.206                       |
| external_v6_ip | 2404:130:8020:8000::2:ce58           |
+----------------+--------------------------------------+
+-------------------------------+--------------------------------------+
| Field                         | Value                                |
+-------------------------------+--------------------------------------+
| Authentication Algorithm      | sha1                                 |
| Description                   |                                      |
| Encryption Algorithm          | aes-256                              |
| ID                            | ceebee2c-f5ac-44fa-a838-xxxxxxxxxxxx |
| IKE Version                   | v1                                   |
| Lifetime                      | {'units': 'seconds', 'value': 14400} |
| Name                          | ike_policy                           |
| Perfect Forward Secrecy (PFS) | group14                              |
| Phase1 Negotiation Mode       | main                                 |
| Project                       | 83100bf293c94607xxxxxxa959ac0218     |
+-------------------------------+--------------------------------------+
+-------------------------------+--------------------------------------+
| Field                         | Value                                |
+-------------------------------+--------------------------------------+
| Authentication Algorithm      | sha1                                 |
| Description                   |                                      |
| Encapsulation Mode            | tunnel                               |
| Encryption Algorithm          | aes-256                              |
| ID                            | 77c66397-43e9-45db-b0cd-xxxxxxxxxxxx |
| Lifetime                      | {'units': 'seconds', 'value': 3600}  |
| Name                          | ipsec_policy                         |
| Perfect Forward Secrecy (PFS) | group14                              |
| Project                       | 83100bf293c94607xxxxxxa959ac0218     |
| Transform Protocol            | esp                                  |
+-------------------------------+--------------------------------------+
+----------------+--------------------------------------+
| Field          | Value                                |
+----------------+--------------------------------------+
| Description    |                                      |
| ID             | 84303467-9c62-47c7-91c9-xxxxxxxxxxxx |
| Name           | vpn_service                          |
| Project        | 83100bf293c94607xxxxxxa959ac0218     |
| Router         | d570c9c8-bde2-4f39-8fa9-xxxxxxxxxxxx |
| State          | True                                 |
| Status         | PENDING_CREATE                       |
| Subnet         | 55c57cd5-1b94-4098-9cf6-xxxxxxxxxxxx |
| external_v4_ip | 150.242.41.251                       |
| external_v6_ip | 2404:130:4020:8000::1:9c3a           |
+----------------+--------------------------------------+
+-------------------------------+--------------------------------------+
| Field                         | Value                                |
+-------------------------------+--------------------------------------+
| Authentication Algorithm      | sha1                                 |
| Description                   |                                      |
| Encryption Algorithm          | aes-256                              |
| ID                            | a184e4c4-856f-4136-9ef1-xxxxxxxxxxxx |
| IKE Version                   | v1                                   |
| Lifetime                      | {'units': 'seconds', 'value': 14400} |
| Name                          | ike_policy                           |
| Perfect Forward Secrecy (PFS) | group14                              |
| Phase1 Negotiation Mode       | main                                 |
| Project                       | 83100bf293c94607xxxxxxa959ac0218     |
+-------------------------------+--------------------------------------+
+-------------------------------+--------------------------------------+
| Field                         | Value                                |
+-------------------------------+--------------------------------------+
| Authentication Algorithm      | sha1                                 |
| Description                   |                                      |
| Encapsulation Mode            | tunnel                               |
| Encryption Algorithm          | aes-256                              |
| ID                            | 9b41de10-194d-4e1d-9f2a-xxxxxxxxxxxx |
| Lifetime                      | {'units': 'seconds', 'value': 3600}  |
| Name                          | ipsec_policy                         |
| Perfect Forward Secrecy (PFS) | group14                              |
| Project                       | 83100bf293c94607xxxxxxa959ac0218     |
| Transform Protocol            | esp                                  |
+-------------------------------+--------------------------------------+
+--------------------------+-------------------------------------------------------+
| Field                    | Value                                                 |
+--------------------------+-------------------------------------------------------+
| Authentication Algorithm | psk                                                   |
| Description              |                                                       |
| ID                       | 1521242f-7d63-43b7-aa62-xxxxxxxxxxxx                  |
| IKE Policy               | a184e4c4-856f-4136-9ef1-xxxxxxxxxxxx                  |
| IPSec Policy             | 9b41de10-194d-4e1d-9f2a-xxxxxxxxxxxx                  |
| Initiator                | bi-directional                                        |
| MTU                      | 1500                                                  |
| Name                     | vpn_site_connection                                   |
| Peer Address             | 103.197.61.206                                        |
| Peer CIDRs               | 192.168.3.0/24                                        |
| Peer ID                  | 103.197.61.206                                        |
| Pre-shared Key           | pre_shared_key                                        |
| Project                  | 83100bf293c94607xxxxxxa959ac0218                      |
| Route Mode               | static                                                |
| State                    | True                                                  |
| Status                   | PENDING_CREATE                                        |
| VPN Service              | 84303467-9c62-47c7-91c9-xxxxxxxxxxxx                  |
| dpd                      | {'action': 'restart', 'interval': 15, 'timeout': 150} |
+--------------------------+-------------------------------------------------------+

Your VPN has been created, note that you will need to create appropriate security group rules.

The script source is included below for reference:

#!/bin/bash

#------------------------------------------------------------------------------
# Parameters
#------------------------------------------------------------------------------

# set the default VPN creation mode
DEFAULT_MENU_PROMPT="Select the option you require or type 'q' to quit: "
ARR_REGIONS=(Hamilton Porirua Wellington)
VPN_MODE=""
REGION_1=""
REGION_2=""

# colour data for message prompt
GREEN="\033[92m" # for success output
YELLOW="\033[93m" # for debug output
RED="\033[91m" # for error output
NC='\033[0m' # remove colour from output

#------------------------------------------------------------------------------
# Functions
#------------------------------------------------------------------------------

usage() {
  echo
  cat <<USAGE_DOC
  Usage: ./$(basename $0) [-h]
  This script will assist in the creation of a VPN endpoint or endpoints on the Catalyst Cloud.
  The default behaviour is to create a single VPN endpoint using the selected region.

  -h Print this usage guide
USAGE_DOC
}

parse_args(){
  while getopts mh OPTION; do
    case "$OPTION" in
      # m)
      #   # build a VPN between two regions of a cloud project
      #   MODE="multi"
      #   ;;
      h)
        usage
        exit 0 ;;
      ?)
        usage
        exit 1 ;;
    esac
  done
}

handle_interruptions() {
  exit 130
}

check_credentials() {
  # Look for $OS_* environment variables. If not defined, prompt the user to source
  # their openrc file

  if [[ ${OS_PROJECT_ID} && ${OS_TOKEN} ]] || [[ ${OS_USERNAME} && ${OS_PASSWORD} && ${OS_PROJECT_ID} ]]; then
    OPENRC="True"
  else
    MSG="No cloud credentials found in the current shell session, please source yopur openrc file."
    echo -e "${RED}${MSG}${NC}"
    exit 1
  fi
}

create_menu() {
  MENU_PROMPT="${1}"
  shift
  arrsize=$1
  shift
  arr=$1
  ret_val=""
  PS3="${MENU_PROMPT}"
  select option in "${@}"
  do
    if [ "$REPLY" == "q" ] || [ "$REPLY" == "Q" ]
    then
      echo "Exiting..."
      break;
    elif [ 1 -le "$REPLY" ] && [ "$REPLY" -le $((arrsize)) ]
    then
      # echo "You have selected :  $option"
      echo
      ret_val=$option
      break;
    else
      echo "Incorrect Input: Select a number 1-$arrsize"
    fi
  done
}

get_vpn_choice() {

  echo "----------------------------------------------------------"
  echo " This script will setup a VPN in your project."
  echo " You can select either:"
  echo " a single region that will connect to an external site"
  echo " or"
  echo " a site-to-site vpn between 2 regions for the same project"
  echo "----------------------------------------------------------"
  echo

  myarray=(single site-to-site)
  MENU_PROMPT="Select the VPN option you require or type 'q' to quit: "
  create_menu "${MENU_PROMPT}" ${#myarray[@]} ${myarray[@]}
  VPN_MODE=$ret_val
}

get_vpn_region() {
  if [ $VPN_MODE == "single" ]
  then
    echo "----------------------------------------"
    echo " Select the region for your VPN endpoint"
    echo "----------------------------------------"
    echo

    MENU_PROMPT="Select the VPN option you require or type 'q' to quit: "
    create_menu "${MENU_PROMPT}" ${#ARR_REGIONS[@]} ${ARR_REGIONS[@]}
    REGION_1=$ret_val
  elif [ $VPN_MODE == "site-to-site" ]
  then
    echo "-------------------------------------------------------"
    echo " Select the regions for your site-to-site VPN endpoints"
    echo "-------------------------------------------------------"
    echo

    EXIT="false"
    while [ $EXIT == "false" ]
    do
      for i in 1 2
      do
        MENU_PROMPT="Select region $i for the site-to-site VPN or type 'q' to quit: "
        create_menu "${MENU_PROMPT}" ${#ARR_REGIONS[@]} ${ARR_REGIONS[@]}
        eval REGION_${i}=$ret_val

        if [ $REGION_2 ]
        then
          if [ $REGION_1 != $REGION_2 ]
          then
            EXIT="true"
          else
            echo "error can't use the same region for both endpoints"
          fi
        fi

      done
    done
  else
    echo "ERROR: The VPN mode was not set correctly!"
    exit 1
  fi
}

lookup_region_name() {
  case $1 in
    Hamilton)
      ret_val="nz-hlz-1"
    ;;
    Porirua)
      ret_val="nz-por-1"
    ;;
    Wellington)
      ret_val="nz_wlg_2"
    ;;
  esac
}

check_openstack() {
  hash openstack 2>/dev/null || {
    echo "openstack command line client is not available, please install it before proceeding";
    exit 1;
  }
  # check if openstack command works with current credentials
  export TOKENID=$(openstack token issue -c id -f value)
  if [ -z $TOKENID ]; then
    echo "Unable to get openstack token please checkl that you have sourced your openrc file"
    exit 1
  fi
}

build_vpn() {
  if [ $REGION_1 ]
  then
    # define single region or region_1 endpoint
    lookup_region_name $REGION_1
    OS_REGION_NAME=$ret_val

    echo "Please enter the name of your $REGION_1 router:"
    read -r region_1_router_name;
    if openstack router show "$region_1_router_name" 2>&1 | grep -q "No Router found for"
    then
      MSG="Unable to find router with name $region_1_router_name"
      echo -e  "${RED}${MSG}${NC}"
      echo please ensure you have created the required routers before running this script
      exit;
    fi

    echo "Please enter the name of your $REGION_1 subnet:";
    read -r region_1_subnet_name;
    if openstack subnet show "$region_1_subnet_name" 2>&1 /dev/null | grep -q 'Unable to find subnet with name'
    then
      MSG="No Subnet found for $region_1_subnet_name"
      echo -e  "${RED}${MSG}${NC}"
      echo please ensure you have created the required subnets before running this script
      exit;
    fi
  fi

  if [ $REGION_2 ]
  then
    lookup_region_name $REGION_2
    OS_REGION_NAME=$ret_val
    echo $OS_REGION_NAME

    echo "Please enter the name of your $REGION_2 router:";
    read -r region_2_router_name;
    if openstack router show "$region_2_router_name" 2>&1 /dev/null | grep -q 'Unable to find router with name'
    then
        echo "Unable to find router with name $region_2_router_name"
        echo please ensure you have created the required routers before running this script
        exit;
    fi

    echo "Please enter the name of your $REGION_2 subnet:";
    read -r region_2_subnet_name;
    if openstack subnet show "$region_2_subnet_name" 2>&1 /dev/null | grep -q 'Unable to find subnet with name'
    then
        echo "Unable to find subnet with name $region_2_subnet_name"
        echo please ensure you have created the required subnets before running this script
        exit;
    fi
  fi

  echo "Please enter your pre shared key:";
  read -r pre_shared_key;

  if [[ $REGION_1 && $REGION_2 ]] # This is a site-to-site VPN across regions
  then
      echo "Please enter the $REGION_1 router ip address";
      read -r region_1_router_ip;
      echo "Please enter the $REGION_1 CIDR range";
      read -r region_1_subnet;
      echo

      echo "Please enter the $REGION_2 router ip address";
      read -r region_2_router_ip;
      echo "Please enter the $REGION_2 CIDR range";
      read -r region_2_subnet;

      region_1_peer_router_ip=$region_2_router_ip
      region_1_peer_subnet=$region_2_subnet
      region_2_peer_router_ip=$region_1_router_ip
      region_2_peer_subnet=$region_1_subnet

  elif [ -z $REGION_2 ] # This ss a single endpoint VPN to a remote site
  then
      echo "Please enter the remote peer router ip address";
      read -r remote_peer_router_ip;
      echo "Please enter the remote peer CIDR range";
      read -r remote_peer_subnet;

      region_1_peer_router_ip=$remote_peer_router_ip
      region_1_peer_subnet=$remote_peer_subnet

  fi

  echo
  echo --------------------------------------------------------
  MSG="Proceeding to create VPN with the following credentials:"
  echo -e  "${GREEN}${MSG}${NC}"

  if [ $REGION_1 ]
  then
      echo "Region name = $REGION_1"
      echo "region_1_router_name = $region_1_router_name"
      echo "region_1_subnet_name = $region_1_subnet_name"
      echo "region_1_router_ip = $region_1_router_ip"
      echo "region_1_subnet = $region_1_subnet"
      echo "region_1_peer_router_ip = $region_1_peer_router_ip"
      echo "region_1_peer_subnet = $region_1_peer_subnet"
      echo
  fi
  if [ $REGION_2 ]
  then

      echo "Region name = $REGION_2"
      echo "region_2_router_name = $region_2_router_name"
      echo "region_2_subnet_name = $region_2_subnet_name"
      echo "region_2_router_ip = $region_2_router_ip"
      echo "region_2_subnet = $region_2_subnet"
      echo "region_2_peer_router_ip = $region_2_peer_router_ip"
      echo "region_2_peer_subnet = $region_2_peer_subnet"
      echo
  fi
  # echo "tenant_id = $tenant_id"
  echo "pre_shared_key = $pre_shared_key"
  echo --------------------------------------------------------
  echo

  # build the first endpoint
  if [ $REGION_1 ]
  then
    MSG="creating endpoint for $REGION_1"
    echo -e  "${YELLOW}${MSG}${NC}"
    lookup_region_name $REGION_1
    OS_REGION_NAME=$ret_val

    openstack vpn service create \
    --subnet $region_1_subnet_name \
    --router $region_1_router_name \
    vpn_service

    openstack vpn ike policy create \
    --auth-algorithm sha1 \
    --encryption-algorithm aes-256 \
    --phase1-negotiation-mode main \
    --pfs group14 \
    --ike-version v1 \
    --lifetime units=seconds,value=14400 \
    ike_policy

    openstack vpn ipsec policy create \
    --transform-protocol esp \
    --auth-algorithm sha1 \
    --encryption-algorithm aes-256 \
    --encapsulation-mode tunnel \
    --pfs group14 \
    --lifetime units=seconds,value=3600 \
    ipsec_policy

    openstack vpn ipsec site connection create \
    --initiator bi-directional \
    --vpnservice vpn_service \
    --ikepolicy ike_policy \
    --ipsecpolicy ipsec_policy \
    --dpd action=restart,interval=15,timeout=150 \
    --peer-address $region_1_peer_router_ip \
    --peer-id $region_1_peer_router_ip \
    --peer-cidr $region_1_peer_subnet \
    --psk pre_shared_key \
    vpn_site_connection
  fi

  # build the second endpoint if creating an inter-region VPN
  if [ $REGION_2 ]
  then
    MSG="creating endpoint for $REGION_2"
    echo -e  "${YELLOW}${MSG}${NC}"
    lookup_region_name $REGION_2
    OS_REGION_NAME=$ret_val

    openstack vpn service create \
    --subnet $region_2_subnet_name \
    --router $region_2_router_name \
    vpn_service

    openstack vpn ike policy create \
    --auth-algorithm sha1 \
    --encryption-algorithm aes-256 \
    --phase1-negotiation-mode main \
    --pfs group14 \
    --ike-version v1 \
    --lifetime units=seconds,value=14400 \
    ike_policy

    openstack vpn ipsec policy create \
    --transform-protocol esp \
    --auth-algorithm sha1 \
    --encryption-algorithm aes-256 \
    --encapsulation-mode tunnel \
    --pfs group14 \
    --lifetime units=seconds,value=3600 \
    ipsec_policy

    openstack vpn ipsec site connection create \
    --initiator bi-directional \
    --vpnservice vpn_service \
    --ikepolicy ike_policy \
    --ipsecpolicy ipsec_policy \
    --dpd action=restart,interval=15,timeout=150 \
    --peer-address $region_2_peer_router_ip \
    --peer-id $region_2_peer_router_ip \
    --peer-cidr $region_2_peer_subnet \
    --psk pre_shared_key \
    vpn_site_connection
  fi

  MSG="Your VPN has been created, note that you will need to create appropriate security group rules."
  echo
  echo -e  "${GREEN}${MSG}${NC}"
  echo
}

#------------------------------------------------------------------------------
# Main
#------------------------------------------------------------------------------

# Handle ctrl-c (SIGINT)
trap handle_interruptions INT

parse_args "$@"

check_credentials
check_openstack
get_vpn_choice
get_vpn_region
build_vpn

In this example we are going to set up a VPN connection in the Hamilton region to a remote router in the Porirua region with a public IP 150.242.40.137 that has the private subnet 10.20.30.0/24 connected to it.

In the Hamilton region we already have defined a router named border-router that is connected to the public network and has a subnet called private subnet with a CIDR of 10.0.0.0/24 connected to one of it’s interfaces. The steps to create these resources are covered in Adding a network

To create the VPN connection we are going to use the VPN screen which is accessed by clicking on the VPN item underneath the Network group on the left hand menu of the console:

../_images/lhs-menu-network.png

Using the VPN screen we are going perform the following steps:

  • Create a VPN Service

  • Create a VPN IKE Policy

  • Create a VPN IPSec Policy

  • Create a VPN Endpoint Group for the local subnet

  • Create a VPN Endpoint Group for the peer CIDR

  • Create a VPN IPSec Site Connection

Create a VPN Service

First we select the VPN Service tab and click on the + Add VPN Service button to create a VPN service.

../_images/vpn-services-tab.png

In the Add VPN Service dialog we do the following:

  • name the VPN Service “vpn service”

  • select “border-router” as the router for this VPN service.

Note

We do not select the subnet for the service as this will be done later using the endpoint groups.

../_images/add-vpn-service.png

Click the Add button and the VPN service will be in the Pending Create state, it will become Active when we have completed the IPSec connection.

../_images/vpn-service-pending-create.png

Create IKE Policy

Next we create the IKE policy for the VPN connection by selecting the IKE Policies tab and clicking on the + Add IKE Policy button. In the dialog we named the policy “ike policy” we enter the following:

  • Name: ike policy

  • Encryption algorithm: change to “aes-256”

  • Lifetime value for IKE key: change to 14400

  • Perfect Forward Secrecy: change to “group14”.

../_images/add-ike-policy.png

Create IPsec Policy

Next we are going to create the IPSec policy by selecting the IPsec Policies tab and clicking on the + Add IPsec Policy button. In the Add IPsec Policy dialog we are going to enter the following:

  • Name: ipsec policy

  • Encryption algorithm: aes-256

  • Perfect Forward Secrecy: group14

The other fields we leave as the defaults. Click the Add button and the policy is created.

../_images/add-ipsec-policy.png

Create Endpoint Groups

Next we are going to add to Endpoint Group one for the local subnet and the other for the remote subnet. Recall that the local subnet called private subnet has a CIDR of 10.0.0.0/24 and the remote subnet has a CIDR of 10.20.30.0/24. Select the Endpoint Groups tab and click on the + Add Endpoint Group button. In the Add Endpoint Group dialog we are going to enter the following:

  • Name: local endpoint group

  • Type: Subnet (for local systems)

  • Local System Subnets: tick the box next to “10.0.0.0/24”

Click the Add button to create the endpoint group.

../_images/add-endpoint-group-local.png

Click the + Add Endpoint Group button again and enter the following:

  • Name: peer endpoint group

  • Type: CIDR (for external systems)

  • External System CIDRs: 10.20.30.0/24

Click the Add button to create the endpoint group.

../_images/add-endpoint-group-peer.png

You should now have two endpoint groups:

../_images/endpoint-groups-created.png

Create an IPsec Site Connection

Finally we are able to create the connection by selecting the IPsec Site Connections tab and clicking the + Add IPsec Site Connection button.

In the Add IPsec Site Connection dialog we are entering the following values:

  • Name: vpn site connection

  • VPN service associated with this connection: vpn service

  • Endpoint group for local subnet(s): local endpoint group

  • IKE policy associated with this connection: ike policy

  • IPsec policy associated with this connection: ipsec policy

  • Peer gateway public IPv4/IPv6 Address or FQDN: 150.242.40.137

  • Peer router identity for authentication (Peer ID): 150.242.40.137

  • Endpoint group for remote peer CIDR(s): peer endpoint group

  • Pre-Shared Key (PSK) string: supersecretpsk

Recall that 150.242.40.137 is the public IP address of the remote router.

Note

Leave the Remote peer subnet(s) field blank this is an old method of defining the peer CIDRs which has been replaced by the Endpoint Groups.

../_images/add-ipsec-site-connection.png

Then click Optional Parameters and change the following:

  • Dead peer detection actions: restart

  • Dead peer detection interval: 15

  • Dead peer detection timeout: 150

../_images/add-ipsec-site-connection-optional.png

Click the Add button and the IPsec Site Connection will be created:

../_images/ipsec-site-connection-pending-create.png

Once the IPsec site connection is created the VPN service will become active:

../_images/vpn-service-active.png

This process should be repeated at the other end using the same configuration options and PSK. Once both sides of the VPN are configured, the peers should automatically detect each other and bring up the VPN.