Cómo implementar un proxy reverso utilizando Apache y mod_jk para dar soporte HTTPS a Tomcat

Valoración del Usuario:  / 0
MaloBueno 

Apache Tomcat (o simplemente Tomcat, anteriormente conocido como Jakarta Tomcat) es un servidor web y servlet container Open Source desarrollado por la fundación Apache (Apache Software Foundation). Tomcat implementa las especificaciones de Java Servlet y JavaServer Pages (JSP) de Sun Microsystems, y provee un entorno de servidor Web HTTP donde el código Java pueda ejecutar.

Debido a que el servidor Tomcat no posee soporte para HTTPS, el objetivo de este artículo es demostrar cómo implementar un proxy reverso (implementado utilizando Apache) para dar soporte HTTPS a Tomcat. La comunicación entre Apache y Tomcat se realiza a través del conector "mod_jk", el cual se instala como un módulo de Apache.



Breve introducción

El escenario actual es el siguiente: los clientes solicitan páginas JSP al servidor Tomcat a través del protocolo HTTP (utilizando por ejemplo el navegador Mozilla Firefox), tal como se observa en la siguiente imagen.

El escenario deseado debería ser aquel en el que los clientes tengan la posibilidad de navegar los sitios hospedados en el servidor Tomcat utilizando HTTPS, o mejor aun utilizar sólo HTTPS y redireccionar todo el tráfico HTTP a HTTPS:

Para lograr el objetivo se incorpora un servidor Web Apache como proxy reverso transparente. Un proxy reverso es un servidor que accede a contenido en representación de un cliente. Los clientes se conectan por HTTPS al proxy reverso y éste lleva a cabo el pedido HTTP al servidor Tomcat como si se tratara del cliente. El lector perspicaz tal vez se pregunte: "¿para qué agregar un proxy reverso si de todas formas los pedidos se van a terminar haciendo por HTTP?". Bueno, el punto clave de la implementación es que ambos servidores se encuentren aislados dentro de una red segura (o inclusive podría tratarse de un mismo servidor si se configura de manera correcta). Además debe restringirse el acceso al puerto 80 del servidor Tomcat (mediante iptables) para que sólo escuche pedidos provenientes del proxy reverso.

En este artículo, la comunicación entre el servidor Apache y el servidor Tomcat se realiza utilizando el conector JK (aunque existen alternativas como "mod_proxy_http" y "mod_proxy_ajp"). La documentación oficial de mod_jk se encuentra en el siguiente enlace:

Working with mod_jk

Este módulo implementa la comunicación entre Apache y Tomcat a través del protocolo AJP (Apache Jserv Protocol), por lo tanto se debe utilizar en conjunto con el componente conector AJP de Tomcat (el cual debe ser configurado en el servidor Tomcat). El protocolo AJP es una versión de HTTP optimizada para la comunicación entre Apache y Tomcat sobre una conexión TCP. La versión actual del protocolo AJP es 1.3 (ajp13).

Documentación oficial AJP:

The Apache Tomcat Connector - AJP Protocol Reference

Para habilitar el conector AJP, editar el archivo de configuración del servidor Tomcat "server.xml" y agregar el siguiente contenido dentro de la sección <Service>:

<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />

Luego es necesario reiniciar el servidor Tomcat.

Escenarios de uso

Una pregunta que se hace a menudo es ¿por qué puede ser necesario comunicar Tomcat con Apache? Siendo una de las características de Tomcat la habilidad de funcionar como servidor Web y servidor de aplicación standalone, gracias al componente Coyote (The Coyote HTTP/1.1 Connector). Algunas buenas razones para necesitar comunicar un servidor Tomcat con un servidor Apache pueden ser:

  • Clustering, balance de carga y seguridad: Apache y mod_jk pueden utilizarse para balancear la carga entre múltiples instancias de Tomcat y dividir instancias de Tomcat en diferentes espacios de nombres.
  • Aprovechar la gran cantidad de módulos y extensiones disponibles para Apache: Apache ha sido el servidor Web más popular del mundo desde 1996, es por ello que existen innumerables módulos para extender su funcionalidad. En apache la instalación y configuración de módulos suele ser sencilla y ampliamente documentada. Comunicar un servidor Apache con Tomcat puede ser una buena alternativa para aprovechar toda estas herramientas.
  • Manejo de errores: A diferencia de Tomcat, Apache corre de forma nativa en un sistema en lugar de dentro de una máquina virtual Java cross-platform (JVM). Por esta razón tiene una ventaja en cuanto al manejo de errores de sockets (conexiones cerradas/inválidas, direcciones IP inválidas, etc.) debido a que las prácticas de optimización de sockets varían de forma significativa de un sistema operativo a otro.
  • Seguridad: Apache posee una comunidad mucho más grande que Tomcat, y por ello tiene muchos más "trucos bajo la manga" en lo que respecta a prácticas de seguridad. Esto no implica que tomcat sea menos seguro y la decisión de manejar la seguridad utilizando Apache debe basarse en el escenario específico de uso.

