Skip to content
forked from shyiko/k8sovpn

OpenVPN tunnel "to see the world the way pods see it" in Kubernetes

Notifications You must be signed in to change notification settings

vimaire/k8sovpn

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

k8sovpn

OpenVPN for Kubernetes.
The primary goal is "to see the world the way pods see it".

In other words, once connected these should work:

ping -4 service-name.namespace
ping -4 service-name.namespace.svc
ping -4 service-name.namespace.svc.cluster.local

Usage

If you don't want to use shyiko/openvpn image - build your own with docker build -t image:tag . (Dockerfile is included in this repo).
(NOTE: any image with openvpn 2+ and easyrsa 3 will do, e.g. kylemanna/docker-openvpn)

Set up OpenVPN server:

# generate
# - CA certificate/private key;
# - server certificate/private key;
# - Diffie-Hellman parameters file;
# - tls-auth key.
# 
# output:  
# ./pki/ca.crt
# ./pki/crl.pem
# ./pki/dh.pem
# ./pki/issued/server.crt
# ./pki/private/ca.key
# ./pki/private/server.key
# ./ta.key
#
docker run -v $(pwd):/workdir -w /workdir --rm -it \
  -e ROOT_CN=<hostname-or-anything-else-to-identify-ca-cert> \
  shyiko/openvpn:2.4.0_easyrsa-3.0.3 \
  bash -c '
  export EASYRSA_PKI=$(pwd)/pki
  easyrsa init-pki
  printf "$ROOT_CN\n" | easyrsa build-ca nopass 
  easyrsa gen-crl
  easyrsa build-server-full server nopass 
  easyrsa gen-dh
  openvpn --genkey --secret ta.key
  '

# create a secret containing everything but CA private key (keep it safe!)
kubectl create secret generic k8sovpn \
  --from-file=pki/ca.crt \
  --from-file=pki/crl.pem \
  --from-file=pki/dh.pem \
  --from-file=pki/issued/server.crt \
  --from-file=pki/private/server.key \
  --from-file=ta.key

# deploy OpenVPN server
kubectl apply -f k8sovpn.yml
kubectl expose -f k8sovpn.yml --port=1194

That's it.
You now have OpenVPN server running inside Kubernetes cluster.
To connect:

# generate client certificate/private key and then pack everything in .ovpn 
# (OpenVPN client configuration)
#
# output:  
# ./pki/issued/$CLIENT_NAME.crt
# ./pki/private/$CLIENT_NAME.key
# ./$CLIENT_NAME.ovpn
#
docker run -v $(pwd):/workdir -w /workdir --rm -it \
  -e REMOTE_HOST=<openvpn-server-hostname-or-ip-address> \
  -e REMOTE_PORT=<openvpn-server-port-1194-by-default> \
  -e CLIENT_NAME=<client_name> \
  shyiko/openvpn:2.4.0_easyrsa-3.0.3 \
  bash -c '
  export EASYRSA_PKI=$(pwd)/pki
  easyrsa build-client-full $CLIENT_NAME nopass
  printf "client
verb 3  
remote $REMOTE_HOST $REMOTE_PORT
persist-key
persist-tun
proto udp
nobind
dev tun
cipher AES-128-GCM
<ca>\n$(cat pki/ca.crt)\n</ca>
<key>\n$(cat pki/private/$CLIENT_NAME.key)\n</key>
<cert>\n$(cat pki/issued/$CLIENT_NAME.crt)\n</cert>
remote-cert-tls server
<tls-auth>\n$(cat ta.key)\n</tls-auth>
key-direction 1
" > /workdir/$CLIENT_NAME.ovpn
  '

# connect
sudo openvpn <client_name>.ovpn

NOTE: .ovpn generated above has certs and keys embedded (which means only .ovpn file needs to be distributed to the client (no need for separate ca.crt or ta.key)).

To revoke client certificate (in case you ever need this):

docker run -v $(pwd):/workdir -w /workdir --rm -it \
  -e CLIENT_NAME=<client_name> \
  shyiko/openvpn:2.4.0_easyrsa-3.0.3 \
  bash -c '
  export EASYRSA_PKI=$(pwd)/pki
  printf "yes\n" | easyrsa revoke $CLIENT_NAME
  easyrsa gen-crl
  '

# propagate updated CRL to the OpenVPN server

kubectl create secret generic k8sovpn \
  --from-file=pki/ca.crt \
  --from-file=pki/crl.pem \
  --from-file=pki/dh.pem \
  --from-file=pki/issued/server.crt \
  --from-file=pki/private/server.key \
  --from-file=ta.key

kubectl replace --force -f k8sovpn.yml

DEMO (aka Testing locally via Minikube)

git clone https://github.com/shyiko/k8sovpn
cd demo/

minikube start

kubectl run nginx --image=nginx
kubectl expose deployment nginx --port=80

# all the certs/keys included in demo/ are for demo purposes only
# see "Usage" on how to generate your own
kubectl create secret generic k8sovpn \
  --from-file=pki/ca.crt \
  --from-file=pki/crl.pem \
  --from-file=pki/dh.pem \
  --from-file=pki/issued/server.crt \
  --from-file=pki/private/server.key \
  --from-file=ta.key
kubectl apply -f ../k8sovpn.yml
kubectl expose -f ../k8sovpn.yml --port=1194 --type=NodePort

# connect * (see footnote)
sudo openvpn \
  --remote $(minikube ip) $( \
      kubectl get svc k8sovpn -o=jsonpath='{.spec.ports[?(@.port==1194)].nodePort}' \
    ) \
  --config jean-luc.picard.ovpn

# try reaching nginx
curl -v http://nginx.default/

* on Linux you may need masterkorp/openvpn-update-resolv-conf
(prepend --setenv PATH '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' --script-security 2 --up /etc/openvpn/update-resolv-conf.sh --down /etc/openvpn/update-resolv-conf.sh to the list of openvpn args).

Alternatives

sshuttle - Transparent proxy server over SSH that supports DNS tunneling.

Legal

All code, unless specified otherwise, is licensed under the MIT license.
Copyright (c) 2018 Stanley Shyiko.

About

OpenVPN tunnel "to see the world the way pods see it" in Kubernetes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published