Servidor VPN con OpenVPN autenticando con LDAP

Hace poco un compañero de trabajo y yo, nos montamos en la tarea de armar un servidor para realizar conexiones vía VPN, usamos una versión Debian estable más reciente como sistema operativo y la versión de OpenVPN que está en el repositorio Debian de la misma versión.

Previamente a la configuración del servicio, se deben tener en cuenta las configuraciones del sistema operativo, posiblemente: conexiones a través de SSH, puertos, tarjetas de red, entre otras.

La idea, era crear un grupo en LDAP y los miembros de dicho grupo tener el privilegio de conectarse a través del servicio de VPN instalado en el servidor. Tomamos una interfaz de red para fijar una dirección IP pública y otra interfaz de red para fijar una dirección IP privada.

Luego instalamos los siguientes programas:

aptitude install openvpn openvpn-auth-ldap libnet-ldap-perl libipc-system-simple-perl

Una vez que se preparan las configuraciones previas, se deben realizar ciertas configuraciones específicamente para el servicio, cuando se realiza la instalación del OpenVPN se crea un directorio en la ruta absoluta /etc/openvpn, allí se deben copiar los certificados y llaves para el servicio, los mencionados deberían ser:

  • servidor-vpn.crt
  • servidor-vpn.key
  • dh1024.pem
  • ca.crt

Crear los directorios y permisos para guardar los mensajes logs correspondientes al servicio y autenticación de usuario:

mkdir /var/log/openvpn
mkdir /var/log/openvpn/usuarios
chmod 755 /var/log/openvpn
chmod 755 /var/log/openvpn/usuarios/
chown root.adm /var/log/openvpn
chown nobody.nogroup /var/log/openvpn/usuarios/

Particularmente, creamos un subdirectorio para dejar scripts personalizados de autenticación, por ejemplo: /etc/openvpn/at

mkdir /etc/openvpn/at

Tomamos un ejemplo de un script hecho en perl y lo modificamos a nuestras necesidades llamándolo: /etc/openvpn/at/valida-usuario.pl con un contenido parecido al siguiente:

#! /usr/bin/perl -w
 
use Net::LDAP;
use IPC::System::Simple qw(capture);
use strict;
 
my $ldap;
my $result;
my $base = "dc=sateliteguayana,dc=net,dc=ve";
my $opt_uri = "ldap.sateliteguayana.net.ve";
my $opt_user = $ENV{'username'};
my $opt_passwd = $ENV{'password'};
my $opt_fecha = capture('date');
my $opt_region = capture('ldapsearch -x -h '.$opt_uri.' -b '.$base.' uid='.$opt_user.' dn | grep ^dn: | cut -d" " -f2 | cut -d"," -f2,3,4'); 
my $opt_group = "cn=usuariosvpn,o=satelite,dc=sateliteguayana,dc=net,dc=ve";
my $opt_binddn = "uid=".$opt_user.",".$opt_region.",o=satelite,dc=sateliteguayana,dc=net,dc=ve";
 
open(LOGFILE,'>>/var/log/openvpn/usuarios/'.$opt_user.'.log');
$ldap = Net::LDAP->new($opt_uri) or die("connect $opt_uri failed!");
$result = $ldap->bind($opt_binddn,password=>$opt_passwd);
$result->code and die($result->error);
$result = $ldap->search(base=>$opt_group, filter=>"(&(memberUid=$opt_user))");
$result->code();
my $var_count = $result->count;
if ($var_count == 1) { 
 print LOGFILE "$opt_user: Conexion aceptada - ".$opt_fecha;
 exit 0; 
}
unless($var_count) { 
 print LOGFILE "$opt_user: Conexion rechazada - ".$opt_fecha;
 exit 1; 
}
close(LOGFILE);

Posteriormente, asignamos privilegios de ejecución:

chmod 755 /etc/openvpn/at/valida-usuario.pl

Creamos el archivo /etc/openvpn/servidor.conf con el contenido similar al siguiente:

# Direccion IP pública de servidor
local 192.168.1.12

port 1194
proto tcp
dev tap0
ca ca.crt
cert servidor-vpn.crt
key servidor-vpn.key
dh dh1024.pem

# IP servidor, mascara de red y rango
server-bridge 192.168.0.12 255.255.255.0 192.168.0.20 192.168.0.100
 
# Rutas hacia donde entrará la navegación del cliente foráneo
push "route 192.168.0.0 255.255.255.0"
 
# Opciones DNS, DOMINIO y PUERTA ENLACE
push "dhcp-option DNS 192.168.0.4"
push "dhcp-option DNS 192.168.0.5"
push "dhcp-option WINS 192.168.0.6"
push "dhcp-option DOMAIN sateliteguayana.net.ve"
push "route-gateway 192.168.0.12"
 
