<p>I am looking at how to make OpenVPN client work on a pod's container, I explain what I do, but you can skip all my explanation and offer your solution directly, I don't care replacing all the below with your steps if it works, I want to make my container to use a VPN (ExpressVPN for example) in a way that both external and internal networking works.</p>
<p>I have a docker image that is an OpenVPN Client, it works fine with the command:</p>
<pre class="lang-bash prettyprint-override"><code>docker run --rm -it --cap-add=NET_ADMIN --device=/dev/net/tun my-app /bin/bash
</code></pre>
<p>The docker image had an entry point bash script:</p>
<pre class="lang-bash prettyprint-override"><code>curl https://vpnvendor/configurations.zip -o /app/configurations.zip
mkdir -p /app/open_vpn/ip_vanish/config
unzip /app/configurations.zip -d /app/open_vpn/config
printf &quot;username\npassword\n&quot; &gt; /app/open_vpn/vpn-auth.conf
cd /app/open_vpn/config
openvpn --config ./config.ovpn --auth-user-pass /app/open_vpn/vpn-auth.conf

</code></pre>
<p>It works fine, but when I deploy it as a container in a K8S Pod, it breaks, it is understandable, K8S clusters need internal network communication between the nodes, so the VPN breaks it ... how do I make it work? the Google search was frustrating, none of the solutions worked and there were just a few, there is one with similar issue: <a href="https://stackoverflow.com/questions/65494743/openvpn-client-pod-on-k8s-local-network-unreachable/65504666">OpenVPN-Client Pod on K8s - Local network unreachable</a>
But did not understand it very well, please help.</p>
<p>Since IPVanish is well known, let's take their ovpn example, I use other vendor but had access to an IPVanish account and it does not work either:</p>
<pre class="lang-bash prettyprint-override"><code>client
dev tun
proto udp
remote lon-a52.ipvanish.com 443
resolv-retry infinite
nobind
persist-key
persist-tun
persist-remote-ip
ca ca.ipvanish.com.crt
verify-x509-name lon-a52.ipvanish.com name
auth-user-pass
comp-lzo
verb 3
auth SHA256
cipher AES-256-CBC
keysize 256
tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA
</code></pre>
<p>I accept responses in Golang or YAML it does not matter, although I use go-client, my code for pod creation is:</p>
<pre class="lang-golang prettyprint-override"><code>podObj := &amp;v1.Pod{
        ObjectMeta: metav1.ObjectMeta{
            Name:      &quot;mypod&quot;,
            Namespace: &quot;default&quot;,
        },
        Spec: v1.PodSpec{
            Containers: []v1.Container{
                {
                    Name:            &quot;worker1&quot;,
                    Image:           &quot;192.168.1.138:5000/myimage&quot;,
                    ImagePullPolicy: v1.PullAlways,
                    Stdin: true,
                    TTY:   true,
                    /* Trying to simulate --device=/dev/net/tun I copied the below, but it does not work
// https://garunski.medium.com/openvpn-and-minikube-25511099f8de
                    VolumeMounts: []v1.VolumeMount{
                        {
                            ReadOnly:  true,
                            Name:      &quot;dev-tun&quot;,
                            MountPath: &quot;/dev/net/tun&quot;,
                        },
                    },*/
                    SecurityContext: &amp;v1.SecurityContext{
                        // Taken from https://caveofcode.com/how-to-setup-a-vpn-connection-from-inside-a-pod-in-kubernetes/
                        Privileged: boolPtr(true),
                        Capabilities: &amp;v1.Capabilities{
                            Add: []v1.Capability{
                                &quot;NET_ADMIN&quot;,
                            },
                        },
                    },
                },
            },
            NodeName: &quot;worker-node01&quot;,
        },
    }
clientset.CoreV1().Pods(&quot;default&quot;).Create(context.Background(), podObj, metav1.CreateOptions{})
</code></pre>
<p>I can add the <code>NET_ADMIN</code> capability, but I need also to give access to the <code>/dev/net/tun</code> device and that's the problem, but even If I find a way, it will break internal networking.</p>
<h2>Update one</h2>
<p>I made external networking work, by adding the following two lines in my docker's entry point:</p>
<pre class="lang-bash prettyprint-override"><code># Taken from https://caveofcode.com/how-to-setup-a-vpn-connection-from-inside-a-pod-in-kubernetes/
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
</code></pre>

<p>Here is a minimal example of a pod with OpenVPN client. I used <a href="https://github.com/kylemanna/docker-openvpn" rel="noreferrer">kylemanna/openvpn</a> as a server and to generate a basic client config. I only added two routes to the generated config to make it working. See below:</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: Pod
metadata:
  name: ovpn
  namespace: default
spec:
  containers:
    - name: ovpn
      image: debian:buster
      args:
        - bash
        - -c
        # install OpenVPN and curl; use curl in an endless loop to print external IP
        - apt update &amp;&amp; apt install -y openvpn curl &amp;&amp; cd /config &amp;&amp; openvpn client &amp; while sleep 5; do echo $(date; curl --silent ifconfig.me/ip); done
      volumeMounts:
        - mountPath: /dev/net/tun
          readOnly: true
          name: tun-device
        - mountPath: /config
          name: config
      securityContext:
        capabilities:
          add: [&quot;NET_ADMIN&quot;]
  volumes:
    - name: tun-device
      hostPath:
        path: /dev/net/tun
    - name: config
      secret:
        secretName: ovpn-config
---
apiVersion: v1
kind: Secret
metadata:
  name: ovpn-config
  namespace: default
stringData:
  client: |

    # A sample config generated by https://github.com/kylemanna/docker-openvpn server
    client
    nobind
    dev tun

    # Remote server params
    remote PASTE.SERVER.IP.HERE 1194 udp

    # Push all traffic through the VPN
    redirect-gateway def1
    # except these two k8s subnets
    route 10.43.0.0 255.255.0.0 net_gateway
    route 10.42.0.0 255.255.0.0 net_gateway

    # Below goes irrelevant TLS config
    remote-cert-tls server
    &lt;key&gt;
    -----BEGIN PRIVATE KEY-----
    -----END PRIVATE KEY-----
    &lt;/key&gt;
    &lt;cert&gt;
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
    &lt;/cert&gt;
    &lt;ca&gt;
    -----BEGIN CERTIFICATE-----
    -----END CERTIFICATE-----
    &lt;/ca&gt;
    key-direction 1
    &lt;tls-auth&gt;
    #
    # 2048 bit OpenVPN static key
    #
    -----BEGIN OpenVPN Static key V1-----
    -----END OpenVPN Static key V1-----
    &lt;/tls-auth&gt;
</code></pre>
