VPNaaS Simplified on Fujitsu K5

Often on our Cloud surgery calls I’ll have requests on how to go about configuring Virtual Private Networks (IPSec VPNs) between the various public clouds and customer sites.

The purpose of this blog is to demonstrate the process of establishing such a secure tunnel using the VPNaaS feature available on Fujitsu’s Cloud Service K5.

Prerequisites

The biggest key to success here is preparation – most issues are encountered when the customer’s VPN configuration and K5’s VPN configurations are not programmed with the same prerequisites. In order to try and simplify this process for you, here at CNETS we’ve put together a simple VPNaaS template that can be downloaded by clicking on the image below and shared with the customer. Please ensure that this is document is understood, agreed, and completed before trying to build your service – sounds sensible I hope – you’d be surprised at how often people skip this step.

vpndoc

Another prerequisite on your cloud environment is that you have already created the virtual network, subnet, router and added a Global IP (public ip address) to the virtual router.

Once you’ve completed these prerequisites it’s time to start building your VPN.

OpenStack IPSec VPNaaS Tool

Again CNETS come to the rescue, unless you enjoy manually building all the necessary API calls, we’ve built an Angular based User Interface to simplify all the necessary API calls to build and configure your VPNaaS. The tool is located here –  https://cnets-vpnaas.uk-1.cf-app.net/ and needs a valid Fujitsu Cloud Service K5 administrative contract account to login.

VPNTool

I’ve also created the following diagram to illustrate what will be configured in a soon to be published video … as soon as I can get my OBS recording software to start playing nicely again. I will join two subnets across two K5 regions – one subnet is located in our US region and the other subnet is in our UK region. The exact same process is used if configuring K5’s VPNaaS when connecting to VPNaaS offerings in other public/private clouds or customer VPN appliances.

K5NetworkingInterVPN

Note: One fundamental concept that needs to be understood is that you are linking one layer 3 subnet to another layer 3 subnet only. What I mean by this is that in the following example I’ll add the 192.168.10.0/24 subnet in the UK region and the 192.168.0.0/24 subnet in the US region to the IPSec VPN (these subnet CIDRS should not be over-lapping). Once the VPN tunnel is established and the correct security groups applied Server A will be able to communicate with Server C and vice-versa. However, Server B and Server D will NOT be able to communicate. An additional proxy service would be needed on each of the VPN peer subnets to facilitate routing traffic from Server B and Server D through the VPN tunnel.

As it’s near Christmas and we’re full of festive spirit here in CNETS this week (at least I am), I’ve got one final treat – for those of you who like to follow along – below I’ve also included the two heat templates that I’ve used for the demo to build the infrastructure in the diagram above. Don’t forget to change the input parameters and DNS setting to match your target AZ if using them on Fujitsu’s Cloud Service K5. These templates should also work with other OpenStack clouds.

Heat Template Project A

heat_template_version: 2013-05-23
# Author: Graham Land
# Date: 15/11/2017
# Purpose: Demo IPSec VPNaaS – Base for Project A
#
# Twitter: @allthingsclowd
# Blog: https://allthingscloud.eu
#
#
description: Template for VPNaaS (IPSec) Demo Project A – Two Networks and a Router with two Servers A & B
# Input parameters
parameters:
k5_image:
type: string
label: Image name or ID
description: Image to be used for compute instance
default: "Ubuntu Server 16.04 LTS (English) 01"
flavor:
type: string
label: Flavor
description: Type of instance (flavor) to be used
default: "P-1"
ssh_key_pair:
type: string
label: Key name
description: Name of key-pair to be used for compute instance
default: "LEMP-KP-AZ1"
availability_zone:
type: string
label: Availability Zone
description: Region AZ to use
default: "uk-1a"
my_ip:
type: string
label: The IP Address (CIDR format) of My PC on the Internet
description: PC Internet IP Address (CIDR format)
default: "31.53.253.24/32"
# K5 Infrastructure resources to be built
resources:
# Create a private network
private_network_a:
type: OS::Neutron::Net
properties:
availability_zone: { get_param: availability_zone }
name: "Network-A"
# Create a new subnet on the private network
private_subnet_a:
type: OS::Neutron::Subnet
depends_on: private_network_a
properties:
availability_zone: { get_param: availability_zone }
name: "Subnetwork-A"
network_id: { get_resource: private_network_a }
cidr: "192.168.0.0/24"
gateway_ip: "192.168.0.254"
allocation_pools:
start: "192.168.0.100"
end: "192.168.0.150"
dns_nameservers: ["62.60.39.9", "62.60.42.9"]
# Create a second private network
private_network_b:
type: OS::Neutron::Net
properties:
availability_zone: { get_param: availability_zone }
name: "Network-B"
# Create a new subnet on the second private network
private_subnet_b:
type: OS::Neutron::Subnet
depends_on: private_network_b
properties:
availability_zone: { get_param: availability_zone }
name: "Subnetwork-B"
network_id: { get_resource: private_network_b }
cidr: "10.0.0.0/24"
gateway_ip: "10.0.0.254"
allocation_pools:
start: "10.0.0.100"
end: "10.0.0.150"
dns_nameservers: ["62.60.39.9", "62.60.42.9"]
# Create a virtual router
virtual_router:
type: OS::Neutron::Router
properties:
availability_zone: { get_param: availability_zone }
name: "Simple-Virtual-Router"
# Connect an interface on the private network's subnet to the router
virtual_router_interface_1:
type: OS::Neutron::RouterInterface
depends_on: virtual_router
properties:
router_id: { get_resource: virtual_router }
subnet_id: { get_resource: private_subnet_a }
# Connect an interface on the private network's subnet to the router
virtual_router_interface_2:
type: OS::Neutron::RouterInterface
depends_on: virtual_router
properties:
router_id: { get_resource: virtual_router }
subnet_id: { get_resource: private_subnet_b }
# Create security group
security_group:
type: OS::Neutron::SecurityGroup
properties:
description: VPN Security Group
name: VPN-SG
rules:
# allow inbound traffic from remote VPN subnet
remote_ip_prefix: 192.168.10.0/24
protocol: tcp
remote_ip_prefix: 192.168.10.0/24
protocol: icmp
# allow inbound traffic from my remote PC
remote_ip_prefix: { get_param: my_ip }
protocol: icmp
remote_ip_prefix: { get_param: my_ip }
protocol: tcp
port_range_min: 22
port_range_max: 22
################### Server A ################################################################
# Create a system volume for use with the server
server-A-sys-vol:
type: OS::Cinder::Volume
properties:
availability_zone: { get_param: availability_zone }
name: "Server-A-boot-vol"
size: 3
volume_type: "M1"
image : { get_param: k5_image }
server-A-port:
type: OS::Neutron::Port
depends_on: private_network_a
properties:
availability_zone: { get_param: availability_zone }
network_id: { get_resource: private_network_a }
name: "Server-A-Port"
fixed_ips:
subnet_id: { get_resource: private_subnet_a }
security_groups: [{ get_resource: security_group }]
# Build a server using the system volume defined above
server-A:
type: OS::Nova::Server
depends_on: server-A-port
properties:
availability_zone: { get_param: availability_zone }
key_name: { get_param: ssh_key_pair }
image: { get_param: k5_image }
flavor: { get_param: flavor }
admin_user: ubuntu
metadata: { "fcx.autofailover": True }
block_device_mapping: [{"volume_size": "3", "volume_id": {get_resource: server-A-sys-vol}, "delete_on_termination": True, "device_name": "/dev/vda"}]
name: "Server-A"
networks:
port: { get_resource: server-A-port }
###########################################################################################################
################### Server B ################################################################
# Create a system volume for use with the server
server-B-sys-vol:
type: OS::Cinder::Volume
depends_on: private_network_b
properties:
availability_zone: { get_param: availability_zone }
name: "Server-B-boot-vol"
size: 3
volume_type: "M1"
image : { get_param: k5_image }
# Build a server using the system volume defined above
server-B:
type: OS::Nova::Server
properties:
availability_zone: { get_param: availability_zone }
key_name: { get_param: ssh_key_pair }
image: { get_param: k5_image }
flavor: { get_param: flavor }
admin_user: ubuntu
metadata: { "fcx.autofailover": True }
block_device_mapping: [{"volume_size": "3", "volume_id": {get_resource: server-B-sys-vol}, "delete_on_termination": True, "device_name": "/dev/vda"}]
name: "Server-B"
networks:
network: { get_resource: private_network_b }
###########################################################################################################

view raw
VPNDemoProjectA.YML
hosted with ❤ by GitHub

Heat Template Project B

