Build an OpenVPN Server inside Google Kubernetes Engine (GKE)

Fauzan
4 min readMay 23, 2021

--

When we have our service deployed in the cloud, we surely need to think about security of our services. This is commonly become a reason for us to build a VPN connection between our server to our local machine, to reduce attack vector.

At AWS, we can create VPN profile client directly from the console. But unlike AWS, GCP doesn’t have that feature which means that we need to build the openvpn server manually to server.

https://stackoverflow.com/a/65077666/6822338

In my case, I have 2 GKE clusters (staging & production) which most of our service is running in, so instead of creating OpenVPN in a VM Instance, I choose to deploy it inside the staging kubernetes cluster. In this article, I’m gonna show you how to deploy an openvpn server inside kubernetes to connect to the internal kubernetes network and gcp vpc network.

  1. Download openvpn helm chart to local helm repository.
helm repo add stable http://storage.googleapis.com/kubernetes-charts;
helm pull stable/openvpn;
tar -xzvf openvpn-4.2.5.tgz

2. Open the project and open up values.yaml file. Here we would change many variables based on our kubernetes cluster and google vpc network configuration. Below is some variable I modified from default:

This is needed for the client to be able to connect to the internet.

# Add privileged init container to enable IPv4 forwardingipForwardInitContainer: true

Adjust OVPN_K8S_POD_NETWORK, OVPN_K8S_POD_SUBNET with value from our kubernetes cluster.

openvpn:
# Network allocated for openvpn clients (default: 10.240.0.0).
OVPN_NETWORK: 10.240.0.0# Network subnet allocated for openvpn client (default: 255.255.0.0).OVPN_SUBNET: 255.255.255.0# Protocol used by openvpn tcp or udp (default: udp).OVPN_PROTO: tcp# Kubernetes pod network (optional).OVPN_K8S_POD_NETWORK: 10.228.0.0# Kubernetes pod network subnet (optional).OVPN_K8S_POD_SUBNET: 255.252.0.0# Override default ciphercipher: BF-CBC

For variable OVPN_SUBNET, because I think we would not use this client more than 254 clients so I reduced this to 255.255.255.0 to make it efficient.

For the cipher, with this default value AES-256-CBC, I got an error and the vpn server somehow is not be able to receive any connection, I assumed that with this chiper model , there’s some extra configuration needed to make this works. Instead of having extra time to research and configure this chiper, for now I used the fallback chiper model of BF-CBC, which is less secure.

3. For the vpn client to connect to gcp vpc, add a route configuration based on you gcp vpc network configuration.

Open file openvpn/templates/config-openvpn.yaml and add a route like below.

{{ if and (.Values.openvpn.OVPN_K8S_SVC_NETWORK) (.Values.openvpn.OVPN_K8S_SVC_SUBNET) }}push "route {{ .Values.openvpn.OVPN_K8S_SVC_NETWORK }} {{ .Values.openvpn.OVPN_K8S_SVC_SUBNET }}"{{ end }}push "route 192.168.100.0 255.255.255.0"push "route 192.168.101.0 255.255.255.0"push "route 192.168.102.0 255.255.255.0"push "route 192.168.103.0 255.255.255.0"{{ if .Values.openvpn.dhcpOptionDomain }}OVPN_K8S_SEARCH

4. All is done and just need to be applied.

cd openvpn-helm-chart;
helm install openvpn .

the installation would show some steps to get the vpn client configuration.
more likely we should run a command like this.

POD_NAME=$(kubectl get pods --namespace "{{ .Release.Namespace }}" -l "app={{ template "openvpn.name" . }},release={{ .Release.Name }}" -o jsonpath='{ .items[0].metadata.name }')SERVICE_NAME=$(kubectl get svc --namespace "{{ .Release.Namespace }}" -l "app={{ template "openvpn.name" . }},release={{ .Release.Name }}" -o jsonpath='{ .items[0].metadata.name }')SERVICE_IP=$(kubectl get svc --namespace "{{ .Release.Namespace }}" "$SERVICE_NAME" {{"-o go-template='{{ range $k, $v := (index .status.loadBalancer.ingress 0)}}{{ $v }}{{end}}'"}})KEY_NAME=kubeVPNkubectl --namespace "{{ .Release.Namespace }}" exec -it "$POD_NAME" /etc/openvpn/setup/newClientCert.sh "$KEY_NAME" "$SERVICE_IP"kubectl --namespace "{{ .Release.Namespace }}" exec -it "$POD_NAME" cat "/etc/openvpn/certs/pki/$KEY_NAME.ovpn" > "$KEY_NAME.ovpn"

That is all, for this configuration. I didn’t cover how I use LDAP authentication for the VPN server, so with just openvpn client and .ovpn configuratin it should be able to establish the connection, maybe on another article I will make it.

If you have any question just comment below, I surely will respond when I have a free time.

--

--