How to setup a VPN connection from inside a pod in Kubernetes

So your corporation want to move an application inside your awesome cluster, but the application requires access to another network. So how do we setup a VPN client from our docker container running in our Kubernetes cluster? I’ll explain how I managed to setup a point-to-point connection from inside a pod in Kubernetes using OpenVPN and a little scripting.

First off, we need a base image to start with. The best approach is using the base image your application requiring VPN runs on.

I’ll use the microsoft/aspnetcore:1.1.1 image as my base image.

There are two approaches to this.

build a new image from our base image, that our application then will use moving forward. setup the whole thing in 1 Dockerfile and build the whole thing every time. The first one is probably preferred since you’ll save time on every build going forward. It’s the one I would go with. But to start off, we’ll just use a single Dockerfile.

The Dockerfile

So let’s start by adding OpenVPN to our base image and adding our credentials to it.

Two approaches as to how you wanna add your VPN informations to the container.

Copy it in when you build it Mount it as a volume in Kubernetes The second approach is the more secure and correct way of doing so. But the first one is the easiest and the one I will be using for the sake of simplicity.

FROM microsoft/aspnetcore:1.1.1
RUN apt-get update \
 && apt-get install -y openvpn \
 && rm -rf /var/lib/apt/lists/*
COPY ./vpn /etc/openvpn
COPY ./ .
COPY ./ .
CMD sh ./

So nothing fancy here really. We install OpenVPN and copy the content of our vpn folder to the openvpn folder.

Other than that we copy the path for your app inside the app folder together with a script and then run the script to start the container.

You’ll want to put all your OpenVPN files in the vpn folder. Now I am no expert here. My setup was an .ovpn followed by a ca.crt, ca.key, client.crt and a client.key file for my point-to-point VPN connection.

The startup script

mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
cd /etc/openvpn/
openvpn --config client.ovpn --daemon .
dotnet /app/myapp.dll

Now the script makes the necessary steps that make it possible for OpenVPN to communicate out of the container. The tun device driver allows packet reception and transmission for user space programs e.g OpenVPN. You can read more about it in the Kernel TUN device driver documentation.

On line 7, OpenVPN is started using our .opvn file. It is run as a background process with the –daemon flag.

On line 8, we start up the application in need of our VPN connection.

Now after building the image. You should run it, but it needs NET_ADMIN capabilities like this:

docker build -t myimage .
docker run --cap-add NET_ADMIN myimage

Making the VPN container work in Kubernetes

Now when the container is build the way it is. It is pretty simple to make it work with Kubernetes. Basically we just need to add the same capabilities to the container in Kubernetes, as we did in Docker.

apiVersion: extensions/v1beta1
kind: Deployment
  name: myapi
  replicas: 1
        app: myapi
      - name: myapi
        image: myapi:v1
        - containerPort: 80
              - NET_ADMIN
        - name: repository-secret

The important part is on line 17-20. Those 4 lines do the same thing as –cap-add=NET_ADMIN did when running the container with Docker.

Thats it! You should now have a container with a VPN connection running inside your Kubernetes cluster!

I hope you found this useful! Please do not hesitate to reach out in the comments or at @karnich.

Posted in Docker, Kubernetes
Write a comment