Instalar OpenVpn Server en Kubernetes
Vamos a implementar un sistema VPN con contenedores. En este caso, os explicamos como generar un servidor VPN a través de un clúster de Kubernetes fácilmente.
Lo primero hablaremos un poco de Helm, que es un gestor de paquetes para Kubernetes y es lo que vamos a usar.
La principal función de Helm es definir, instalar y actualizar aplicaciones complejas de Kubernetes. Helm es mantenido por la CNCF en colaboración con Microsoft, Google, Bitnami y la comunidad de Helm.
PROYECTO HELM: https://helm.sh/
El objetivo principal de esto es facilitar el acceso a los servicios de kubernetes a desarrolladores de aplicaciones, por ejemplo. También podría usarse para cualquier servicio al que solo se deba acceder a través de una VPN o como una VPN estándar.
Como podéis prever, nos vamos conectar a la red de nuestro clúster Kubernetes, no a la red corporativa.
Instalar Helm en Debian
Instalamos snap:
raulunzue@KBMASTER:~$ sudo apt update
raulunzue@KBMASTER:~# sudo apt-get install snap
Instalamos Helm:
raulunzue@KBMASTER:~$ sudo snap install helm --classic
helm 3.1.2 from Snapcrafters installed
Configuración de OpenVpn Server con Kubernetes
Comprobamos el estado del cluster:
raulunzue@KBMASTER:~$ kubectl get node
NAME STATUS ROLES AGE VERSION
kbmaster Ready master 71d v1.17.4
kubernetes01 Ready 46h v1.17.4
kubernetes02 Ready 71d v1.17.4
Comprobamos la external IP del cluster, en mi caso no la tiene:
raulunzue@KBMASTER:~$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-deployment-elblogdenegu NodePort 10.96.198.40 80:31910/TCP 63s
kubernetes ClusterIP 10.96.0.1 443/TCP 71d
Por defecto, el cluster sólo es accesible de forma interna, así que tendremos que habilitar el acceso externo:
raulunzue@KBMASTER:~$ kubectl proxy
Starting to serve on 127.0.0.1:8001
Agregamos un repo como root:
root@KBMASTER:~# helm repo add stable http://storage.googleapis.com/kubernetes-charts
"stable" has been added to your repositories
Actualizamos los repos:
raulunzue@KBMASTER:~$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈
He instalamos:
raulunzue@KBMASTER:~$ helm install stable/openvpn --generate-name
NAME: openvpn-1584572359
LAST DEPLOYED: Wed Mar 18 23:59:23 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
OpenVPN is now starting.
Please be aware that certificate generation is variable and may take some time (minutes).
Check pod status with the command:
POD_NAME=$(kubectl get pods --namespace "default" -l app=openvpn -o jsonpath='{ .items[0].metadata.name }') && kubectl --namespace "default" logs $POD_NAME --follow
LoadBalancer ingress creation can take some time as well. Check service status with the command:
kubectl --namespace "default" get svc
Once the external IP is available and all the server certificates are generated create client key .ovpn files by pasting the following into a shell:
POD_NAME=$(kubectl get pods --namespace "default" -l "app=openvpn,release=openvpn-1584572359" -o jsonpath='{ .items[0].metadata.name }')
SERVICE_NAME=$(kubectl get svc --namespace "default" -l "app=openvpn,release=openvpn-1584572359" -o jsonpath='{ .items[0].metadata.name }')
SERVICE_IP=$(kubectl get svc --namespace "default" "$SERVICE_NAME" -o go-template='{{ range $k, $v := (index .status.loadBalancer.ingress 0)}}{{ $v }}{{end}}')
KEY_NAME=kubeVPN
kubectl --namespace "default" exec -it "$POD_NAME" /etc/openvpn/setup/newClientCert.sh "$KEY_NAME" "$SERVICE_IP"
kubectl --namespace "default" exec -it "$POD_NAME" cat "/etc/openvpn/certs/pki/$KEY_NAME.ovpn" > "$KEY_NAME.ovpn"
Revoking certificates works just as easy:
KEY_NAME=
POD_NAME=$(kubectl get pods -n "default" -l "app=openvpn,release=openvpn-1584572359" -o jsonpath='{.items[0].metadata.name}')
kubectl -n "default" exec -it "$POD_NAME" /etc/openvpn/setup/revokeClientCert.sh $KEY_NAME
Copy the resulting $KEY_NAME.ovpn file to your open vpn client (ex: in tunnelblick, just double click on the file). Do this for each user that needs to connect to the VPN. Change KEY_NAME for each additional user.
Como veis nos suelta un “churro” con las instrucciones a seguir. Y ya se ha generado un pod y servicio, que está esperando la configuración:
raulunzue@KBMASTER:~$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-world-deployment-elblogdenegu-6dbbf956cf-hxds8 1/1 Running 5 47d
hello-world-deployment-elblogdenegu-6dbbf956cf-rg882 1/1 Running 1 2d
openvpn-1584572359-f76bbc4c8-4f9ln 0/1 Pending 0 3m47s
raulunzue@KBMASTER:~$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-deployment-elblogdenegu NodePort 10.96.198.40 80:31910/TCP 15m
kubernetes ClusterIP 10.96.0.1 443/TCP 71d
openvpn-1584572359 LoadBalancer 10.96.243.251 443:32592/TCP 3m57s
Así que proseguimos con las instrucciones. Averiguamos la versión de release de nuestro pod:
raulunzue@KBMASTER:~$ kubectl get pods -o json
Y lanzamos el comando modificando $HELM_RELEASE:
POD_NAME=$(kubectl get pods -l "app=openvpn,release=$HELM_RELEASE" -o jsonpath='{.items[0].metadata.name}') && kubectl logs "$POD_NAME" --follow
POD_NAME=$(kubectl get pods -l "app=openvpn,release=openvpn-1584572359" -o jsonpath='{.items[0].metadata.name}') && kubectl logs "$POD_NAME" --follow
El proceso puede tardar MINUTOS, así que paciencia.
raulunzue@KBMASTER:~$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-deployment-elblogdenegu NodePort 10.96.198.40 80:31910/TCP 39m
kubernetes ClusterIP 10.96.0.1 443/TCP 71d
openvpn-1584572359 LoadBalancer 10.96.243.251 443:32592/TCP 27m
Luego tendremos que lanzar el siguiente script para generar la Client KEY:
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Usage: $0 "
exit
fi
KEY_NAME=$1
NAMESPACE=$2
HELM_RELEASE=$3
POD_NAME=$(kubectl get pods -n "$NAMESPACE" -l "app=openvpn,release=$HELM_RELEASE" -o jsonpath='{.items[0].metadata.name}')
SERVICE_NAME=$(kubectl get svc -n "$NAMESPACE" -l "app=openvpn,release=$HELM_RELEASE" -o jsonpath='{.items[0].metadata.name}')
SERVICE_IP=$(kubectl get svc -n "$NAMESPACE" "$SERVICE_NAME" -o go-template='{{range $k, $v := (index .status.loadBalancer.ingress 0)}}{{$v}}{{end}}')
kubectl -n "$NAMESPACE" exec -it "$POD_NAME" /etc/openvpn/setup/newClientCert.sh "$KEY_NAME" "$SERVICE_IP"
kubectl -n "$NAMESPACE" exec -it "$POD_NAME" cat "/etc/openvpn/certs/pki/$KEY_NAME.ovpn" > "$KEY_NAME.ovpn"
Si necesitamos revocarlo:
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Usage: $0 "
exit
fi
KEY_NAME=$1
NAMESPACE=$2
HELM_RELEASE=$3
POD_NAME=$(kubectl get pods -n "$NAMESPACE" -l "app=openvpn,release=$HELM_RELEASE" -o jsonpath='{.items[0].metadata.name}')
kubectl -n "$NAMESPACE" exec -it "$POD_NAME" /etc/openvpn/setup/revokeClientCert.sh $KEY_NAME
Y ya tenemos nuestro OpenVPN server sobre Kubernetes.
Para más info: https://hub.kubeapps.com/charts/stable/openvpn/4.2.1
¿Te ha gustado la entrada SÍGUENOS EN TWITTER?
Te ha gustado la entrada SGUENOS EN TWITTER O INVITANOS A UN CAFE?