José Antonio Yáñez Jiménez 0e735ad83f docs: update vpn/openvpn/servidor
2022-05-24 22:28:35 +00:00

812 lines
20 KiB
Markdown

---
title: OpenVPN - Servidor
description: Tutorial de instalación del Servidor OpenVPN
published: true
date: 2022-05-24T22:28:31.778Z
tags: vpn, servidor, debian
editor: markdown
dateCreated: 2022-05-18T16:48:57.246Z
---
# OpenVPN
![openvpn_logo.svg](/assets/images/openvpn_logo.svg)
## Requisitos
* **[Debian 11 “bullseye”](https://www.debian.org/releases/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
```bash
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
```bash
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
```bash
cp vars.example vars
```
* Editaremos este fichero para dejar nuestras propiedades personalizadas
```bash
nano vars # o vim vars
```
* Establecemos unos valores apropiados para nuestra CA y Signer
```bash
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"
set_var EASYRSA_KEY_SIZE 4096
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_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
```bash
./easyrsa init-pki
```
* Como se nos informa de que el fichero `vars` se ha movido a la PKI procedemos a eliminar el inicial
```bash
rm vars
```
* Generamos nuestra CA
```bash
./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
```bash
./easyrsa init-pki
```
* Como se nos informa de que el fichero `vars` se ha movido a la PKI procedemos a eliminar el inicial
```bash
rm vars
```
* Generamos la solicitud de nuestra SubCA
```bash
./easyrsa build-ca subca
```
* Enviamos la solicitud de nuestra SubCA a la CA para validarla
```bash
scp ~/EasyRSA/pki/reqs/ca.req ca@ca.bastionado.es:/tmp
```
* Conectamos a la CA
```bash
ssh ca@ca.bastionado.es
cd ~/EasyRSA
```
* Importamos y firmamos la solicitud
```bash
./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
```bash
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
```bash
exit
cd ~/EasyRSA
mv /tmp/signer.crt pki/ca.crt
```
### Creación de Certificado en oVPN
* Inicializamos nuestra Infraestructura de Clave Pública en oVPN
```bash
./easyrsa init-pki
```
* Como se nos informa de que el fichero `vars` se ha movido a la PKI procedemos a eliminar el inicial
```bash
rm vars
```
* Generamos la solicitud de nuestra VPN
```bash
./easyrsa gen-req ovpn nopass # Aquí no establecemos Passphrase
```
* Enviamos la solicitud de nuestra VPN a la SubCA para validarla
```bash
scp ~/EasyRSA/pki/reqs/ovpn.req signer@signer.bastionado.es:/tmp
```
* Conectamos a la SubCA
```bash
ssh signer@signer.bastionado.es
cd ~/EasyRSA
```
* Importamos y firmamos la solicitud
```bash
./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
```bash
scp pki/ca.crt ovpn@ovpn.bastionado.es:/tmp
scp pki/issued/ovpn.crt ovpn@ovpn.bastionado.es:/tmp
```
* Volvemos a la VPN
```bash
exit
```
## OpenVPN
### Instalación de dependencias OpenVPN
* Comenzaremos actualizando nuestro repositorio `apt`
```bash
sudo apt update
```
* Después realizaremos una instalación de dependencias previas
```bash
sudo apt -y install ca-certificates wget net-tools gnupg
```
* Ahora añadiremos las claves PGP del repositorio de OpenVPN
```bash
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
```bash
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
```bash
sudo apt update
```
* Y ya podemos proceder con la instalación de OpenVPN
```bash
sudo apt -y install openvpn
```
### Configuración de certificados y seguridad TLS
* Copiamos los certificados que dejamos en /tmp y la clave privada
```bash
sudo cp ~/EasyRSA/pki/private/ovpn.key /etc/openvpn/
sudo cp /tmp/{ovpn.crt,ca.crt} /etc/openvpn/
```
* Volvemos a la ruta de EasyRSA para generar la clave Diffie-Hellman
```bash
cd ~/EasyRSA/
./easyrsa gen-dh
```
* Generamos la firma HMAC para reforzar las capacidades de verificación de integridad TLS
```bash
sudo openvpn --genkey secret ta.key
```
* Movemos los ficheros generados a nuestro directorio de OpenVPN
```bash
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
```bash
mkdir -p ~/client-configs/keys
chmod -R 700 ~/client-configs
```
* Volvemos a la ruta de EasyRSA para generar la solicitud de certificado cliente
```bash
cd ~/EasyRSA/
./easyrsa gen-req client1 nopass
```
* Copiamos la clave privada generada a nuestro directorio de configuraciones Cliente
```bash
cp pki/private/client1.key ~/client-configs/keys/
```
* Enviamos la solicitud de nuestra VPN a la SubCA para validarla
```bash
scp ~/EasyRSA/pki/reqs/client1.req signer@signer.bastionado.es:/tmp
```
* Conectamos a la SubCA
```bash
ssh signer@signer.bastionado.es
cd ~/EasyRSA
```
* Importamos y firmamos la solicitud
```bash
./easyrsa import-req /tmp/client1.req client1
./easyrsa sign-req client client1
```
* Devolvemos el certificado válido a nuestra oVPN
```bash
scp pki/issued/client1.crt ovpn@ovpn.bastionado.es:/tmp
```
* Volvemos a la VPN y copiamos el certificado a nuestro directorio de configuraciones Cliente
```bash
exit
cp /tmp/client1.crt ~/client-configs/keys/
```
* Ahora copiamos el certificado de la SubCA y la Firma HMAC a nuestro directorio de configuraciones Cliente
```bash
exit
sudo cp /etc/openvpn/ta.key ~/client-configs/keys/
sudo cp /etc/openvpn/ca.crt ~/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
```bash
sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/
sudo nano /etc/openvpn/server.conf # sudo vim /etc/openvpn/server.conf
```
> 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)
```bash
tls-auth ta.key 0 # This file is secret
```
> La directiva `cipher` cifra los paquetes del canal de datos con el algoritmo de cifrado `alg`.El valor por defecto es `BF-CBC`, una abreviatura de [Blowfish en modo Cipher Block Chaining](https://cryptopp.com/wiki/Blowfish). 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](https://sweet32.info/#CBC). Nos pasaremos al cifrado [AES en modo Cipher Block Chaining](https://cryptopp.com/wiki/Advanced_Encryption_Standard) con bloques de 256 bits.
* Escogemos el cifrado `AES-256-CBC` que ofrece un buen nivel de seguridad
```bash
cipher AES-256-CBC
```
> La directiva `auth` Autentica los paquetes del canal de datos y (si está habilitado) los paquetes del canal de control `tls-auth` con HMAC utilizando el algoritmo de resumen de mensajes alg. (El valor predeterminado es `SHA1` ). 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`
```bash
auth SHA512
```
* Buscamos la directiva `dh` para modificar su nombre a `dh.pem` ya que es como se denomina nuestro fichero generado anteriormente
```bash
dh dh.pem
```
* Haremos que el servicio OpenVPN se ejecute con el usuario `nobody` y grupo `nogroup` descomentando estos valores
```bash
user nobody
group nogroup
```
* Apuntaremos a nuestro certificado generado anteriormente
```bash
cert ovpn.crt
key ovpn.key
```
* Y para finalizar forzaremos que todo el tráfico de los clientes sea redirigido por la VPN. Buscaremos y descomentaremos las siguientes líneas
```bash
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
```
### Directivas adicionales
* Habilitar la redirección de tráfico
```bash
sudo nano /etc/sysctl.conf # sudo vim /etc/sysctl.conf
net.ipv4.ip_forward=1 # Descomentar esta línea
```
### Puesta en funcionamiento del servicio
* Arrancar y comprobar el estado del servicio OpenVPN
```bash
sudo systemctl start openvpn@server && sudo systemctl status openvpn@server
```
* Comprobar la existencia de la intefaz virtual de OpenVPN
```bash
ip addr show tun0
```
* Habilitar el arranque automático de OpenVPN
```bash
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
```bash
mkdir -p ~/client-configs/files
```
* Copiamos la plantilla de configuración de cliente por defecto y procedemos a editarla
```bash
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
nano ~/client-configs/base.conf # vim ~/client-configs/base.conf
```
* Localizamos la directiva `remote` y establecemos la IP y puerto de nuestro servidor VPN
```bash
remote ovpn.bastionado.es 1194
```
* Nos aseguramos de establecer el protocolo en `UDP`
```bash
proto udp
```
* Realizamos un descenso de privilegios después de inicializar en sistemas que no son Windows descomentando las siguientes líneas
```bash
user nobody
group nogroup
```
* Comentamos los ficheros de certificados y `tls-auth` ya que esta es la plantilla y se establecerán individualmente
```bash
#ca ca.crt
#cert client.crt
#key client.key
#tls-auth ta.key 1
```
* Establecemos las mismas directivas `cipher` y `auth` que establecimos en el servidor
```bash
cipher AES-256-CBC
auth SHA512
```
> La directiva `key-direction` establece una forma alternativa de especificar el parámetro opcional de dirección para las opciones `tls-auth` y `secret`, Es útil cuando se utilizan ficheros incrustados.
* Establecemos la directiva `key-direction`
```bash
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
```bash
nano ~/client-configs/make_config.sh # vim ~/client-configs/make_config.sh
```
* Añadimos el siguiente código al script
```bash
#!/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
```bash
chmod 700 ~/client-configs/make_config.sh
```
* Y ahora ya podemos generar el fichero de configuración para `client1`
```bash
cd ~/client-configs
sudo ./make_config.sh client1
```
* El fichero resultante, `bastionado-client1.ovpn` deberá entregarse al cliente para que éste pueda conectar a la VPN.
## Habilitando el forwarding en nftables
```bash
#!/usr/sbin/nft -f
flush ruleset
define vpn_port=1194
define vpn_if=tun0
define outside_if=enp0s17
define vpn_subnet=10.8.0.0/24
table inet filter {
chain input {
# allow generic VPN connections to the Server
udp dport $vpn_port accept
# allow OpenVPN
# udp dport 1194 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 packats 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;
}
}
```
```bash
sudo systemctl restart nftables.service && sudo systemctl status nftables.service
sudo systemctl enable nftables.service
```
## Habilitando tor
```bash
sudo apt install tor
sudo vim /etc/tor/torrc
VirtualAddrNetwork 10.192.0.0/10
AutomapHostsOnResolve 1
DNSPort 10.8.0.1:53530
TransPort 10.8.0.1:9040
sudo systemctl restart tor.service
sudo netstat -tulpen | grep tor
```
```bash
#!/usr/sbin/nft -f
flush ruleset
define vpn_port=1194
define vpn_if=tun0
define outside_if=enp0s17
define vpn_subnet=10.8.0.0/24
table inet filter {
chain input {
# allow OpenVPN 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 packats 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 ip saddr $vpn_subnet udp dport 53 counter dnat to 10.8.0.1:53530
iifname $vpn_if ip protocol tcp ip saddr $vpn_subnet counter dnat to 10.8.0.1:9040
iifname $vpn_if ip protocol udp ip saddr $vpn_subnet counter dnat to 10.8.0.1:9040
}
}
```
```bash
sudo systemctl restart nftables.service && sudo systemctl status nftables.service
```
```bash
sudo vim /etc/openvpn/server.conf
push "dhcp-option DNS 10.8.0.1"
```
```bash
sudo systemctl restart openvpn@server.service && sudo systemctl status openvpn@server.service
```
## Landing Page para descarga de configuración cliente
```bash
curl -sSL https://packages.sury.org/nginx/README.txt | sudo bash -x
```
```bash
sudo apt update
```
```bash
sudo apt install nginx-core nginx-common nginx nginx-full apache2-utils
```
```bash
cd /var/www
sudo htpasswd -c .htpasswd client1
```
```bash
sudo dd if=/dev/null of=/etc/nginx/nginx.conf && sudo vim /etc/nginx/nginx.conf
```
```bash
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/*;
}
```
```bash
sudo dd if=/dev/null of=/etc/nginx/sites-available/default && sudo vim /etc/nginx/sites-available/default
```
```bash
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;
}
}
```
[bastionado-vpn.tar](/assets/files/bastionado-vpn.tar)
```bash
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
```