Archive for 22 enero 2014

h1

¿Kerberizamos un poco?

enero 22, 2014

Ser administrador de sistemas requiere una gran dosis de paciencia.

En estos días he necesitado mucha para enfrentarme al “todopoderoso” Kerberos, sistema introducido por el M.I.T. a principios de los años 80 tras haber utilizado con éxito el protocolo a nivel interno.

El gran problema a la hora de trabajar con Kerberos es la grandísima cantidad de módulos e implementaciones que tiene. En la actualidad se utiliza la versión 5 (la 4 fue la primera en distribuirse para uso general) asociada a un montón de RFCs que describen en detalle la operativa. Si a esto le añadimos las variaciones que pueden tener los diferentes despliegues en las decenas de sistemas operativos que lo soportan, pues ya la tenemos liada.

El escenario en el que me he movido estos días era un poco atípico: necesitaba aprovechar un servidor NAS (FreeNAS 9.2) algo infrautilizado para que los usuarios de otra sede de mi empresa tuvieran un repositorio de Subversion que rindiera, sin estar sujeto a la lentitud y latencia de un túnel IPsec. Así que paso a paso os cuento lo que hice y las locuras a las que me enfrente con estos elementos:

  • Servidor Windows 2008 R2 Server
  • Servidor FreeNAS 9.2 integrado en el directorio activo.
  • Jail de FreeBSD con los “ports” disponibles.

Mi objetivo era no hacer una chapuza, intentando que el cliente SVN se conectase al repositorio de forma segura (SSL) y sin necesidad de transmitir usuario/contraseña.

En primer lugar puse en marcha un precioso “jail” con la plantilla “pluginjail” de FreeBSD que FreeNAS incluye en el GUI, esta plantilla es genial porque tiene lo justito y necesario para desplegar con facilidad un servidor SVN publicado por Apache y los elementos necesarios para gestionar Kerberos.

Aunque es realmente sencillo desplegar un FreeBSD con esta plantilla, detecté la aparición de bastantes errores en el “syslog” relativos al Netbios, ya que FreeNAS monta un alias IP para el “bridge” con el “jail”, generando una duplicidad de “host” para las dos IPs, para evitarlo os recomiendo activar VIMAGE y eliminar la IP alias, esto virtualiza la pila TCP/IP y, aunque es una característica algo experimental, lo cierto es que funciona bastante bien.

Una vez tengáis una IP asignada al “jail” de FreeBSD y acceso al “shell”, tendréis que modificar bastantes parámetros, en concreto en /etc/hosts conviene que el FQDN del “jail” esté reflejado en la 127.0.0.1

Ejemplo:  127.0.0.1                 localhost serversvn.dominio.local

Aunque en muchas guías se ponen pesados con la resolución inversa en el DNS del FQDN, realmente no es necesario. 

Haremos un “cd /usr/ports” y procederemos a instalar los paquetes que necesitamos. Por si acaso no estáis familiarizados:

[cmd] cd /usr/ports/www/apache22 ; make install [/cmd]
(usamos Apache 2.2 por no disponer de Kerberos el port del 2.4)

Con ello saldrá la pantalla de configuración. No olvidéis activar el módulo SSL y el “rewrite” que siempre vienen bien para por ejemplo forzar https de forma trasparente para el usuario. También para SVN harán falta el DAV y DAV_FS. Y mediante el mismo procedimiento instalaremos en /usr/ports/www/mod_auth_kerb2 el módulo de Kerberos para Apache.