Reconfiguración de nombres

El primer paso del proceso consiste en reconfigurar los nombres de los servidores. Ambos servidores poseen sendos sistemas operativos CentOS 6.4. En el servidor Tomcat se debe cambiar el hostname, ya que ahora "www.pepe.org" debe resolver al front-end (proxy reverso):

# vi /etc/hosts
# hostname backend.pepe.org
# reboot

En el nuevo servidor front-end se debe cambiar el hostname a "www.pepe.org" de igual forma:

# vi /etc/hosts
# hostname www.pepe.org
# reboot

Instalación del servidor Apache

Partiendo de una instalación mínima de CentOS 6.4, el primer paso consiste en instalar el servidor apache:

# yum install httpd httpd-devel apr-util-devel

Luego se deben instalar algunas herramientas necesarias para compilar el módulo "mod_jk":

# yum install make autoconf libtool

Instalación del módulo mod_jk

El siguiente paso consiste en instalar y configurar el conector mod_jk. Descargar el conector Tomcat desde http://tomcat.apache.org/download-connectors.cgi:

# wget http://apache.xfree.com.ar//tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.37-src.tar.gz

Descomprimir el paquete mediante:

# tar xvf tomcat-connectors-1.2.37-src.tar.gz

Luego compilar el módulo:

# cd tomcat-connectors-1.2.37-src/native/
# ./buildconfig.sh
# ./configure --with-apxs=/usr/sbin/apxs
# make

Luego instalar el módulo. Simplemente se debe copiar el archivo *.so en el directorio donde Apache contiene sus módulos:

# cp apache-2.0/mod_jk.so /etc/httpd/modules/

Configuración de Apache

Luego de instalar el módulo "mod_jk" se deben configurar los hosts virtuales necesarios. En este caso se utilizan dos virtual hosts, el primero escucha en el puerto 443 (implementa HTTPS) y define la conexión con Tomcat utilizando el módulo "mod_jk". El segundo es el VirtualHost por defecto que escucha en el puerto 80 y redirecciona todo el tráfico a HTTPS.

Crear el directorio base para el sitio:

# mkdir /var/www/html/pepe.org

Crear un archivo index.html que redireccione al directorio/documento inicial de la aplicación. El contenido de este archivo depende de cada aplicación en particular, por ejemplo:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<meta http-equiv="Refresh" content="0; url=https://www.pepe.org/sitio/index.jsp">

</html>

Notar la redirección a HTTPS en la URL anterior.

Finalmente se debe cambiar el usuario para el directorio base y su contenido. En CentOS el usuario con el que corre Apache es "apache" (a diferencia de Debian y derivados donde el usuario es "www-data"):

# chown -R apache:apache /var/www/html/pepe.org
Configuración de SSL

El fundamento de este artículo se basa en forzar todo el tráfico de un servidor Tomcat a través de HTTPS para mejorar la confidencialidad, integridad y autenticidad de los datos que maneja. Por esta razón se implementa el proxy reverso mediante Apache conectado a Tomcat utilizando "mod_jk". El VirtualHost por defecto redirecciona todo el tráfico entrante al puerto 443 (HTTPS), por lo tanto el siguiente paso consiste en instalar y configurar "mod_ssl" para finalmente configurar la conexión AJP hacia el servidor Tomcat.

Instalar mod_ssl:

# yum install mod_ssl

Luego crear un directorio donde almacenar los certificados y clave privada:

# mkdir /etc/httpd/conf/ssl

Si no se posee un certificado, el artículo Cómo crear tu propia Autoridad Certificante (CA) explica cómo crear una autoridad certificante para expedir tus propios certificados autofirmados.

