Páginas

miércoles, 22 de mayo de 2013

Balanceo de carga y SSL con Apache y Tomcat

Introducción

Vamos a configurar un servidor Apache para servir una aplicación web desplegada en varias instancias Tomcat balanceando la carga de trabajo entre los servidores. Supondremos además que el acceso a la aplicacionón se realiza a través del protocolo https.

La comunicación entre el servidor web Apache y los distintos Tomcat se realiza usando el protocolo AJP.

El usuario accederá a la url https://servidor.org/app-web/ eligirá un certificado de acceso, establecerá sesión ssl con el servidor y Apacheredirigirá la petición a alguno de los Tomcat balanceados.

Una vez establecida la sesión de trabajo con un cierto Tomcat, Apache mantendrá las restantes peticiones del usuario en ese mismo Tomcat.

Instalación y configuración de los servidores Tomcat

El primer paso para realizar la configuración consiste en instalar y configurar varias instancias del servidor Tomcat. Para ello descargamos Tomcat (por ejemplo la versión apache-tomcat-6.0.35.zip) y lo descomprimimos en tantas carpetas distintas como deseemos. Una vez instalados debemos hacer una serie de cambios en la configuración de todos ellos.

Cambiar la variable CATALINA_HOME

Debemos cambiar la variable CATALINA_HOME de cada uno de los Tomcat para que apunte a la carpeta en la que está instalado. Para ello editamos el fichero bin/catalina.sh y en la primera línea escribimos:

 CATALINA_HOME=/home/egdepedro/balanceo/apache-tomcat-6.0.35-00

Cambiando la carpeta por la correspondiente en cada uno de ellos.

Configurar el puerto del servidor

Debemos configurar los Tomcat para que usen puertos distintos y no den errores en el arranque. En el archivo conf/server.xml debemos cambiar el puerto indicado en la línea:

<Server port="8005" shutdown="SHUTDOWN">

Usando distintos puertos en cada instancia. Por ejemplo 8005, 8006, 8007...

Configurar los conectores AJP

En el mismo fichero conf/server.xml debemos buscar la siguiente línea:

<Connector port="10009" protocol="AJP/1.3" redirectPort="8443" />

Y del mismo modo usar distintos puertos en cada instancia 10009, 10109, 10209...

Deshabilitar el conector HTTP

Este paso es opcional. Si lo deseamos podemos eliminar la configuración para los conectores HTTP borrando la siguiente línea del fichero conf/server.xml:

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

De este modo la única forma de acceder al servidor es a través del conector AJP. Si deseamos seguir manteniendo el acceso por HTTP debemos asegurarnos de usar puertos distintos en cada instancia.

Configurar la ruta jvmRoute

Por último debemos indicar una jvmRoute a cada instancia para que sea accesible por el servidor Apache. Este nombre ha de ser único por cada Tomcat y será el que se use en la configuración de Apache. En el fichero conf/server.xml buscamos y modificamos la linea:

<Engine name="Catalina" defaultHost="localhost" jvmRoute="00">

Por último desplegamos las aplicaciones que queremos balancear y arrancamos todas las instancias de Tomcat asegurándonos de que arranquen sin errores.

Configuración del balanceador (mod_jk)

El primer paso para configurar el balanceo de carga es habilitar el módulo de apache encargado de ello. Para ello en el fichero httpd.conf debemos incluir la siguiente línea en la zona de carga de módulos

LoadModule jk_module modules/mod_jk.so

Ahora debemos configurar el módulo. Para ello pondremos la configuración en un fichero aparte que incluiremos de la siguiente forma

include /opt/apache/conf/extra/httpd-jk.conf

Fichero httpd-jk.conf

<IfModule jk_module>

  JkWorkersFile /opt/apache/conf/workers.properties
  JkShmFile /opt/apache/logs/jk.shm

  JkLogFile logs/mod_jk.log
  JkLogLevel info
  JkLogStampFormat  "[%a %b %d %H:%M:%S %Y] "
  # JkRequestLogFormat
  JkRequestLogFormat "%w %V %T"

  # JkOptions indicates to send SSK KEY SIZE
  JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
              
  # You can use external file for mount points.
  # It will be checked for updates each 60 seconds.
  # The format of the file is: /url=worker
  JkMountFile conf/uriworkermap.properties

  # Add jkstatus for managing runtime data
  <Location /jkmanager/>
    JkMount jkstatus
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
  </Location>

  # Should mod_jk send SSL information to Tomcat (default is On)
  JkExtractSSL On
  # What is the indicator for SSL (default is HTTPS)
  JkHTTPSIndicator HTTPS
  # What is the indicator for SSL session (default is SSL_SESSION_ID)
  JkSESSIONIndicator SSL_SESSION_ID
  # What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
  JkCIPHERIndicator SSL_CIPHER
  # What is the indicator for the client SSL certificated (default is SSL_CLIENT_CERT)
  JkCERTSIndicator SSL_CLIENT_CERT
</IfModule>

Lo más interesante de este fichero son las líneas donde se configura JkWorkersFile para poner el fichero donde se indican las distintas instancias de Tomcat configuradas. Otra configuración importante es la que se indica JkMountFile. En este fichero configuraremos las url que queramos mapear al balanceador. Las últimas líneas son interesantes para cuando configuremos el SSL.

