Virtual Private Network (IPsec)
The following instructions will deploy a virtual machine acting as an edge VPN endpoint for IPsec site to site connection. It is based on StrongSwan which is a complete IPsec solution providing encryption and authentication to servers and clients. It can be used to secure communications with remote networks, so that connecting remotely is the same as connecting locally.
The full documentation is available here.
These 2 Public Cloud examples can be partly deployed using these two HEAT
templates : vpn_simple.yaml & node.yaml
Once downloaded on your computer run this OpenStack command adjusting the parameters accordingly to your environment:
$ openstack stack create -t vpn_simple.yaml --parameter key_name=yubikey-taylor test --wait
2022-04-19 07:18:37Z [test]: CREATE_IN_PROGRESS Stack CREATE started
2022-04-19 07:18:37Z [test.dmz_security_group]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:38Z [test.dmz_security_group]: CREATE_COMPLETE state changed
2022-04-19 07:18:38Z [test.random_password]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:38Z [test.random_password]: CREATE_COMPLETE state changed
2022-04-19 07:18:39Z [test.dmz_router]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:40Z [test.nodes_net]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:40Z [test.nodes_net]: CREATE_COMPLETE state changed
2022-04-19 07:18:40Z [test.nodes_subnet]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:41Z [test.nodes_group]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:41Z [test.nodes_group]: CREATE_COMPLETE state changed
2022-04-19 07:18:41Z [test.nodes_subnet]: CREATE_COMPLETE state changed
2022-04-19 07:18:42Z [test.sg_nodes]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:42Z [test.sg_nodes]: CREATE_COMPLETE state changed
2022-04-19 07:18:42Z [test.sg_nodes_rule_dmz]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:42Z [test.sg_nodes_rule_udp]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:42Z [test.nodes]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:42Z [test.sg_nodes_rule_tcp]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:43Z [test.sg_nodes_rule_dmz]: CREATE_COMPLETE state changed
2022-04-19 07:18:43Z [test.sg_nodes_rule_udp]: CREATE_COMPLETE state changed
2022-04-19 07:18:43Z [test.sg_nodes_rule_tcp]: CREATE_COMPLETE state changed
2022-04-19 07:18:43Z [test.dmz_net]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:43Z [test.dmz_net]: CREATE_COMPLETE state changed
2022-04-19 07:18:43Z [test.dmz_subnet]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:43Z [test.dmz_router]: CREATE_COMPLETE state changed
2022-04-19 07:18:43Z [test.dmz_router_nodes_patch]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:44Z [test.dmz_subnet]: CREATE_COMPLETE state changed
2022-04-19 07:18:44Z [test.dmz_router_dmz_patch]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:47Z [test.dmz_router_nodes_patch]: CREATE_COMPLETE state changed
2022-04-19 07:18:47Z [test.dmz_router_dmz_patch]: CREATE_COMPLETE state changed
2022-04-19 07:18:47Z [test.dmzhost_port]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:49Z [test.dmzhost_port]: CREATE_COMPLETE state changed
2022-04-19 07:18:49Z [test.dmzhost_port_floating_ip]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:52Z [test.dmzhost_port_floating_ip]: CREATE_COMPLETE state changed
2022-04-19 07:18:52Z [test.sg_dmz_rule_self]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:52Z [test.dmzhost]: CREATE_IN_PROGRESS state changed
2022-04-19 07:18:52Z [test.sg_dmz_rule_self]: CREATE_COMPLETE state changed
2022-04-19 07:19:06Z [test.nodes]: CREATE_COMPLETE state changed
2022-04-19 07:19:08Z [test.dmzhost]: CREATE_COMPLETE state changed
2022-04-19 07:19:08Z [test]: CREATE_COMPLETE Stack CREATE completed successfully
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| id | 8af838ef-8ddf-46fe-8c0c-6f794cf8e96a |
| stack_name | test |
| description | No description |
| creation_time | 2022-04-19T07:18:36Z |
| updated_time | None |
| stack_status | CREATE_COMPLETE |
| stack_status_reason | Stack CREATE completed successfully |
+---------------------+--------------------------------------+
Once the stack is created you can retrieve the vpn IP using for example this command:
openstack stack show test
+-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
| Field | Value |
+-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
| id | 8af838ef-8ddf-46fe-8c0c-6f794cf8e96a |
| stack_name | test |
| description | No description |
| creation_time | 2022-04-19T07:18:36Z |
| updated_time | None |
| stack_status | CREATE_COMPLETE |
| stack_status_reason | Stack CREATE completed successfully |
| parameters | OS::project_id: f8e2d506252c4961ad0fa321abf1f1b5 |
| | OS::stack_id: 8af838ef-8ddf-46fe-8c0c-6f794cf8e96a |
| | OS::stack_name: test |
| | dmz_flavor: a1-ram2-disk20-perf1 |
| | key_name: yubikey-taylor |
| | nodes_flavor: a2-ram4-disk50-perf1 |
| | nodes_image: Debian 11.3 bullseye |
| | public_network: ext-floating1 |
| | |
| outputs | - description: Floating IP of the VPN host |
| | output_key: dmz_public_ip |
| | output_value: 195.15.246.193 |
| | - description: For Windows servers only, login password |
| | output_key: admin_pass |
| | output_value: |
| | - ikP4NYAk |
| | - usns10xz |
| | - description: Nodes ip addresses |
| | output_key: nodes_ips |
| | output_value: |
| | - 10.0.0.137 |
| | - 10.0.0.250 |
| | |
| links | - href: https://api.pub1.infomaniak.cloud/orchestration-api/v1/f8e2d506252c4961ad0fa321abf1f1b5/stacks/test/8af838ef-8ddf-46fe-8c0c-6f794cf8e96a |
| | rel: self |
| | |
| deletion_time | None |
| notification_topics | [] |
| capabilities | [] |
| disable_rollback | True |
| timeout_mins | None |
| stack_owner | PCU-XDS7FSZ |
| parent | None |
| stack_user_project_id | 78f32027adf44cf29e1303b1b12b1995 |
| tags | [] |
| | |
+-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+
Now you can jump to the step 7 (7-configure-strongswan) for the example1 or to the step 4 (configure-the-windows-10-vpn) for the example 2
Example 1 : Site to site connection
In this example we will expose the private subnet 10.0.0.0/24
located inside the Public Cloud to an external server through an IPsec connection.
Create the network architecture required for this tutorial
1. Create the VPN network, subnet and router
taylor@laptop:~$ openstack router create vpn-router
taylor@laptop:~$ openstack network create vpn-network
taylor@laptop:~$ openstack subnet create vpn-subnet --network vpn-network --subnet-range 192.168.0.0/24 --gateway 192.168.0.1 --dns-nameserver 83.166.143.51 --dns-nameserver 83.166.143.52
taylor@laptop:~$ openstack router add subnet vpn-router vpn-subnet
2. connect the router VPN router to the internet
taylor@laptop:~$ openstack router set --external-gateway ext-floating1 vpn-router
3. Create the VM that will be the infomaniak VPN endpoint
taylor@laptop:~$ openstack server create --flavor a2-ram4-disk20-perf1 --key-name yubikey-taylor --network vpn-network --image "Debian 11 bullseye" vpn
4. Create a Security Group and remove the default one
taylor@laptop:~$ openstack security group create vpn-securitygroup
taylor@laptop:~$ openstack security group rule create --protocol tcp --dst-port 22 --ethertype IPv4 vpn-securitygroup
taylor@laptop:~$ openstack security group rule create --protocol udp --dst-port 500 --ethertype IPv4 vpn-securitygroup
taylor@laptop:~$ openstack security group rule create --protocol udp --dst-port 4500 --ethertype IPv4 vpn-securitygroup
taylor@laptop:~$ openstack security group rule create --protocol esp --ethertype IPv4 vpn-securitygroup
taylor@laptop:~$ openstack server add security group vpn vpn-securitygroup
taylor@laptop:~$ openstack server remove security group vpn default
5. Add a Floating IP to the VPN VM
taylor@laptop:~$ openstack floating ip create ext-floating1
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| created_at | 2021-09-21T11:04:49Z |
| description | |
| dns_domain | None |
| dns_name | None |
| fixed_ip_address | None |
| floating_ip_address | 195.15.244.244 |
| floating_network_id | 0f9c3806-bd21-490f-918d-4a6d1c648489 |
| id | 157f41c9-eea3-4491-a827-63b306d53277 |
| name | 195.15.244.244 |
| port_details | None |
| port_id | None |
| project_id | 1cd2e93b8a95454e906ff3bb2f99b103 |
| qos_policy_id | None |
| revision_number | 0 |
| router_id | None |
| status | DOWN |
| subnet_id | None |
| tags | [] |
| updated_at | 2021-09-21T11:04:49Z |
+---------------------+--------------------------------------+
Associate the floating IP to the VM. Replace 195.15.244.244
accordingly to your setup
taylor@laptop:~$ openstack server add floating ip vpn 195.15.244.244
6. Install and configure StrongSwan
Connect to the VM created previously
taylor@laptop:~$ ssh debian@195.15.244.244
debian@vpn:~$ sudo apt update
debian@vpn:~$ sudo apt upgrade
debian@vpn:~$ sudo apt install strongswan strongswan-pki
debian@vpn:~$ sudo sysctl -w net.ipv4.conf.ens3.send_redirects=1
debian@vpn:~$ echo "1" | sudo tee /proc/sys/net/ipv4/ip_forward
Make the sysctl parameters persistent in case of reboot by editing /etc/sysctl.d/99-sysctl.conf
as follow :
root@vpn:~# sysctl -p
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 1
7. Configure StrongSwan
Edit the file /etc/ipsec.secrets
and choose a strong PSK (Pre Shared Key).
# This file holds shared secrets or RSA private keys for authentication.
# RSA private key for this host, authenticating it to any other host
# which knows the public part.
infomaniak-endpoint external-endpoint : PSK "Replace This with A very strong and very long string!"
Edit the file /etc/ipsec.conf
and replace the IPs accordingly to your setup.
192.168.0.35
= infomaniak vpn VM local IP
195.15.226.142
= IP of the external endpoint
# ipsec.conf - strongSwan IPsec configuration file
# basic configuration
config setup
# strictcrlpolicy=yes
# uniqueids = no
# Add connections here.
conn infomaniak_VPN
keyexchange=ikev2
left=192.168.0.35
leftsubnet=10.0.0.0/24
leftid=infomaniak-endpoint
leftfirewall=no
leftsendcert=never
right=195.15.226.142
rightsubnet=10.135.0.0/24
rightid=external-endpoint
auto=route
dpdaction=hold
dpddelay=30s
dpdtimeout=120s
ike=aes128-sha256-modp1536
ikelifetime=3600s
esp=aes128-sha256-modp1536
lifetime=3600s
type=tunnel
authby=psk
debian@vpn:~$ sudo ipsec restart
Starting strongSwan 5.9.1 IPsec [starter]...
debian@vpn:~$ sudo ipsec status
Routed Connections:
infomaniak_VPNaaS{1}: ROUTED, TUNNEL, reqid 1
infomaniak_VPNaaS{1}: 0.0.0.0/32 === 0.0.0.0/32
Security Associations (0 up, 0 connecting):
none
8. Configure the other side the same way but inverse left and right entries. Also in the ipsec.secrets
root@external-endpoint-vm:~# cat /etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
keylife=20m
rekeymargin=3m
keyingtries=1
mobike=no
# basic configuration
conn infomaniak_VPN
keyexchange=ikev2
leftfirewall=no
left=195.15.226.142
leftsubnet=10.135.0.0/24
leftid=external-endpoint
right=195.15.244.244
rightsubnet=10.0.0.0/24
rightid=infomaniak-endpoint
auto=route
dpdaction=hold
dpddelay=30s
dpdtimeout=120s
ike=aes128-sha256-modp1536
ikelifetime=3600s
esp=aes128-sha256-modp1536
lifetime=3600s
type=tunnel
authby=psk
root@external-endpoint-vm:~# cat /etc/ipsec.secrets
# which knows the public part.
external-endpoint infomaniak-endpoint : PSK "Replace This with A very strong and very long string!"
9. Bring up the VPN connection
debian@vpn:~$ sudo ipsec up infomaniak_VPN
10. We add rule allowing the vpn VM to forward the traffic from the remote subnet
taylor@laptop:~$ VM_PORT=$(openstack port list --server vpn -c id -f value)
taylor@laptop:~$ openstack port set --allowed-address ip-address=10.135.0.0/24 ${VM_PORT}
11. We create a static route on the vpn router so the traffic from the local subnets to the remote subnet goes through the VPN
taylor@laptop:~$ openstack router add route --route destination=10.135.0.0/24,gateway=192.168.0.35 vpn-router
At this point the private VM should be accessible from the external endpoint.
12. Exposing a private subnet to the VPN
In this example the subnet 10.0.0.0/24
will be accesible from the external-endpoint. Let's create it and also create a VM on this subnet to confirm it works.
taylor@laptop (pub1|taylor):~$ openstack network create ik-private-net-1
taylor@laptop (pub1|taylor):~$ openstack subnet create ik-private-subnet-1 --network ik-private-net-1 --subnet-range 10.0.0.0/24 --gateway 10.0.0.1 --dns-nameserver 83.166.143.51 --dns-nameserver 83.166.143.52
taylor@laptop (pub1|taylor):~$ openstack router add subnet vpn-router ik-private-subnet-1
taylor@laptop (pub1|taylor):~$ openstack server create --flavor a2-ram4-disk20-perf1 --key-name yubikey-taylor --network ik-private-net-1 --image "Debian 11 bullseye" ik-private-subnet-1-vm-1
taylor@laptop (pub1|taylor):~$ openstack security group rule create --protocol tcp --dst-port 22 --ethertype IPv4 default
taylor@laptop (pub1|taylor):~$ openstack security group rule create --protocol icmp default
Example 2 : Site to win10 client ikev2 connnection
Assuming you followed step 1 to 6 of the previous Example :
1. Generate the certificates
root@vpn:~# mkdir -p /root/strongswan-pki/{cacerts,certs,private}
root@vpn:~# chmod 600 /root/strongswan-pki/
root@vpn:~# pki --gen --type rsa --size 4096 --outform pem > /root/strongswan-pki/private/ca-key.pem
root@vpn:~# pki --self --ca --lifetime 3650 --in /root/strongswan-pki/private/ca-key.pem --type rsa --dn "CN=StrongSwan VPN root CA" --outform pem > /root/strongswan-pki/cacerts/ca-cert.pem
root@vpn:~# pki --gen --type rsa --size 4096 --outform pem > /root/strongswan-pki/private/server-key.pem
root@vpn:~# pki --pub --in /root/strongswan-pki/private/server-key.pem --type rsa | pki --issue --lifetime 1825 \
--cacert /root/strongswan-pki/cacerts/ca-cert.pem --cakey /root/strongswan-pki/private/ca-key.pem \
--dn "CN=195.15.244.244" --san 195.15.244.244 --san @195.15.244.244 \
--flag serverAuth --flag ikeIntermediate --outform pem > /root/strongswan-pki/certs/server-cert.pem
Copy the certificates in the /etc/ipsec.d
directory
root@vpn:~# cp -r /root/strongswan-pki/* /etc/ipsec.d/
2. Configure the ikev2 StrongSwan connection
Add this in /etc/ipsec.conf
to configure the ikev2 connection. Change the IPs accordingly to your setup
conn ikev2
auto=add
compress=no
type=tunnel
keyexchange=ikev2
fragmentation=yes
forceencaps=yes
dpdaction=clear
dpddelay=300s
rekey=no
left=%any
leftid=195.15.244.244
leftcert=server-cert.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
right=%any
rightid=%any
rightauth=eap-mschapv2
rightsourceip=10.0.0.0/24
rightdns=83.166.143.51,83.166.143.52
rightsendcert=never
eap_identity=%identity
edit /etc/ipsec.secrets
to add the private key name and to add users and passwords, in our case we add the user taylor
: RSA "server-key.pem"
taylor : EAP "My_veRy_Str0NG_paSsword!"
root@vpn:~# ipsec restart
3. Configure iptables
root@vpn# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o ens3 -m policy --pol ipsec --dir out -j ACCEPT
root@vpn# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o ens3 -j MASQUERADE
4. Configure the Windows 10 VPN
Copy/Paste the full content of /etc/ipsec.d/cacerts/ca-cert.pem
somewhere on the win10 client computer for, example C:\ik\ik-vpn-ca-cert.pem
Open an admin powerShell and import the certificate
Import-Certificate -CertStoreLocation cert:\LocalMachine\Root\ -FilePath C:\ik\ik-vpn-ca-cert.pem
5. Create the VPN connection
Add-VpnConnection -Name "Infomaniak VPN Connection"
-ServerAddress "195.15.244.244"
-TunnelType "IKEv2"
-AuthenticationMethod "EAP"
-EncryptionLevel "Maximum"
-RememberCredential
You should see a new VPN connection available. Press WINDOWS+Q
and search for VPN settings
. You should then see your connection, click conenct and you' ll be prompted for user/password configured earlier.
You might need to adjust the routing on the windows client side, for example
Get the VPN network intefarce ID
PS C:\WINDOWS\system32> Get-NetIPInterface
Then add the route
PS C:\WINDOWS\system32> New-NetRoute -DestinationPrefix "10.0.0.0/24" -InterfaceIndex 80