heat_template_version: 2013-05-23
# Author: Graham Land
# Date: 15/11/2017
# Purpose: Demo IPSec VPNaaS – Base for Project B – Two Networks and a Router with two Servers C & D
#
# Twitter: @allthingsclowd
# Blog: https://allthingscloud.eu
#
#
description: Template for VPNaaS (IPSec) Demo Project B – Two Networks and a Router with two Servers C & D
# Input parameters
parameters:
k5_image:
type: string
label: Image name or ID
description: Image to be used for compute instance
default: "Ubuntu Server 16.04 LTS (English) 01"
flavor:
type: string
label: Flavor
description: Type of instance (flavor) to be used
default: "P-1"
ssh_key_pair:
type: string
label: Key name
description: Name of key-pair to be used for compute instance
default: "LEMP-KP-AZ2"
availability_zone:
type: string
label: Availability Zone
description: Region AZ to use
default: "uk-1b"
my_ip:
type: string
label: The IP Address (CIDR format) of My PC on the Internet
description: PC Internet IP Address (CIDR format)
default: "31.53.253.24/32"
# K5 Infrastructure resources to be built
resources:
# Create a private network
private_network_a:
type: OS::Neutron::Net
properties:
availability_zone: { get_param: availability_zone }
name: "Network-C"
# Create a new subnet on the private network
private_subnet_a:
type: OS::Neutron::Subnet
depends_on: private_network_a
properties:
availability_zone: { get_param: availability_zone }
name: "Subnetwork-C"
network_id: { get_resource: private_network_a }
cidr: "192.168.10.0/24"
gateway_ip: "192.168.10.254"
allocation_pools:
start: "192.168.10.100"
end: "192.168.10.150"
dns_nameservers: ["62.60.39.9", "62.60.42.9"]
# Create a second private network
private_network_b:
type: OS::Neutron::Net
properties:
availability_zone: { get_param: availability_zone }
name: "Network-D"
# Create a new subnet on the second private network
private_subnet_b:
type: OS::Neutron::Subnet
depends_on: private_network_b
properties:
availability_zone: { get_param: availability_zone }
name: "Subnetwork-D"
network_id: { get_resource: private_network_b }
cidr: "10.0.10.0/24"
gateway_ip: "10.0.10.254"
allocation_pools:
start: "10.0.10.100"
end: "10.0.10.150"
dns_nameservers: ["62.60.39.9", "62.60.42.9"]
# Create a virtual router
virtual_router:
type: OS::Neutron::Router
properties:
availability_zone: { get_param: availability_zone }
name: "Simple-Virtual-Router"
# Connect an interface on the private network's subnet to the router
virtual_router_interface_1:
type: OS::Neutron::RouterInterface
depends_on: virtual_router
properties:
router_id: { get_resource: virtual_router }
subnet_id: { get_resource: private_subnet_a }
# Connect an interface on the private network's subnet to the router
virtual_router_interface_2:
type: OS::Neutron::RouterInterface
depends_on: virtual_router
properties:
router_id: { get_resource: virtual_router }
subnet_id: { get_resource: private_subnet_b }
# Create security group
security_group:
type: OS::Neutron::SecurityGroup
properties:
description: VPN Security Group
name: VPN-SG
rules:
# allow inbound traffic from remote VPN subnet
remote_ip_prefix: 192.168.0.0/24
protocol: tcp
remote_ip_prefix: 192.168.0.0/24
protocol: icmp
# allow inbound traffic from my remote PC
remote_ip_prefix: { get_param: my_ip }
protocol: icmp
remote_ip_prefix: { get_param: my_ip }
protocol: tcp
port_range_min: 22
port_range_max: 22
################### Server A ################################################################
# Create a system volume for use with the server
server-A-sys-vol:
type: OS::Cinder::Volume
properties:
availability_zone: { get_param: availability_zone }
name: "Server-C-boot-vol"
size: 3
volume_type: "M1"
image : { get_param: k5_image }
server-A-port:
type: OS::Neutron::Port
properties:
availability_zone: { get_param: availability_zone }
network_id: { get_resource: private_network_a }
name: "Server-C-Port"
fixed_ips:
subnet_id: { get_resource: private_subnet_a }
security_groups: [{ get_resource: security_group }]
# Build a server using the system volume defined above
server-A:
type: OS::Nova::Server
depends_on: private_network_a
properties:
availability_zone: { get_param: availability_zone }
key_name: { get_param: ssh_key_pair }
image: { get_param: k5_image }
flavor: { get_param: flavor }
admin_user: ubuntu
metadata: { "fcx.autofailover": True }
block_device_mapping: [{"volume_size": "3", "volume_id": {get_resource: server-A-sys-vol}, "delete_on_termination": True, "device_name": "/dev/vda"}]
name: "Server-C"
networks:
port: { get_resource: server-A-port }
###########################################################################################################
################### Server B ################################################################
# Create a system volume for use with the server
server-B-sys-vol:
type: OS::Cinder::Volume
depends_on: private_network_b
properties:
availability_zone: { get_param: availability_zone }
name: "Server-D-boot-vol"
size: 3
volume_type: "M1"
image : { get_param: k5_image }
# Build a server using the system volume defined above
server-B:
type: OS::Nova::Server
properties:
availability_zone: { get_param: availability_zone }
key_name: { get_param: ssh_key_pair }
image: { get_param: k5_image }
flavor: { get_param: flavor }
admin_user: ubuntu
metadata: { "fcx.autofailover": True }
block_device_mapping: [{"volume_size": "3", "volume_id": {get_resource: server-B-sys-vol}, "delete_on_termination": True, "device_name": "/dev/vda"}]
name: "Server-D"
networks:
network: { get_resource: private_network_b }
###########################################################################################################

view raw
VPNDemoProjectB.YML
hosted with ❤ by GitHub

Video demo to follow shortly.

Happy Tunneling!

Graham

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s