Apache kerberizado - Single Sign On (AD y MIT Kerberos)

Una funcionalidad que se está utilizando mucho en las empresas es el Single Sign On (SSO), esto es, permitir que los usuarios se logueen una vez y accedan a todos los sistemas que necesiten, sin tener que ingresar nuevamente sus credenciales. Más allá de las graves implicaciones de seguridad que esto acarrea, es algo que se está utilizando mucho y que los administradores deben conocer.
El SSO no es otra cosa que kerberizar servicios, es decir, autenticar el usuario, obtener un ticket, y luego solicitar servicios con el ticket de sessión. En el caso de los servicios Web, MS integra fácilmente IIS con la autenticación de Active Directory. Apache, por su parte, también brinda esta posibilidad.
En este artículo mostraré los pasos necesarios para kerberizar Apache, es decir, permitir que un usuario acceda a un sitio web sólo si antes se autentica utilizando kerberos. La configuración mostrada es sobre un servidor GNU/Linux, y describe los pasos para kerberizar Apache tanto en una red con AD, como en una de MIT Keberos.
Se asume que el lector tiene ciertos conocimientos básicos de kerberos. Sino pueden leer los artículos que escribí anteriormente sobre el tema:
- Instalación de MIT Kerberos
- Configurar PAM para utilizar kerberos
- Autenticar con kerberos y almacenar información de usuarios con LDAP en GNU/Linux
- OpenLDAP kerberizado

Yendo al grano, los pasos de configuración son los siguientes:

1. Crear un usuario en el dominio que servirá como principal para el servicio HTTP (solicitud de tickets de servicio). El uso es como el de una cuenta de máquina.
  En AD:
    - Abrir Active Directory Users and Computers (ADUC)
    - Ir al dominio donde se creará el usuario.
    - Click derecho en Users
    - Elegir New -> User
    - Completar los datos y finalizar.

  En MIT Kerberos:
      # kadmin.local
      Authenticating as principal root/admin@DVPEM.ORG with password.
      kadmin.local: addprinc -randkey HTTP/apache.dvpem.org@DVPEM.ORG
      WARNING: no policy specified for HTTP/apache.dvpem.org@DVPEM.ORG; defaulting to no policy
      Principal "HTTP/apache.dvpem.org@DVPEM.ORG" created.
      donde -randkey permite generar un password random.

2. Mapear el servicio HTTP con el usuario recién creado y exportar el keytab para ser utilizado en el servidor:
    En AD:
      ktpass -princ HTTP/apache.dvpem.org@DVPEM.ORG -mapuser DVPEM\pruebaapache -ptype KRB5_NT_PRINCIPAL -pass prueba -out C:\apache.keytab
    donde:
      -princ indica el nombre que tendrá el principal (servicio HTTP)
      -mapuser indica el usuario con el que se mapea el servicio
      -ptype especifica el tipo del principal
      -pass asigna un password para el principal. Si utilizan un asterisco (*) el sistema pregunta el password.
      -out especifica el nombre del archivo keytab a generar
    Dependiendo del tipo de encripción soportado por el servidor y el cliente, puede ser necesario especificar el uso de encripción débil. Esto se realiza con:
      -mapop set +desonly
      -crypto all o bien -crypto DES-CBC-MD5

    En MIT Kerberos:
      kadmin.local: ktadd -k /root/apache.keytab HTTP/apache.dvpem.org
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/root/apache.keytab.

3. Copiar el keytab al servidor donde se encuentra Apache instalado. Cambiar el dueño del archivo y restringir los permisos. Si por ejemplo se copia el archivo a /etc/apache2/apache.keytab, ejecutar lo siguiente:
    chown www-data:www-data /etc/apache2/apache.keytab
    cmod 400 /etc/apache2/apache.keytab

4. Instalar en el servidor web las utilidades de kerberos y el módulo de Apache, y habilitar el módulo:
    # apt-get install krb5-{config,user} libapache2-mod-auth-kerb
    # a2enmod mod_auth_kerb

5. Configurar los valores de realm, KDCs, y dominios para kerberos. Esto es, editar las siguientes líneas del archivo /etc/krb5.conf
  - En la sección libdefaults setear el nombre del realm:
      default_realm = DVPEM.ORG
  - En la sección realms, indicar cuáles son los servidores KDC para nuestro realm:
      DVPEM.ORG = {
 kdc = kdc01.dvpem.org:88
 admin_server = kdc01.dvpem.org
 }
  - En la sección domain_realm, agregar los mapeos de dominio con realms:
      .dvpem.org = DVPEM.ORG
      dvpem.org = DVPEM.ORG

6. Testear si kerberos funciona correctamente. Para ello, solicitar un ticket de usuario, para un usuario válido del dominio:
    $ kinit demasiadovivo@DVPEM.ORG
    $ klist

