abr 05
2010
OpenVPN-AD: Autenticación en Active Directory
Enviado por K-nábora Bufete Tecnológico en window$, Sistemas, seguridad, networking, linux
OpenVPN es una de las herramientas más utilizadas para la creación y gestión de redes privadas virtuales debido a cuatro factores principalmente: facilidad de instalación y uso, fiabilidad, multiplataforma (es posible su instalación en distintos sistemas operativos) y ser opensource.
Cuando un cliente intenta realizar una conexión con un servidor OpenVPN, este último debe autenticar y validar de alguna manera a dichos usuarios. Para ello, OpenVPN provee dos mecanismos distintos:
- En base a certificados digitales (incorpora la herramienta openssl para la creación de certificados)
- Mediante usuario y contraseña
Para el caso que nos ocupa, nos vamos a centrar en la autenticación con usuario y contraseña. Mediante este mecanismo, que puede ser alternativo o completentario al uso de certificados digitales, el cliente demanda al usuario dicha información y la envía al servidor para su validación.
Dicho proceso de envío por parte del cliente al servidor se puede realizar de dos maneras distintas, dependiendo de la configuración del servidor:
- Mediante variables de entorno
- A través de un fichero temporal
El servidor, una vez que recoge el nombre del usuario y la contraseña, ejecuta un script para validar la información y autorizar la conexión por parte del cliente. Existen diferentes scripts para poder realizar dicho proceso en Linux, pero no hemos encontrado ninguno que contraste los datos de usuario con Active Directory, así que nos hemos puesto manos a la obra.
En primer lugar, hay que configurar el cliente y el servidor de manera que realicen este tipo de proceso de validación. En el fichero de configuración del cliente hay que introducir la línea "auth-user-pass" para que el cliente pida al usuario que proporciones su usuario y contraseña. En el fichero de configuración del servidor hay que insertar la línea "auth-user-pass-verify script via-file" donde script es el nombre del script, y via-file es el método de envío de los datos por parte del cliente. Para este caso en concreto se enviará dentro de un fichero.
El script en cuestión puede ser escrito en varios lenguajes, aunque los más cómodos para ello son perl y python. Nosotros hemos elegido este último por familiaridad.
Al principio del fichero están definidas una serie de variables, como pueden ser la dirección del controlador de dominio, la ruta de directorio que hay que modificar y algunas otras, que hay que adaptar y modificar para que se amolden a los diferentes entornos. Entre todas estas variables hay una, grupovpn, que requiere una explicación.
Para poder diferenciar los usuarios privilegiados que se pueden conectar a través de una vpn de los que no, hemos enfocado el script de manera que busque en un grupo existente en el sistema a los usuarios a los que se les permite el acceso externo mediante este mecanismo. De ahí que existan una variable en el script que contenga el grupo donde se encuentran dichos usuarios. De esta forma, cuando un usuario conecta, primero se valida que el usuario sea un usuario válido del dominio y después, que dicho usuario se encuentre dentro del grupo de usuarios de vpn.
A continuación, reflejamos el script de autenticación, cortesía de SG6 Labs:
------------------------------------------------------------------------------------------
# Copyright SG6 - Soluciones Globales en Seguridad de la Informacion
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import sys
import ldap
#----------------------------- INFORMACION A MODIFICAR ------------------#
#Nombre del grupo de usuarios que podran tener acceso a la conexion por VPN
grupovpn="vpnusers"
#Nombre del dominio de la organizacion, es decir DC=example,DC=com
dominio="example.com"
#Ruta del directorio donde se encuentran alojados los grupos, se podria utilizar la raiz del
#directorio pero de esta manera es mas rapido. Tambien se puede usar la raiz si se desconoce
#la ruta de los grupos y usuarios
basegrupo="CN=Groups,DC=example,DC=com"
#Ruta del directorio donde se enctran alojados los usuarios
baseusuario="CN=Users,DC=example,DC=com"
#Direccion del servidor controlador de dominio
nombredc="server.example.com"
#-------------------------- FIN INFORMACION A MODIFICAR ------------------#
#El nombre del fichero con usuario y password se pasa como argumento por
#parte de OpenVpn
f=open(sys.argv[1],'r')
contenido=f.readlines()
f.close()
#Se quita el n porque si no, no se realizan correctamente las busquedas
usuario=contenido[0][:-1]
password=contenido[1][:-1]
try:
l = ldap.open(nombredc)
#Conectando de esta manera se evitan problemas de que el CN del usuario
#contenga acentos, ya que en el nombre de usuario no deben haber
l.simple_bind_s(usuario+"@"+dominio,password)
#El alcance de la busqueda es de subarbol
scope=ldap.SCOPE_SUBTREE
#Primero se obtiene el nombre completo del grupo del tipo CN=nombregrupo,CN=...
filter = "(&(objectCategory=Group)(cn="+grupovpn+"))"
res=l.search_s(basegrupo,scope,filter)
#Se extrae la ruta del grupo a partir del record devuelto por la busqueda
grupotemp=res[0][0]
#Ahora el filtro busca entradas en el directorio con el nombre de usuario y que sea
#miembro del grupo de usuarios de vpn
filter="(&(objectCategory=user)(sAMAccountName="+usuario+")(memberOf="+grupotemp+"))"
res=l.search_s(baseusuario,scope,filter)
#Si ha encontrado entradas permite la conexion
if len(res)==0:
sys.exit(1)
sys.exit(0);
except ldap.LDAPError, error_message:
sys.exit(1);