Para terminar ya solamente nos hace falta Subversion, en /usr/ports/devel/subversion dispondremos de la última versión (siempre es recomendable hacer un [cmd] portsnap fetch ; portsnap update [/cmd] por si las moscas. No olvidemos en la pantalla de configuración activar el MOD_DAV_SVN que instalará y activará el módulo DAV necesario para los clientes.

Tocaría ahora configurar el fichero /etc/krb5.conf para configurar el KDC. Es realmente sencillo si, lógicamente, tenemos algo de idea respecto a la configuración para por ejemplo la integración de Samba en un directorio activo. Por si acaso os paso un ejemplo con unos parámetros revisados y comprobados:

[libdefaults]
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24000
clockskew = 300
default_realm = DOMINIO.LOCAL [realms]
DOMINIO.LOCAL = {
kdc = kdc.dominio.local:88
} [domain_realm]
dominio.local = DOMINIO.LOCAL
.dominio.local = DOMINIO.LOCAL
DOMINIO.LOCAL = DOMINIO.LOCAL
.DOMINIO.LOCAL = DOMINIO.LOCAL [appdefaults]
kinit = {
renewable = true
krb4_convert = false
forwardable = true
}

Y con esto pasamos a la chicha, que es la parte que más se me ha complicado debido a a los tipos de cifrado soportados. Inicialmente Microsoft en este enlace nos dice alegremente que pasemos de verificar el KDC con la opción “KrbVerifyKDC Off”, lo cual abre una brecha de seguridad que posibilita a un atacante meternos un servidor maligno que Apache no se preocupe de comprobar. Entiendo que es complicado que alguien se preocupe de venir a nuestra oficina con un servidor malo maloso, pero nunca se sabe, especialmente en grandes empresas 🙂

Si hubiera decidido hacer caso a M$ estaría todo listo en un par de horas, pero preferí complicarme la vida a sabiendas de que no hay buena documentación y, los foros, a veces más que ayudar nos complican la vida. Eso si, reconozco que en los tiempos pretéritos buscarse la vida entre miles de fotocopias, libros y apuntes era mucho peor.

Lo primero de todo es crear una cuenta en el directorio activo para que la pueda utilizar el servicio Apache. La contraseña la podemos definir ahora o luego (cuando generemos el “keytab” con el comando “ktpass”). Como nombre de inicio de sesión de usuario indicaremos el servicio y el FQDN, es decir: HTTP/serversvn.dominio.local y como nombre de cuenta (anterior a Windows 2000) lo que queramos. Anotamos los datos y esa será la cuenta que hará de enlace con el directorio activo para autenticar a los usuarios de Apache.

Una vez hecho esto vamos a la línea de comandos del servidor de dominio y generamos el fichero “keytab” que viene a ser una forma segura de validar al servidor  Apache contra el KDC. El comando es un poco engorroso, así que os paso los parámetros que funcionan a la perfección en mi escenario:

[cmd] C:\>ktpass -princ HTTP/serversvn.dominio.local@DOMINIO.LOCAL -mapuser usuariosvn@DOMINIO.LOCAL -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL -pass password -out fichero.keytab [/cmd]

Parece algo lioso, pero no lo es. Básicamente lo parametrizamos como servicio HTTP, la / actua de separador, luego va el FQDN del servidor que utilicemos (a estas alturas supongo ya has registrado una entrada DNS estática apuntando al “serversvn”) y lo mapeamos como el usuario (anterior a Windows 2000) que acabamos de crear. Indicamos la versión y tipo de servicio Kerberos y el cifrado, finalmente indicamos el nombre del fichero keytab que copiaremos posteriormente en /usr/local/etc/apache22/keytab o una ruta a la que tenga acceso Apache.

Ahora vamos al directorio activo y en el usuario que hemos creado marcamos en “Opciones de cuenta” que la contraseña nunca expire, también marcamos “No pedir la autenticación de Kerberos previa” y, finalmente, el detalle que me complicó la vida enormemente, que aunque no parezca necesario es imprescindible: marcad también “Esta cuenta admite cifrado AES de Kerberos de 256 bits” porque parece que por defecto el KDC basado en Windows 2008 Server utiliza otro cifrado (y esto por más que he mirado, no lo he visto en ningún lado, de hecho M$ afirma tenerlo activo por defecto).

Esta cuenta recomiendo que sea miembro de “Invitados del dominio”, no precisamos que tenga acceso a más recursos que el simple intercambio de “tickets Kerberos”.

Con esto queda lo más sencillo. En primer lugar conviene poner unos permisos restrictivos al “keytab” y lo haremos legible a Apache cambiando el propietario. Una vez tenemos el fichero “keytab” en el “jail” de FreeBSD hacemos:

[cmd] chmod 640 /usr/local/etc/apache22/keytab/fichero.keytab ; chown www:www /usr/local/etc/apache22/keytab/fichero.keytab [/cmd]

Y probamos que el “keytab” funciona bien: ” kinit -k -t fichero.keytab HTTP/serversvn.dominio.local” . Si tenemos la suerte de no recibir ningún error, con el comando “klist” veremos que tenemos un “ticket kerberos” emitido para nuestro servidor, comprobad que el SPN es completo, incluyendo el @DOMINIO.LOCAL

Si hay error tendremos que verificar que hay conectividad al KDC y que los pasos anteriores han sido correctamente realizados.

Y para finalizar queda configurar Apache, donde tan sólo toca personalizar en el fichero /usr/local/etc/apache22/httpd.conf los siguientes parámetros:

  1. servername serversvn.dominio.local  (FQDN)
  2. Listen 443 (o el puerto que queramos utilizar para https)
  3. Revisamos que los módulos “mod_auth_kerb.so”, “mod_rewrite.so”, “mod_dav.so”, “mod_dav_fs.so”, “mod_ssl.so”, “mod_dav_svn.so” y “mod_authz_svn.so” están sin comentar.
  4. Personalizamos el DocumentRoot a donde publicaremos los repositorios SVN.
  5. En el <Directory “/usr/local/www…> indicamos el DocumentRoot que acabamos de definir y dejamos sin comentar solamente AllowOverride All (para permitir autenticación kerberos) y listo. Esto también podríamos definirlo posteriormente en el Virtual Host, pero en ocasiones hay gente a la que le da problemas.

Entiendo en este punto que sabéis generar los certificados necesarios para https ya sea con OpenSSL, PKI de dominio o comprando un certificado a una entidad certificadora. Una vez tengamos los certificados crearemos la ruta /usr/local/etc/apache22/Includes un fichero.conf con el siguiente contenido:

# Forzamos https
<VirtualHost *:80>
RewriteEngine on
ReWriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R,L]
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile etc/apache22/ssl/serversvn.crt
SSLCertificateKeyFile etc/apache22/ssl/serversvn.key
SSLCACertificateFile etc/apache22/ssl/CA.crt
<Location />
DAV svn
SVNParentPath /usr/local/www/subversion/
SVNListParentPath On
SVNAutoVersioning On
AuthName “SVN SERVER
AuthType Kerberos
KrbMethodNegotiate On
KrbVerifyKDC On
KrbSaveCredentials On
KrbMethodK5Passwd Off   (esto es opcional pero recomendable como medida de seguridad)
KrbAuthRealms DOMINIO.LOCAL
Krb5KeyTab /usr/local/etc/apache22/keytab/fichero.keytab
KrbServiceName HTTP/serversvn.dominio.local
SSLRequireSSL
Require valid-user
</Location>
<Location /repo1>
AuthzSVNAccessFile /usr/local/www/subversion/repo1/conf/auth.conf
</Location>
</VirtualHost>