7. Agregar la siguiente configuración a apache para el directorio que se desea autenticar con kerberos. En este ejemplo, la intención es autenticar el directorio /var/www/mipagina
    <Directory /var/www/mipagina>
      AuthType Kerberos
      AuthName "Kerberos Login"
      KrbMethodK5Passwd Off
      KrbMethodNegotiate On
      KrbAuthRealms DVPEM.ORG
      KrbServiceName HTTP
      Krb5KeyTab /etc/apache2/apache.keytab
      require valid-user
    </Directory>
donde:
  AuthType Kerberos: especifica el tipo de autenticación
  KrbMethodNegotiate On: habilita el uso de SPNEGO (GSSAPI-SASL)
  KrbMethodK5Passwd Off: deshabilita el uso de password para la autenticación. Esto puede causar problemas con browsers que no soportan SPNEGO, o máquinas que no se encuentran unidas al dominio. En estos casos puede setearse este valor en On, pero esto permite el uso de autenticación BASIC (muy insegura).
  KrbAuthRealms DVPEM.ORG: especifica el realm (o dominio)
  KrbServiceName HTTP: nombre del servicio
  Krb5KeyTab /etc/apache2/apache.keytab: donde se encuentra el keytab
  require valid-user: fuerza a que el usuario sea validado antes de acceder.

8. Chequear que el ticket provisto por el servidor contiene un tipo de encripción que es consistente con los valores configurado en el keytab:
  Obtener un ticket de servicio y listar los tipos de encripción:
    kvno HTTP/apache.dvpem.org@DVPEM.ORG
    klist -e
  Mostrar los tipos de encripción configurados en el keytab:
    klist -e -k -t /etc/apache2/apache.keytab
Si los valores no coinciden, el servicio no podrá ser utilizado.
NOTA: Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar errores en la autenticación.

9. Reiniciar Apache y probar la configuración accediendo a la página Web protegida con Kerberos.
Algo muy importante es que debe utilizarse el nombre DNS especificado en el keytab como nombre del servicio, dado que si se utiliza la IP o un alias, la autenticación no funcionará.

10. Errores, posibles causas y soluciones. A continuación se listan los errores con los que me topé al configurar el servicio y una explicación sobre cómo lo solucioné. Además incluí soluciones alternativas.
  krb5_get_init_creds_password() failed: Cannot resolve network address for KDC in requested realm
    - Verificar que tanto el registro A como el registro PTR del servidor se encuentren registrados. Si por ejemplo el nombre del servidor apache es apache.dvpem.org, debe ingresarse el registro PTR correspondiende a la IP de dicho servidor.
    - El parámetro KrbAuthRealms de Apache debe estar seteado correctamente. Recordar que en este parámetro se especifica el realm (dominio) en mayúsculas:
KrbAuthRealms DVPEM.ORG
    - Los kdc del dominio se encuentran seteados correctamente en el archivo /etc/krb5.conf. Un ejemplo de esta configuración es:
DVPEM.ORG = {
 kdc = kdc01.dvpem.org:88
 admin_server = kdc01.dvpem.org
 }

  failed to verify krb5 credentials: Server not found in Kerberos database
    - El principal utilizado esta mal configurado en el keytab creado o en el atributo KrbServiceName de la configuración de Apache.
    - Al acceder a la página debe utilizarse el nombre del servidor registrado en el keytab. Es decir, si el principal está designado para apache.dvpem.org, en el navegador debe utilziarse la dirección apache.dvpem.org.
   
  failed to verify krb5 credentials: KDC has no support for encryption type
    - El tipo de encripción aceptada por el servidor no es compatible con la encripción aceptada por el cliente, o bien los tipos de encripción configurados en el keytab no son compatibles con el servidor. Verificar obteniendo un ticket de servicio y la encripción soportada en el keytab:
      kvno HTTP/apache.dvpem.org@DVPEM.ORG
      klist -e
      klist -e -k -t /etc/apache2/apache.keytab
      Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar el error mencionado si se utilizan estos sistemas.
   
  gss_acquire_cred() failed: Unspecified GSS failure.  Minor code may provide more information (, )
    - Revisar si no se encuentra seteado el valor "Use Kerberos DES encryption for this account" en la cuenta del usuario utilizada para el pricipal.

 
Referencias

- Kerberos Module for Apache - Configuration
- Configure Apache to use Kerberos authentication
- Kerberos authentication with Apache in a multi-domain Active Directory
- Single Sign On with Kerberos using Debian and Windows Server 2008 R2
- Kerberos-Based SSO with Apache
- Using mod_auth_kerb and Windows 2000/2003/2008R2 as KDC
- Apache on Linux and Single-Sign-On with Active Directory
- Active Directory and Apache Kerberos authentication
- JBoss Doc - Chapter 5. Configuring Microsoft Active Directory
- Ktpass