By

Autenticando con certificado digital tras un proxy reverso

Hace ya algún tiempo, trabajando en Yaco Sistemas, me encontré con un contratiempo tras desplegar una aplicación web y hoy he decidido compartir con vosotros la experiencia. Así que voy a ello.

Escenario

Como apunte inicial, comenzaré diciendo que este post trata la autenticación con certificado digital x509 entre Apache y Tomcat y el escenario en el que nos movemos sería, a grandes rasgos, como el que muestra la imagen a continuación.

Escenario autenticacion Apache Tomcat

Bien, empecemos por el principio. Tenemos un usuario el cual ya tiene un certificado digital x509 configurado en su navegador con el cual se le permite autenticar en una aplicación web que se encuentra desplegada en un servidor Tomcat con el conector AJP debidamente configurado.

Con todo esto, si el usuario lanzara la petición de autenticación directamente al servidor Tomcat, éste le pediría un certificado válido al usuario, y tras recibirlo y validar que es correcto, realizaría la autenticación sin problemas.

Pero nuestro escenario no es tan idílico, ya que para poder llegar al servidor Tomcat, antes pasaremos por un servidor Apache que actuará como proxy reverso (Reverse Proxy) y aquí es donde se complican las cosas, obteniendo el resultado que muestra la siguiente imagen.

Apache Tomcat autenticacion fallida

El usuario accede a la aplicación intentando autenticar con certificado digital, pero no obtiene la respuesta esperada sino un error indicando que no se ha ofrecido ningún certificado. ¿Por qué ha pasado esto?

Lo que ha ocurrido es que la petición del usuario ha llegado al proxy reverso (Apache2) y éste inicia una petición similar, pero nueva, hacia la aplicación web en Tomcat. Es decir, realiza una petición similar, creando una nueva petición, pero no manteniendo la anterior; con lo cual, la aplicación web (Tomcat) pide un certificado digital al proxy reverso (Apache2), originando un error e imposibilitando la autenticación, pues el proxy reverso no tiene configurado ningún certificado.

Solución

Y aquí es donde viene la magia y lo que me salvó de la tragedia aquel día. Se trata de una opción especial en SSL llamada +ExportCertData. Sí sí, a mi también me pareció increíble, pero esta opción lo arregla todo en la comunicación entre nuestro usuario y la aplicación final.

En la configuración HTTPS de nuestro proxy reverso, es decir Apache2, deberemos incluir la siguiente opción SSL:

SSLOptions +ExportCertData

Un ejemplo de configuración HTTPS para el proxy reverso podría ser la siguiente:

Listen 443
NameVirtualHost *:443
<VirtualHost *:443>
   ServerName localhost

   ErrorLog /var/log/apache2/https-error.log
   CustomLog /var/log/apache2/https-access.log combined

   SSLEngine On
   SSLCertificateFile    /etc/apache2/ssl/server.crt
   SSLCertificateKeyFile /etc/apache2/ssl/server.key

   SSLCACertificateFile /etc/apache2/ssl/client-accepted-ca-chain.crt
   SSLVerifyClient require
   SSLVerifyDepth 2

   SSLOptions +ExportCertData

   <Proxy *>
     AddDefaultCharset Off
     Order deny,allow
     Allow from all
   </Proxy>

   ProxyPass / ajp://tomcat:8009/
   ProxyPassReverse / ajp://tomcat:8009/

</VirtualHost>

Bien! Ya tenemos el proxy reverso configurado correctamente! Rápidamente comprobamos que la sintaxis sea correcta y reiniciamos el servicio para que los cambios se hagan al fin efectivos.

# apachectl -t
Syntax OK
# apachectl graceful

Comprobando el resultado

Hecho todo esto, ahora la autenticación debería realizarse sin problemas. El esquema de la comunicación entre el usuario y la aplicación final sería algo como lo que muestra la imagen que sigue:

Apache Tomcat autenticación correcta

El usuario inicia la petición de autenticación a la aplicación web haciendo uso de su navegador. La petición viaja a través del proxy reverso (Apache2) que ahora, al contar con la opción especial +ExportCertData, éste no inicia una nueva petición, sino que “retransmite” la petición iniciada por el usuario y los datos del certificado, haciendo posible la autenticación.

Pues esto es todo. Espero que a alguien le sirva de ayuda en caso de tener el mismo problema, a mi +ExportCertData “me salvó el día” :-)

Un saludo.