Fichero workers.properties

worker.list=jkstatus,lb

worker.00.host=localhost
worker.00.port=10009
worker.00.type=ajp13
worker.00.fail_on_status=-404,500,503

worker.01.host=localhost
worker.01.port=10109
worker.01.type=ajp13
worker.01.fail_on_status=-404,500,503

worker.lb.type=lb
worker.lb.balance_workers=00,01
worker.lb.sticky_session=true
worker.lb.method=B

worker.jkstatus.type=status

En este fichero se configura la lista de workers. En la primera línea indicamos que vamos a usar el worker jkstatus, útil para acceder a la configuración del módulo desde un navegador, y el worker lb que es realmente el balanceador.

Después configuramos los worker correspondientes a cada uno de los tomcat. En este punto es muy importante nombrar a cada uno de ellos de la misma forma que los nombramos mediante el parámetro jvmRoute en sus ficheros server.xml. Esta será la forma en que el balanceador sepa la forma de redirigir las peticiones a cada uno de los tomcat. Además indicamos el host, el puerto AJP, el tipo de worker y los errores que queremos que se propaguen al apache. Si no indicamos la línea fail_on_status apache irá saltando de tomcat en tomcat cuando las instancias devuelvan errores.

Posteriormente configuramos el worker lb indicando su tipo, los worker ajp asociados, el método de balanceo y la propiedad sticky_session. Esta propiedad se usa para indicar al balanceador que mantenga cada sesión de usuario en el mismo tomcat en el que se lanzó inicialmente. Para aplicaciones web que mantienen datos en sesión esta es la forma de mantenerlos.

Por último se configura el worker jkstatus para proporcionar información acerca del módulo.

Fichero uriworkermap.properties

/jkstatus/*=jkstatus
/app-web/*=lb

En este fichero indicamos que las peticiones a jkstatus sean atendidas por el worker apropiado y las peticiones a app-web (nuestra aplicación balanceada) sean atendidas por el balanceador de carga.

Configuración de SSL

Debemos activar el módulo SSL del mismo modo que activamos el módulo jk. Incluimos las siguientes líneas en la zona de carga de módulos del fichero httpd.conf:

LoadModule ssl_module modules/mod_ssl.so

En caso de que no se encuentre cargado también debemos activar el módulo headers para la gestión de las cabeceras de las peticiones:

LoadModule headers_module modules/mod_headers.so

Ahora debemos configurar el módulo. Para ello pondremos la configuración en un fichero aparte que incluiremos de la siguiente forma

Include /opt/apache/conf/extra/httpd-ssl.conf

Fichero httpd-ssl.conf

En este fichero dejamos todos los valores por defecto salvo las siguientes líneas que incluiremos al final:

Include conf/extra/proxypass.conf
Include conf/extra/proxypass/*.conf

Fichero proxypass.conf

En el fichero proxypass.conf configuramos las opciones generales para https

#Parametros SSL
SSLEngine on
SSLCertificateFile    /opt/apache/conf/server.crt
SSLCertificateKeyFile /opt/apache/conf/server.key
SSLCACertificateFile  /opt/apache/conf/certificadosCA.crt
SSLVerifyClient none
SSLVerifyDepth 2
SSLOptions +ExportCertData
SSLInsecureRenegotiation on
#SSLOptions +ExportCertData +OptRenegotiate

#Inicializo cabeceras
RequestHeader set SSL_CLIENT_S_DN ""
RequestHeader set SSL-CLIENTCERT-PEM ""
RequestHeader set SSL_CLIENT_VERIFY ""
RequestHeader set SSL_CLIENT_CERT_CHAIN_0 ""

Las opciones más interesantes son SSLCertificateFile que indicará el fichero con el certificado del servidor, SSLCertificateKeyFile que indica el fichero con la clave privada del servidor y SSLCACertificateFile que referencia al fichero con los certificados de los clientes (o los de sus CA's) en los que confiemos.

Fichero proxypass/app-web.conf

En este fichero incluiremos las opciones específicas de configuración de SSL para cada aplicación. En nuestro caso estamos configurando la aplicación app-web

<Location /app-web/* >
 #Cabeceras con ssl-clientcert-pem
 SSLVerifyClient require
 RequestHeader set SSL_CLIENT_S_DN "%{SSL_CLIENT_S_DN}s"
 RequestHeader set SSL-CLIENTCERT-PEM "%{SSL_CLIENT_CERT}s"
 RequestHeader set SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}s"
 RequestHeader set SSL_CLIENT_CERT_CHAIN_0 "%{SSL_CLIENT_CERT_CHAIN_0}s"
 JkMount lb
 SSLRenegBufferSize 1000000000
</Location>

Lo más interesante de este fichero es la línea JkMount lb que indica el montaje del balanceador de carga para atender a las peticiones en la url /app-web/* por protocolo seguro. Además indicamos que para estas peticiones requerimos certificado de cliente mediante la línea SSLVerifyClient require.

No hay comentarios:

Publicar un comentario