keepalive 10 120
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/vpn-status-servidor.log
log /var/log/openvpn/vpn-servidor.log
verb 3
script-security 3 system
 
# Integración con LDAP
auth-user-pass-verify /etc/openvpn/at/valida-usuario.pl via-env
client-cert-not-required
username-as-common-name

Finalmente tomamos el firewall que originalmente viene con OpenVPN anclado en la ruta /usr/share/doc/openvpn/examples/sample-config-files/firewall.sh y fue ajustado a nuestras necesidades.

#!/bin/bash
 
# Configuracion Firewall para VPN
# junio 2013
 
# eth0 IP internet
# eth1 IP corporativa
 
PRIVATE=192.168.0.12/24
LOOP=127.0.0.1
 
# Elimina reglas y politicas
iptables -P OUTPUT DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -F
iptables -t nat -X
iptables -t nat -Z
iptables -t nat -F
 
# Establece politicas
iptables -P OUTPUT ACCEPT
iptables -P INPUT DROP
iptables -P FORWARD DROP
 
# Prevenir paquetes externos usando loopback
iptables -A INPUT -i eth0 -s $LOOP -j DROP
iptables -A FORWARD -i eth0 -s $LOOP -j DROP
iptables -A INPUT -i eth0 -d $LOOP -j DROP
iptables -A FORWARD -i eth0 -d $LOOP -j DROP
 
# Cualquier entrada desde internet deberia tener IP real
iptables -A FORWARD -i eth0 -s 172.16.0.0/12 -j DROP
iptables -A FORWARD -i eth0 -s 10.0.0.0/8 -j DROP
iptables -A INPUT -i eth0 -s 172.16.0.0/12 -j DROP
iptables -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP
 
# Bloquear NetBIOS
iptables -A FORWARD -p tcp --sport 137:139 -o eth0 -j DROP
iptables -A FORWARD -p udp --sport 137:139 -o eth0 -j DROP
iptables -A OUTPUT -p tcp --sport 137:139 -o eth0 -j DROP
iptables -A OUTPUT -p udp --sport 137:139 -o eth0 -j DROP
 
# Chequeo de direcciones validas con salida a internet
iptables -A FORWARD ! -s $PRIVATE -i eth1 -j DROP
 
# Permitir loopback local
iptables -A INPUT -s $LOOP -j ACCEPT
iptables -A INPUT -d $LOOP -j ACCEPT
 
# Deshabilitar respuesta de ping
iptables -A FORWARD -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
 
# Permitir servicios por puertos especificos
iptables -A FORWARD -p udp --dport 53 -j ACCEPT
iptables -A FORWARD -p tcp -m multiport --dports http,https,ldap,ldaps -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports http,https,ldap,ldaps -j ACCEPT
 
# Permitir paquetes VPN a traves del puerto especifico
iptables -A INPUT -p tcp --dport 1194 -j ACCEPT
 
# Deshabilitar todo TUN y habilitar TAP
iptables -A INPUT -i tun+ -j DROP
iptables -A FORWARD -i tun+ -j DROP
iptables -A INPUT -i tap+ -j ACCEPT
iptables -A FORWARD -i tap+ -j ACCEPT
 
# Permitir entrada y transicion de red corporativa a traves eth1
iptables -A INPUT -i eth1 -j ACCEPT
iptables -A FORWARD -i eth1 -j ACCEPT
 
# Mantener estado de conexion desde maquina local y red privada
iptables -A OUTPUT -m state --state NEW -o eth0 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state NEW -o eth0 -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
 
# Mascara de red privada
iptables -t nat -A POSTROUTING -s $PRIVATE -o eth0 -j MASQUERADE
 
exit 0

Lo guardamos en un archivo /etc/network/if-up.d/firewall con sus respectivos privilegios de ejecución, para que levante al momento de levantar las interfaces de red.

Finalmente, se activó el bit de forwarding para permitir la comunicación entre el cliente foráneo y la red privada a través del servidor VPN, editando el archivo /etc/sysctl.conf y añadiendo un 1 a la variable net.ipv4.ip_forward y descomentándola, luego activando dicho bit:

sysctl -p

Completada la configuración, se reiniciaron los servicios de red y VPN:

invoke-rc.d networking restart ; invoke-rc.d openvpn restart

Las configuraciones y estimaciones específicas de LDAP dependen enteramente de las necesidades de quien lo usa, acá sólo publiqué un pequeño ejemplo genérico de como hicimos la configuración del servicio VPN.

Advertisements
This entry was posted in LDAP, VPN. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s