Con esto ya estamos cerca de terminar, y ya me gustaría a mi que alguien me hubiese preparado todos los pasos así tan sencillos 🙂

Vamos a crear el repositorio y el fichero de autenticación de usuarios de dominio autorizados para el “repo1”. Presupongo que en la ruta “DocumentRoot” antes definida habéis creado el directorio “subversion” o como lo queráis llamar. Hacéis un “cd” a la ruta de subversion y con el comando “svnadmin create repo1” generamos la estructura.

Entraremos en repo1/conf/ y crearemos el fichero auth.conf y dentro establecemos los permisos tal como viene definido en la ayuda de ejemplo que tenemos en el fichero “authz”, con la salvedad de que a todos los usuarios debemos agregarles @DOMINIO.LOCAL 

Siempre mucho cuidadín con las rutas, no es raro despistarse y que se produzcan errores por este motivo.

Hacemos un buen “apachectl restart” tras crear el repositorio SVN, así nos aseguramos de que no hay errores de sintaxis en los ficheros de configuración de Apache y ya sólo queda lo fácil, que es ir a cualquier cliente de SVN en un equipo que esté en el dominio para probar, aunque también podemos utilizar Internet Explorer que por defecto reconoce como zona Intranet a cualquier equipo con FQDN de nuestro dominio: https://serversvn.dominio.local/repo1 y a ver qué pasa. ¡Suerte!