Configure a Site-to-Site VPN Connection with Open Telekom Cloud
Configure a Site-to-Site IPsec VPN Tunnel between your premises and an Open Telekom Cloud VPC using VyOS as software-based router.
Introduction
A Virtual Private Network (VPN) extends a private network across a public network and enables users to exchange data across shared or public networks as if their resources were directly connected.
Open Telekom Cloud is an OpenStack-based public cloud offering from German leading IT services provider T-Systems International GmbH, a subsidiary company of the Deutsche Telekom Group. Open Telekom Cloud offers Infrastructure as a Service (IaaS) from the public cloud. Companies of all sizes and in all industries can obtain computing resources flexibly at the push of a button and benefit from all the advantages of a public cloud environment with the highest security and the strictest data protection according to the GDPR and extreme flexible and competitive price models.
What is the goal ?
After completing this lab, we are going to have configured a virtual private network connection between our premises and Open Telekom Cloud, that allows local network (192.168.1.0/24) devices to communicate with our cloud VPC subnet (10.10.10.0/24) resources.
What are we going to need ?
Let’s break down the picture above to determine the ingredients we are going to need. I assume you have already in place:
- A physical router (192.168.1.1) that provides you internet access and your internal network (192.168.1.0/24) and acts as your DHCP server as well.
- A workstation (desktop or laptop) that lives in your internal network (let’s assume it is the one with IPv4 192.168.1.31). In my case it is an old Asus laptop with i7 and 16GB of RAM running Ubuntu Desktop 22.04 (Jammy Jellyfish). You are going to need some free RAM (circa 4GB) because we are going to spin 2 virtual machines.
- A hypervisor running on your workstation. In my case I used for this lab VirtualBox 7.0, and all networking concepts will be based on how VirtualBox is dealing with internal and external networking for its guests.
- A subscription and a tenant in Open Telekom Cloud.
Additionally we are going to provision:
- A virtual machine (192.168.1.250) in our local network, that will serve as software-based virtual router. This will be our VyOS server running on Debian.
- A virtual machine (192.168.1.36) in our local network. This can be running on any OS you wish but for this lab I chose to use Ubuntu Server 22.04.1 LTS (Jammy Jellyfish).
- A VPC and a Subnet (10.10.10.0/24) in our Open Telekom Cloud tenant.
- A virtual machine (10.10.10.213) in our cloud network — Elastic Cloud Server (ECS) in the Open Telekom Cloud lingo. I chose to use Ubuntu Server 22.04.1 LTS (Jammy Jellyfish) for this as well.
- A Virtual Private Network service between those two networks in our Open Telekom Cloud tenant.
- A temporary Elastic IP Address (EIP) in your tenant — we are going to bind it to virtual machine 10.10.10.213 for testing our VPN connection and then we will discard it as it defies the very purpose of what we are aiming at.
- A Security Group (SG) that we will bind with our cloud virtual machine, and through that we will allow SSH and ICMP protocols.
The rest of the virtual machines depicted in the picture are only for the sake of completeness.
Adjust the IPv4 addresses as you see fit — the ones used above describe my personal network and nothing more.
Provisioning local virtual machines
As I mentioned earlier this lab is going to use VirtualBox to spin virtual machines. If you are not familiar with the tool there are plenty tutorial in the internet to get you on board; for this very article this is out of scope.
While providing the virtual machines make sure you create them with one NIC that is attached to your Bridged Adapter.
IMPORTANT: If you are working on a Mac and your only choice for Bridged is the WiFi adapter, unfortunately for some reason that will not work out. It seems there is an incompatibility on macOS with VirtualBox on that topic.
Install and configure the VyOS Server
Now we have those two virtual machines in place, it is time to prepare one of them to serve as a software-based router. For that matter we are going to use VyOS, a fully open source network OS based on Debian that provides a free routing, firewall, VPN, NAT platform for IPv4 and IPv6 networking. It is derived from the software-based virtual router community edition of Vyatta, Vyatta Core.
If you follow the instructions of another article of mine (sticking to the configuration of the 192.168.1.0/24 network) you will have your software-based router up and running in less than 10mins.
The article above describes a constellation of two local networks one public (192.168.1.0/24) and one private (192.168.56.0/24). In this article we describe how to configure and establish a S2S VPN connection for the former. Of course you can recreate the VPN scenario for the latter one by adjusting the IPSec configuration (on the cloud and on our router) for the second CIDR.
Create VPC and Subnet
Working from Open Telekom Cloud console is quite easy, comfortable and uncomplicated. If you are already acquainted with the AWS console you will feel already being in a familiar place.
First thing first, let’s create a VPC:
Make sure the CIDR you chose is not overlapping with the CIDR block of another VPC!
Create an Elastic Cloud Server
As second step let’s create our cloud virtual machine.
Choose the smallest flavor, our VyOS server won’t need something extraordinary:
Choose the OS of your choice (in this case Ubuntu 22.04) and dial up the hard disk capacity a bit.
Place the ECS instance in the subnet we just created and although we mention since the beginning that this is going to be 10.10.10.213 (it was just for the sake of explaining the high level view — it doesn’t play any significant role) let is get an automatically assigned IP address.
Let Open Telekom Cloud assign an EIP to this instance or create one yourself. It doesn’t really matter as long as you still have available EIPs based on your quotas and your utilization.
Create a Security Group, add new two Inbound Rules allowing SSH and ICMP protocols and come back to this wizard. Refresh the dropbox and assign additionally this SG to your instance.
Last step, we are going to create a Key Pair in order to be able to access this machine via SSH:
Run through the rest of the wizard steps and wait till your ECS instance is provisioned.
Create an Elastic Cloud Server
Getting closer to finish up our cloud resource needs. Last in the list to create a Virtual Private Network.
As VPC declare the network we create before, and don’t specify a CIDR block but select the subnet we created in that VPC. As Remote Gateway declare the public IP address of your premises (the one you get from your ISP). Remote Subnet should be the CIDR block of your local network, 192.168.1.0/24 (or alternatively 192.168.56.0/24 if you chose to go for the private network — but here we are discussing the first).
You can have multiple Remote Subnets, and create discrete tunnels for each one of them.
Enter a Private Shared Key (PSK) and you are almost there.
Create the VPN and wait till it’s provisioned. We are going to see that our VPN acquired an additional public IP address (Local Gateway) that is practically the IP address for the cloud gateway.
Click Modify and adjust your IKE and IPSEC policies as you see in the picture below, click OK and wait till VPN resource makes the necessary updates. While waiting we can jump back to our VyOS server and start configuring the VPN connection from the customer’s side.
Configure IPSec S2S VPN connection on VyOS
At this point we have everything needed in place on our cloud tenant. It’s to configure our VyOS server so we can establish a VPN connection between the two networks.
Let’s lay the base of IPSec configuration, which interface we are going to use and our log level:
set vpn ipsec interface 'eth0'
set vpn ipsec log level '1'
set vpn ipsec log subsystem 'any'
Then we are going to provide the exact same IKE Policy we created on the remote side:
set vpn ipsec ike-group otc-eu-de-ike key-exchange 'ikev1'
set vpn ipsec ike-group otc-eu-de-ike lifetime '86400'
set vpn ipsec ike-group otc-eu-de-ike proposal 1 encryption 'aes256'
set vpn ipsec ike-group otc-eu-de-ike proposal 1 hash 'sha1'
set vpn ipsec ike-group otc-eu-de-ike proposal 1 dh-group '14'
Respectively we then going to provide the IPsec Policy we set in our Open Telekom Cloud VPN resource:
set vpn ipsec esp-group otc-eu-de-esp lifetime '3600'
set vpn ipsec esp-group otc-eu-de-esp mode 'tunnel'
set vpn ipsec esp-group otc-eu-de-esp pfs 'enable'
set vpn ipsec esp-group otc-eu-de-esp proposal 1 encryption 'aes256'
set vpn ipsec esp-group otc-eu-de-esp proposal 1 hash 'sha1'
and lastly we are going to configure our IPsec Site-to-Site connection:
set vpn ipsec interface 'eth0'
set vpn ipsec site-to-site peer OTC authentication mode 'pre-shared-secret'
set vpn ipsec site-to-site peer OTC authentication pre-shared-secret 'XXX'
set vpn ipsec site-to-site peer OTC authentication remote-id 'X.X.X.X'
set vpn ipsec site-to-site peer OTC ike-group 'otc-eu-de-ike'
set vpn ipsec site-to-site peer OTC local-address '192.168.1.250'
set vpn ipsec site-to-site peer OTC remote-address 'XXX'
set vpn ipsec site-to-site peer OTC tunnel 0 esp-group 'otc-eu-de-esp'
set vpn ipsec site-to-site peer OTC tunnel 0 local prefix 192.168.1.0/24
set vpn ipsec site-to-site peer OTC tunnel 0 remote prefix 10.10.10.0/24
As authentcation remote-id
and remote-address
we are going to set the Local Gateway IP address that was automatically assigned to our VPN when we created in the cloud (eg. 80.X.X.X).
As authentication pre-shared-secret
we are going to use the PSK we entered in our VPN creation wizard.
Let’s make the first rain check to see if we have a connection:
show vpn ipsec sa
And we have success, we are connected! Let’s see what changed on the Open Telekom Cloud console:
If you want to constantly monitor your connection from the customer’s side you can use the following command:
monitor command 'show vpn ipsec sa'
Configure the default route of our local VM
Last piece of the puzzle is to logon to our Ubuntu virtual machine in our local network and define an additional default route via the VyOS Server:
sudo ip route add default via 192.168.1.250
Check connectivity
From the customer side, logon to your second Ubuntu virtual machine and ping the ECS instance using its private IP address (e.g 10.10.10.213):
It goes through! Now let’s try from the other end. Connect via SSH to your ECS instance using its public IP address, the EIP we bound with it (eg. 80.X.X.X) and the Key Pair associated with it, and ping the Ubuntu instance in our local network using its private IP address (e.g 192.168.1.36)
ssh -i KeyPair.pem ubuntu@EIP
It goes through as well! We finally achieved to expand our local network to a VPC in the cloud and establish bidirectional communication.
Dynamically update the IP of the Remote Gateway
Usually ISP providers will refresh your dynamic IP address in a span of 24 hours. In the absence of a static IP on your premises that will break the connection minimum on a daily basis. That means that without a static IP address you will lose your VPN connection in a daily basis if you don’t resort to an automated way to alter your Remote Gateway’s IP address in an unattended fashion.
Open Telekom Cloud is an Openstack-based cloud and utilised a fork of Openstack Go SDK (gophercloud, initially developed by Rackspace) to support the programmatic access to its resources.
GopherTelekomCloud is the official Go SDK for Open Telekom Cloud and has some additional features than the original SDK. Nevertheless the way using it remain the same.
First thing we have to do is to import the right package and its dependencies:
import (
opentelekomcloud "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/openstack"
)
and populate the AuthOptions
struct with your access details:
// Option 1: Pass the values manually
authOptions := opentelekomcloud.AuthOptions{
IdentityEndpoint: "https://iam.eu-de.otc.t-systems.com/v3",
Username: "{username}",
Password: "{password}",
TenantID: "{tenant_id}",
}
// Option 2: Retrieve all the auth options from your environment variables
authOptions, err := opentelekomcloud.AuthOptionsFromEnv()
In this example we will go for the second option, create a new file and export as environmental variables your access details:
export OS_AUTH_URL="https://iam.eu-de.otc.t-systems.com/v3"
export OS_USERNAME="{username}"
export OS_PASSWORD="{password}"
export OS_DOMAIN_NAME="{domain_id}"
export OS_TENANT_NAME="{tenant_name}"
export OS_OTC_ACCESSKEY="{access_key}"
export OS_OTC_SECRETKEY="{secret_key}"
export OS_OTC_REGION="eu-de"
You can either use your credentials or your Access & Secret Keys pair. It’s up to you to choose.
Once we populated the AuthOptions
struct we need to use it as an input param in order to acquire a ProviderClient
instance, that is the top-level client that all of your OpenStack (and eventually Open Telekom Cloud) services derive from. The provider contains all of the authentication details that allow your Go code to access the API — such as the base URL and token ID.
authOptions, err := openstack.AuthOptionsFromEnv()
if err != nil {
klog.Fatalln(err)
}
providerClient, err := openstack.AuthenticatedClient(authOptions)
if err != nil {
klog.Fatalln(err)
}
Next, we have to identify our current IP address, that is assigned to us from our ISP, by calling the addresshttps://myexternalip.com/raw
:
func getExternalIP() (string, error) {
resp, err := http.Get(externalIpRawUrl)
if err != nil {
return "", err
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
klog.Errorln(err)
}
}(resp.Body)
ipaddress, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(ipaddress), nil
}
Then we have to retrieve our VPN connection resource given its internal unique identifier (this one you can find it in Open Telekom Cloud console)
func getIPSecConnection(id string) (*ipsec.Connection, error) {
client, err := openstack.NewNetworkV2(provider, opentelekomcloud.EndpointOpts{
Region: *region,
})
if err != nil {
return nil, err
}
connection, err := ipsec.Get(client, id).Extract()
if err != nil {
return nil, err
}
return connection, nil
}
If the our current IP address is different than the PeerAddress
of the connection (the IP address we entered in our Remote Gateway manually earlier in this article) then we can proceed and change its value:
if connection.PeerAddress != externalIp {
err := updateIPSecConnection(*ipSecConnectionId, externalIp)
if err != nil {
klog.Fatalln(err)
}
} else {
klog.Infoln("skip update, no ip address change...")
}
func updateIPSecConnection(id string, ipaddress string) error {
klog.Infof("updating ipsec connection peer-address to %v...", ipaddress)
client, err := openstack.NewNetworkV2(provider, opentelekomcloud.EndpointOpts{
Region: *region,
})
if err != nil {
return err
}
updateOpts := ipsec.UpdateOpts{
PeerAddress: ipaddress,
}
_, err = ipsec.Update(client, id, updateOpts).Extract()
if err != nil {
return err
}
klog.Infof("updated ipsec connection peer-address to %v...", ipaddress)
return nil
}
and simple as that you have updated now your IP address eliminating the need of having a dedicated static IP address from your ISP saving you significant costs.
The VPN connection needs though some time to modify its PeerAddress, and that means that you might experience some downtime in your VPN connections, perhaps on a daily basis.
Summary
That’s a simple and straightforward way to set up a VPN connection between your premises and Open Telekom Cloud without resorting to expensive solutions like buying a static IP or dedicated routing hardware. When it comes to the dynamic IP address update, you are welcome to refine the code to be more production-ready and make it run periodically as a Linux or Kubernetes CronJob.
You can find the whole code for the updater in the repository below: