24 KiB
title | description | published | date | tags | editor | dateCreated |
---|---|---|---|---|---|---|
OpenVPN - Servidor | Tutorial de instalación del Servidor OpenVPN | true | 2022-05-25T23:45:52.556Z | vpn, servidor, debian | markdown | 2022-05-18T16:48:57.246Z |
OpenVPN
Requisitos
- Debian 11 “bullseye”
- Usuario con privilegios
sudo
EasyRSA
Instalación de EasyRSA (en CA, Signer y oVPN)
- Primero descargamos la última versión disponible de EasyRSA en nuestra CA y nuestro Signer
wget -P ~/ https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.0/EasyRSA-3.1.0.tgz
- Luego descomprimimos y dejamos un nombre sencillo
cd ~
tar xvf EasyRSA-3.1.0.tgz
mv EasyRSA-3.1.0 EasyRSA
cd EasyRSA
Configuración de EasyRSA (en CA, Signer y oVPN)
- Inicialmente tendremos un fichero
vars.example
que utilizaremos como base
cp vars.example vars
- Editaremos este fichero para dejar nuestras propiedades personalizadas
nano vars # o vim vars
- Establecemos unos valores apropiados de la organización
set_var EASYRSA_REQ_COUNTRY "ES"
set_var EASYRSA_REQ_PROVINCE "Valladolid"
set_var EASYRSA_REQ_CITY "Valladolid"
set_var EASYRSA_REQ_ORG "Bastionado"
set_var EASYRSA_REQ_EMAIL "admin@bastionado.es"
set_var EASYRSA_REQ_OU "Community"
- Utilizaremos criptografía de curva elíptica para el cifrado, concretamente una Curva Edwards
set_var EASYRSA_ALGO ed
- La especificación de curva elíptica que utilizaremos será la Curva 25519, definida como una curva segura segçun SafeCurves
set_var EASYRSA_CURVE ed25519
- Establecemos tiempos de expiración
set_var EASYRSA_CA_EXPIRE 7090 # La CA durará 20 años
set_var EASYRSA_CERT_EXPIRE 180 # Los certificados cliente caducan cada 6 meses
set_var EASYRSA_CRL_DAYS 90 # La lista de revocaciones se actualiza aproximadamente cada 3 meses
set_var EASYRSA_CERT_RENEW 20 # Los certificados se pueden renovar con 20 días de antelación
Creación de CA
- Inicializamos nuestra Infraestructura de Clave Pública en la CA
./easyrsa init-pki
- Como se nos informa de que el fichero
vars
se ha movido a la PKI procedemos a mover nuestro fichero personalizado
mv vars pki/vars
- Generamos nuestra CA
./easyrsa build-ca # Podríamos añadir 'nopass' para no establecer una Passphrase
Creación de SubCA en Signer
- Inicializamos nuestra Infraestructura de Clave Pública en la SubCA
./easyrsa init-pki
- Como se nos informa de que el fichero
vars
se ha movido a la PKI procedemos a mover nuestro fichero personalizado
mv vars pki/vars
- Generamos la solicitud de nuestra SubCA
./easyrsa build-ca subca
- Enviamos la solicitud de nuestra SubCA a la CA para validarla
scp ~/EasyRSA/pki/reqs/ca.req ca@ca.bastionado.es:/tmp
- Nos situamos sobre la CA e importamos y firmamos la solicitud
./easyrsa import-req /tmp/ca.req signer
./easyrsa sign-req ca signer
- Devolvemos el certificado encadenado de la CA con la SubCA válido a nuestra SubCA
cat pki/issued/signer.crt \
pki/ca.crt \
> /tmp/signer.crt
scp /tmp/signer.crt signer@signer.bastionado.es:/tmp
rm -rf /tmp/signer.crt
- Volvemos a la SubCA y movemos el certificado a la ruta de puesto PKI
mv /tmp/signer.crt ~/EasyRSA/pki/ca.crt
Creación de Certificado en oVPN
- Inicializamos nuestra Infraestructura de Clave Pública en oVPN
./easyrsa init-pki
- Como se nos informa de que el fichero
vars
se ha movido a la PKI procedemos a mover nuestro fichero personalizado
mv vars pki/vars
- Generamos la solicitud de nuestra VPN
./easyrsa gen-req ovpn nopass # Aquí no establecemos Passphrase
- Enviamos la solicitud de nuestra VPN a la SubCA para validarla
scp ~/EasyRSA/pki/reqs/ovpn.req signer@signer.bastionado.es:/tmp
- Nos situamos sobre la SubCA e importamos y firmamos la solicitud
./easyrsa import-req /tmp/ovpn.req ovpn
./easyrsa sign-req server ovpn
- Devolvemos el certificado válido a nuestra oVPN junto con el certificado de la SubCA
scp pki/ca.crt ovpn@ovpn.bastionado.es:/tmp
scp pki/issued/ovpn.crt ovpn@ovpn.bastionado.es:/tmp
OpenVPN
Instalación de dependencias OpenVPN
- Comenzaremos actualizando nuestro repositorio
apt
sudo apt update
- Después realizaremos una instalación de dependencias previas
sudo apt -y install ca-certificates wget net-tools gnupg
- Ahora añadiremos las claves PGP del repositorio de OpenVPN
wget -qO- https://swupdate.openvpn.net/repos/repo-public.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/openvpn-archive-keyring.gpg > /dev/null
- Y añadiremos el repositorio de OpenVPN a nuestro listado de repositorios
echo "deb [signed-by=/usr/share/keyrings/openvpn-archive-keyring.gpg] http://build.openvpn.net/debian/openvpn/stable bullseye main" | sudo tee /etc/apt/sources.list.d/openvpn-repo.list > /dev/null
- Es turno de volver a actualizar nuestro listado de repositorios
sudo apt update
- Y ya podemos proceder con la instalación de OpenVPN
sudo apt -y install openvpn
Configuración de certificados y seguridad TLS
- Copiamos los certificados que dejamos en /tmp y la clave privada
sudo cp ~/EasyRSA/pki/private/ovpn.key /etc/openvpn/
sudo cp /tmp/ovpn.crt ~/EasyRSA/pki/ovpn.crt
sudo mv /tmp/{ovpn.crt,ca.crt} /etc/openvpn/
- Volvemos a la ruta de EasyRSA para generar la clave Diffie-Hellman
cd ~/EasyRSA/
./easyrsa --keysize=4096 gen-dh
- Generamos la firma HMAC para reforzar las capacidades de verificación de integridad TLS
sudo openvpn --genkey secret ta.key
- Movemos los ficheros generados a nuestro directorio de OpenVPN
sudo mv ~/EasyRSA/ta.key /etc/openvpn/
sudo mv ~/EasyRSA/pki/dh.pem /etc/openvpn/
Certificados Cliente
Cona la estructura propuesta las solicitudes de certificados cliente serán generadas desde el servidor de OpenVPN oVPN
y firmadas desde la SubCA Signer
, de tal modo que, posteriormente, el cliente simplemente recibirá un fichero de configuración para conectar a la VPN junto con sus certificados sin tener que estar intercambiando certificados inicialmente si fuera el propio cliente el que realizara la solicitud de creación de certificado.
- Crearemos un directorio en nuestra VPN para almacenar las configuraciones de cliente y restringiremos los permisos
mkdir -p ~/client-configs/keys
chmod -R 700 ~/client-configs
- Volvemos a la ruta de EasyRSA para generar la solicitud de certificado cliente
cd ~/EasyRSA/
./easyrsa gen-req client1 nopass
./easyrsa gen-req client2 nopass
./easyrsa gen-req client3 nopass
./easyrsa gen-req client4 nopass
- Copiamos la clave privada generada a nuestro directorio de configuraciones Cliente
cp pki/private/{client1.key,client2.key,client3.key,client4.key} ~/client-configs/keys/
- Enviamos las solicitudes de nuestra VPN a la SubCA para validarlas
scp ~/EasyRSA/pki/reqs/{client1.req,client2.req,client3.req,client4.req} signer@signer.bastionado.es:/tmp
- Nos situamos sobre la SubCA e importamos y firmamos las solicitudes
./easyrsa import-req /tmp/client1.req client1
./easyrsa import-req /tmp/client2.req client2
./easyrsa import-req /tmp/client3.req client3
./easyrsa import-req /tmp/client4.req client4
./easyrsa sign-req client client1
./easyrsa sign-req client client2
./easyrsa sign-req client client3
./easyrsa sign-req client client4
- Devolvemos los certificados válidos a nuestra oVPN
scp pki/issued/{client1.crt,client2.crt,client3.crt,client4.crt} ovpn@ovpn.bastionado.es:/tmp
- Volvemos a la VPN y copiamos el certificado a nuestro directorio de configuraciones Cliente
cp /tmp/{client1.crt,client2.crt,client3.crt,client4.crt} ~/client-configs/keys/
- Ahora copiamos el certificado de la SubCA y la Firma HMAC a nuestro directorio de configuraciones Cliente
exit
sudo cp /etc/openvpn/{ca.crt,ta.key} ~/client-configs/keys/
Configuración de OpenVPN
Ahora que ya hemos terminado completamente con la Infraestructura de Clave Pública es el momento de configurar el servicio OpenVPN.
- Comenzamos copiando la configuración de ejemplo y lo editamos
sudo nano /etc/openvpn/server.conf # sudo vim /etc/openvpn/server.conf
- Modificamos el puerto por defecto y mantenemos el uso del protocolo UDP, más rápido y resistente frente a ataques de denegación de servicio
port 6174
proto udp
- Especificamos la interfaz de red que se creará de forma explícita como
tun0
dev tun0
- Apuntaremos a nuestros certificados generados anteriormente
ca ca.crt
cert ovpn.crt
key ovpn.key
- Establecemos la directiva
dh
con nuestra clave generada anteriormente
dh dh.pem
- Establecemos la subred que se establecerá en las conexiones. El servidor tendrá automáticamente la IP
10.10.10.1
server 10.10.10.0 255.255.255.0
- Establecemos un fichero de persistencia para que los clientes vuelvan a tener la misma asignación de IP en caso de una caida del servicio
ifconfig-pool-persist /var/log/openvpn/ipp.txt
def1
Modifica la tabla de enrutamiento de los clientes para redirigir todo el tráfico hacia la intrerfaz VPN.bypass-dhcp
Añade una ruta directa al servidor DHCP de OpenVPN
- Forzaremos que todo el tráfico de los clientes sea redirigido por la VPN.
push "redirect-gateway def1 bypass-dhcp"
- Establecemos los servidores DNS.
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 1.0.0.1"
- Establecemos una directiva para consultar que los clientes siguen conectados cada 10 segundos y se consideran desconectados si no responden en 2 minutros.
keepalive 10 120
La directiva
tls-auth
añade una capa adicional de autenticación HMAC sobre el canal de control TLS para mitigar los ataques DoS y los ataques a la pila TLS. En pocas palabras, --tls-auth habilita una especie de "cortafuegos HMAC" en el puerto TCP/UDP de OpenVPN, donde los paquetes del canal de control TLS que lleven una firma HMAC incorrecta pueden ser descartados inmediatamente sin respuesta.
- Nos aseguramos de que
tls-auth
está habilitado (debemos eliminar el;
inicial si existe)
tls-auth ta.key 0 # This file is secret
La directiva
cipher
cifra los paquetes del canal de datos con el algoritmo de cifradoalg
.El valor por defecto esBF-CBC
, una abreviatura de Blowfish en modo Cipher Block Chaining. Ya no se recomienda el uso de BF-CBC, debido a su tamaño de bloque de 64 bits. Este pequeño tamaño de bloque permite realizar ataques basados en colisiones, como ha demostrado SWEET32. Nos pasaremos al cifrado AES en modo Cipher Block Chaining con bloques de 256 bits.
- Escogemos el cifrado
AES-256-CBC
que ofrece un buen nivel de seguridad
cipher AES-256-CBC
La directiva
auth
Autentica los paquetes del canal de datos y (si está habilitado) los paquetes del canal de controltls-auth
con HMAC utilizando el algoritmo de resumen de mensajes alg. (El valor predeterminado esSHA1
). HMAC es un algoritmo de autenticación de mensajes (MAC) de uso común que utiliza una cadena de datos, un algoritmo hash seguro y una clave, para producir una firma digital.El protocolo de canal de datos de OpenVPN utiliza encrypt-then-mac (es decir, primero encripta un paquete y luego HMAC el texto cifrado resultante), lo que evita los ataques de oráculo de relleno.
- Justo debajo añadimos la directiva
auth
auth SHA512
- Haremos que el servicio OpenVPN se ejecute con el usuario
nobody
y gruponogroup
descomentando estos valores
user nobody
group nogroup
- Las opciones de persistencia tratarán de evitar el acceso a ciertos recursos en el reinicio que pueden dejar de ser accesibles debido a la reducción de privilegios.
persist-key
persist-tun
- Escribimos el estado (un resumen de las conexiones) cada minuto en un fichero
status /var/log/openvpn/openvpn-status.log
- También escribimos un fichero de registro que se mantendrá entre sesiones
log-append /var/log/openvpn/openvpn.log
- Establecemos el nivel de detalle que va desde 0 (nada) a 9 (ultra detallado)
verb 3
- Informamos a los clientes ante un reinio del servidor para que puedan reconectar posterirmente
explicit-exit-notify 1
Directivas adicionales
- Habilitar la redirección de tráfico
sudo nano /etc/sysctl.conf # sudo vim /etc/sysctl.conf
net.ipv4.ip_forward=1 # Descomentar esta línea
sudo sysctl -w net.ipv4.ip_forward=1
Puesta en funcionamiento del servicio
- Arrancar y comprobar el estado del servicio OpenVPN
sudo systemctl restart openvpn@server && sudo systemctl status openvpn@server
- Comprobar la existencia de la intefaz virtual de OpenVPN
ip addr show tun0
- Habilitar el arranque automático de OpenVPN
sudo systemctl enable openvpn@server
Configuración para el cliente
Plantilla de cliente
Ahora que ya tenemos nuestra VPN funcionando es el momento de generar la configuración que los clientes importarán para poder conectar a nuestra VPN.
- Comenzamos creando en nuestro directorio de configuración de clientes un directorio donde almacenar la configuración individual
mkdir -p ~/client-configs/files
- Copiamos la plantilla de configuración de cliente por defecto y procedemos a editarla
nano ~/client-configs/base.conf # vim ~/client-configs/base.conf
- Especificamos que estamos ante un fichero cliente
client
- Configuramos el modo de interfaz igual que en el servidor.
dev tun
- Hacemos lo mismo con el protocolo.
proto udp
- Establecemos la IP y puerto de nuestro servidor VPN.
remote ovpn.bastionado.es 6174
- Intentamos que el intento de resolución de nombre del servidor VPN sea infinita, útil para equipos que no están permanentemente conectados a internet.
resolv-retry infinite
- Con la siguiente directa hacemos que el puerto local de salida sea dinámico.
nobind
- Realizamos un descenso de privilegios después de inicializar en sistemas que no son Windows.
user nobody
group nogroup
- Intentamos persistir los siguientes valores entre reinicios.
persist-key
persist-tun
- Realizamos verificación del certificado del servidor y sus usos extendidos.
remote-cert-tls server
- Establecemos las mismas directivas
cipher
yauth
que establecimos en el servidor
cipher AES-256-CBC
auth SHA512
- Establecemos el nivel de detalle que va desde 0 (nada) a 9 (ultra detallado)
verb 3
La directiva
key-direction
establece una forma alternativa de especificar el parámetro opcional de dirección para las opcionestls-auth
ysecret
, Es útil cuando se utilizan ficheros incrustados.
- Establecemos la directiva
key-direction
key-direction 1
Script de configuración de clientes
Generaremos un script que se encargará de crear un fichero incrustado con la configuración de conexión plantilla y los certificados apropiados para cada cliente.
- Creamos el script
nano ~/client-configs/make_config.sh # vim ~/client-configs/make_config.sh
- Añadimos el siguiente código al script
#!/bin/bash
# First argument: Client identifier
KEY_DIR=/home/ovpn/client-configs/keys
OUTPUT_DIR=/home/ovpn/client-configs/files
BASE_CONFIG=/home/ovpn/client-configs/base.conf
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/${1}.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/${1}.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/bastionado-${1}.ovpn
- Establecemos los permisos de ejecución
chmod 700 ~/client-configs/make_config.sh
- Y ahora ya podemos generar el fichero de configuración para
client1
cd ~/client-configs
sudo ./make_config.sh client1
sudo ./make_config.sh client2
sudo ./make_config.sh client3
sudo ./make_config.sh client3
- Los fichero resultantes,
bastionado-client{1,2,3}.ovpn
deberán entregarse a los clientes para que éstos puedan conectar a la VPN.
Habilitando el forwarding en nftables
sudo vim /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
define vpn_port=6174
define vpn_if=tun0
define outside_if=enp0s17
define vpn_subnet=10.10.10.0/24
table inet filter {
chain input {
# allow OpenVPN VPN connections to the Server
udp dport $vpn_port accept
}
chain forward {
#Drop forwarded packets if they are not matched
type filter hook forward priority 0; policy drop;
# allow existing connections
ct state related,established accept
# allow packets from vpn interface
iifname $vpn_if oifname $outside_if accept
}
chain output {
# Security drops
ct state invalid counter drop
oifname != "lo" ip saddr != 127.0.0.1 ip daddr != 127.0.0.1 tcp flags & (fin|ack) == fin|ack counter drop
oifname != "lo" ip saddr != 127.0.0.1 ip daddr != 127.0.0.1 tcp flags & (rst|ack) == rst|ack counter drop
}
}
# create a ipv4 table only for NAT entries (you need both chains even if they're empty)
table ip nat {
chain postrouting {
type nat hook postrouting priority 100;
# enable NAT for VPN
iifname $vpn_if oifname $outside_if ip saddr $vpn_subnet masquerade
}
chain prerouting {
type nat hook prerouting priority 0;
}
}
sudo systemctl restart nftables.service && sudo systemctl status nftables.service
sudo systemctl enable nftables.service
OpenVPN + TOR
Configuración de OpenVPN
sudo cp /etc/openvpn/server.conf /etc/openvpn/tor.conf
sudo vim /etc/openvpn/tor.conf
port 6175
dev tun1
server 10.10.20.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp-tor.txt
push "dhcp-option DNS 10.10.20.1"
push "dhcp-option DNS 1.1.1.1"
status /var/log/openvpn/openvpn-status-tor.log
log-append /var/log/openvpn/openvpn-tor.log
Puesta en funcionamiento del servicio
- Arrancar y comprobar el estado del servicio OpenVPN
sudo systemctl restart openvpn@tor && sudo systemctl status openvpn@tor
- Comprobar la existencia de la intefaz virtual de OpenVPN
ip addr show tun1
- Habilitar el arranque automático de OpenVPN
sudo systemctl enable openvpn@tor
Habilitando tor
sudo apt install tor -y
sudo vim /etc/tor/torrc
VirtualAddrNetwork 10.192.0.0/10
AutomapHostsOnResolve 1
AutomapHostsSuffixes .onion,.exit
DNSPort 10.10.20.1:53530
TransPort 10.10.20.1:9040
ExitNodes {us}
StrictNodes 1
sudo systemctl restart tor.service
sudo netstat -tulpen | grep tor
#!/usr/sbin/nft -f
flush ruleset
define vpn_port=6174
define vpn_if=tun0
define outside_if=enp0s17
define vpn_subnet=10.10.10.0/24
define vpn_port_tor=6175
define vpn_if_tor=tun1
define vpn_subnet_tor=10.10.20.0/24
table inet filter {
chain input {
# allow OpenVPN connections to the Server
udp dport $vpn_port accept
# allow OpenVPN TOR connections to the Server
udp dport $vpn_port_tor accept
}
chain forward {
#Drop forwarded packets if they are not matched
type filter hook forward priority 0; policy drop;
# allow existing connections
ct state related,established accept
# allow packets from vpn interface
iifname $vpn_if oifname $outside_if accept
}
chain output {
# Security drops
ct state invalid counter drop
oifname != "lo" ip saddr != 127.0.0.1 ip daddr != 127.0.0.1 tcp flags & (fin|ack) == fin|ack counter drop
oifname != "lo" ip saddr != 127.0.0.1 ip daddr != 127.0.0.1 tcp flags & (rst|ack) == rst|ack counter drop
}
}
# create a ipv4 table only for NAT entries (you need both chains even if they're empty)
table ip nat {
chain postrouting {
type nat hook postrouting priority 100;
# enable NAT for VPN
iifname $vpn_if oifname $outside_if ip saddr $vpn_subnet masquerade
}
chain prerouting {
# Transparent proxy to TOR
type nat hook prerouting priority 0;
iifname $vpn_if_tor ip saddr $vpn_subnet udp dport 53 counter dnat to 10.10.20.1:53530
iifname $vpn_if_tor ip protocol tcp ip saddr $vpn_subnet_tor counter dnat to 10.10.20.1:9040
iifname $vpn_if_tor ip protocol udp ip saddr $vpn_subnet_tor counter dnat to 10.10.20.1:9040
}
}
sudo systemctl restart nftables.service && sudo systemctl status nftables.service
sudo vim /etc/openvpn/server.conf
push "dhcp-option DNS 10.8.0.1"
sudo systemctl restart openvpn@server.service && sudo systemctl status openvpn@server.service
Landing Page para descarga de configuración cliente
curl -sSL https://packages.sury.org/nginx/README.txt | sudo bash -x
sudo apt update
sudo apt install nginx-core nginx-common nginx nginx-full apache2-utils
cd /var/www
sudo htpasswd -c .htpasswd client1
sudo dd if=/dev/null of=/etc/nginx/nginx.conf && sudo vim /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types application/atom+xml application/javascript application/json application/rss+xml
application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype
application/x-font-ttf application/x-javascript application/xhtml+xml application/xml
font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon
image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
sudo dd if=/dev/null of=/etc/nginx/sites-available/default && sudo vim /etc/nginx/sites-available/default
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html;
server_name _;
location /download {
try_files $uri $uri/ =404;
auth_basic "Client Area";
auth_basic_user_file /var/www/.htpasswd;
}
}
scp -i .\.ssh\id_admin_bastionado .\bastionado-vpn.tar ovpn@ovpn.bastionado.es:/home/ovpn
sudo tar -xvf bastionado-vpn.tar -C /var/www/html
sudo cp /home/ovpn/client-configs/files/bastionado-client1.ovpn /var/www/html/download
sudo chown -R www-data:www-data /var/www
sudo find /var/www -type f -print0|sudo xargs -0 chmod 660
sudo find /var/www -type d -print0|sudo xargs -0 chmod 770