Para determinar su validez, es posible verificar los certificados (exportar en formato de texto plano) mediante el comando:

# openssl x509 -text -in server.crt

Para evitar conflictos de acceso a los certificados, es necesario deshabilitar SELinux (aún no le he dedicado tiempo para comprender su funcionamiento, shame on me...)

Editar el archivo "ssl.conf" el cual contiene la configuración del VirtualHost seguro (HTTPS):

# vi /etc/httpd/conf.d/ssl.conf
    # Parámetros del sitio
    ServerAdmin webmaster@pepe.org
    ServerName pepe.org
    ServerAlias *.pepe.org
    ErrorLog logs/pepe.org-error_log
    CustomLog logs/pepe.org-access_log common
    LogLevel warn

    # Directorio raíz del sitio
    DocumentRoot "/var/www/html/pepe.org"

    # Ruta a los certificados
    SSLCertificateKeyFile "/etc/httpd/conf/ssl/server.key"
    SSLCertificateChainFile "/etc/httpd/conf/ssl/server-ca.crt"
    SSLCertificateFile "/etc/httpd/conf/ssl/server.crt"

Configuración del firewall

Editar el archivo /etc/sysconfig/iptables:

# vi /etc/sysconfig/iptables

Agregar las líneas (donde corresponda, la posición afecta el funcionamiento):

    iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
    iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT

Reiniciar el firewall:

# service iptables restart
Configuración del conector mod_jk

Luego de verificar que la conexión HTTPS funcione correctamente es necesario implementar el conector. Editar el archivo /etc/httpd/conf.d/ssl.conf:

# vi /etc/httpd/conf.d/ssl.conf

Antes de la definición del VirtualHost se debe agregar la configuración mínima para que el módulo "mod_jk" funcione:

    # Carga del módulo
    LoadModule jk_module /etc/httpd/modules/mod_jk.so

    # Ruta al archivo "workers.properties"
    JkWorkersFile /etc/httpd/conf/workers.properties

    # Ruta a la memoria compartida jk
    JkShmFile /var/log/httpd/mod_jk.shm

    # Archivo de log
    JkLogFile /var/log/httpd/mod_jk.log

    # Nivel de log, puede ser "debug", "error" o "info":
    JkLogLevel debug

    # Formato de estampillas de tiempo
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "

NOTA: el archivo workers.properties se define más adelante, es conveniente guardarlo en el mismo directorio donde se encuentra el archivo httpd.conf

Configuración del VirtualHost

Dentro del VirtualHost es necesario mapear al menos un espacio de nombres a un worker. Los workers representan instancias de Tomcat que están escuchando pedidos. Estos se configuran en el archivo workers.properties (en la siguiente sección). El mapeo se realiza mediante la instrucción JkMount (es posible utilizar múltiples instrucciones JkMount simultáneamente).

En la siguiente sección se definen los workers "workerpepe", el cual sirve pedidos correspondientes al sitio ficticio "pepe", y "jk-status", el cual sirve pedidos de estado de Tomcat (útil para ver la carga del servidor Tomcat).

A modo de ejemplo, y tal como se mostró en el contenido del archivo "index.html", se supone que el sitio ficticio "pepe" se encuentra en la URL base /pepe del servidor Tomcat.

En la configuración del VirtualHost seguro agregar las siguientes líneas:

    JkMount /sitio workerpepe
    JkMount /sitio/* workerpepe
    
    JkMount /status jk-status
    JkMount /status/* jk-status

Configuración de Workers

Copiar el archivo de ejemplo desde el directorio donde se compiló el módulo "mod_jk":

# cp tomcat-connectors-1.2.37-src/conf/workers.properties.minimal /etc/httpd/conf/workers.properties

Editar el archivo workers.properties:

# vi workers.properties

Configurar los workers "workerpepe" y "jk-status":

    worker.list=workerpepe,jk-status
    
    worker.workerpepe.type=ajp13
    worker.workerpepe.host=backend.pepe.org
    worker.workerpepe.port=8009
    
    worker.jk-status.type=status

Para testear la conexión, reiniciar Apache y navegar hasta la URL base del sitio "pepe":

# service apache restart

Desde un Web browser cliente acceder a la dirección http://www.pepe.org

Debería funcionar perfectamente!



Suscribirse

    Registrate para recibir las novedades y artículos por correo electrónico.

Linuxito en G+