Buscar este blog

sábado, 17 de enero de 2015

JBoss, Apache mod-cluster - Configure SSL to read client certificates

Update:
Tras un tiempo trabajando con este tipo de configuración he visto que no es la más adecuada. He creado una nueva entrada donde se especifica un mejor solución. Se puede consultar aquí: http://trabajosdesisifo.blogspot.com.es/2015/04/jboss-modcluster-ssl-windows.html




El objetivo es conectar un Servidor Apache con un Servidor JBOSS formando un cluster de un único nodo en alta disponibilidad (HA), y que JBOSS pueda leer los certificados de los usuarios para así, eventualmente autenticarlos y autorizarlos.

Apache leerá el certificado del cliente y se lo enviará al cluster dentro de una cabecera de la request.
JBOSS funcionará en el puerto 8080, pero los usuarios se conectarán primero a Apache en el puerto 8888, que será el que valide que es válido (simplemente ver que es correcto y que no está caducado, no se incluyen validaciones contra listas de revocación o demás) y se lo pase al servidor que compone el cluster.

Se hará una prueba con una aplicación que lea el certificado de usuario directamente de la request y en un Controller. En una aplicación real esto lo debería hacer un filtro de autenticación.


Se usará siempre configuración por defecto, pero para una aplicación más compleja podrá requerir un ajuste más fino, por ejemplo, cambiando el protocolo de conexión de ajp a http, o definiendo un proxy para concentrar los mensajes multicast, etc.

Materiales y herramientas
Se emplearán los siguientes sistemas:
  • Apache 2.2 - openssl
  • Apache mod_cluster 1.2.0 Final
  • JBOSS EAP 6.2 (Jboss AS 7.3)
    • Se usará el perfil standalone de alta disponibilidad.
    • Certificados válidos
    • Herramienta para manejar certificados. Recomiendo keystoreExplorer.
Configuración Apache
El tutorial está hecho con Apache 2.2.17 SSL, pero también valdría cualquier revisión posterior.
La versión actual se puede descargar de http://ftp.cixug.es/apache//httpd/binaries/win32/, pero teniendo cuidado de escoger el empaquetado con openssl, ya que se necesitan esos módulos para configurar el https.
Instalación de mod_cluster
Teniendo instalado Apache, el siguiente paso es añadirle una serie de módulos para el mod_cluster. Estos módulos se obtendrá de otra distribución de Apache que se obtiene de la propia página del proyecto: http://mod-cluster.jboss.org/downloads/1-2-6-Final-bin
Habrá que bajar el paquete con los binarios, en este caso para windows-x86.
Se trata de un Apache en sí mismo, aunque sin los ficheros de configuración. La opción más sencilla es coger los módulos que se necesitan y copiarlos directamente al otro apache que ya se tiene funcionando.
Los módulos están en el directorio raíz de la descarga (httpd-2.2), en la carpeta modules. Se necesitan los siguientes:
  • mod_proxy.so
  • mod_proxy_ajp.so
  • mod_proxy_http.so
  • mod_slotmem.so
  • mod_manager.so
  • mod_proxy_cluster.so
  • mod_advertise.so
Los tres primeros ya se tienen en el otro Apache, pero no está de más sobreescribirlos para asegurarse de que son compatibles entre sí.
Basta con copiar/sobreescribir esos siete módulos del Apache mod_cluster al Apache instalado, también al directorio de módulos. Por defecto estará en C:\Program Files (x86)\Apache Software Foundation\Apache2.2\modules
Ahora ya nos podemos olvidar del apache mod_cluster y centrarnos en el principal.
En el directorio $APACHE$/conf, editar el archivo httpd.conf y añadir (o descomentar) las siguientes líneas al comienzo (es la zona donde se cargan los módulos):

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule slotmem_module modules/mod_slotmem.so
LoadModule manager_module modules/mod_manager.so
LoadModule proxy_cluster_module modules/mod_proxy_cluster.so
LoadModule advertise_module modules/mod_advertise.so
Ejecutar el comando $APACHE$/bin/httpd -M para ver que carga bien esos módulos.
Configuración del HTTPS
La configuración de HTTPS en Apache está explicada en la siguiente receta: Configurar SSL APACHE con certificados de prueba
Básicamente, lo que se necesita es lo siguiente:
  • Fichero con la clave pública del servidor
  • Fichero con la clave privada del servidor
  • Fichero con la lista de CAs en las que confía el servidor
  • Fichero con la configuración general del ssl (ss.conf)
  • Cargar dos nuevos módulos:
    • mod_ssl.so
    • mod_headers.so
mod_headers no se necesita para el SSL, pero sí que se utilizará en este caso para enviar el certificado del usuario dentro de un campo de la cabecera de la request.
Estos dos módulos ya están incluidos en la distribución de Apache (openssl) así que basta con descomentarlos y ver que se cargan bien.
Configuración del virtual host
Se creará un virtual host indicando la dirección y puerto al que se conectarán los usuarios.
En el virtual host se definirá lo siguiente:
  • Activar la conexión por HTTPS
  • Crear un handler para ver información de mod_cluster
  • Crear un handler para que pida certificado al contactar con una aplicación del servidor
  • Configurar los parámetros de autodescubrimiento del cluster
La configuración completa es la siguiente:

Listen 8888
<VirtualHost localhost:8888>
    #Establecer https para todo el virtual host
    Include conf/ssl.conf
    ErrorLog  logs/ssl_cluster_error.log   
    CustomLog logs/ssl_cluster_custom.log  "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{SSL_CLIENT_VERIFY}x %{SSL_SERVER_I_DN}x \"%r\" %b"
     
<Directory />
        Options FollowSymLinks
        AllowOverride None
        Order deny,allow
        Allow from all
    </Directory>
 
    #Consulta de información del cluster yendo a URL https://localhost:8888/mod_cluster-manager
    <Location /mod_cluster-manager>
        #Mostrar información extra en la página del manager
        AllowDisplay on
        SetHandler mod_cluster-manager
    </Location>
 
    #Handler específico para esta aplicación. Todo lo que vaya por ahí necesitará certificado
    <location /certificadoApp>
        SSLVerifyClient require
        SSLVerifyDepth  2
        #El certificado del cliente se envía al servidor en el header de la request, dentro del parámetro "X-ClientCert"
        RequestHeader set X-ClientCert %{SSL_CLIENT_CERT}s
    </location>
 
    #Configuración para descubir y establecer el cluster
    KeepAliveTimeout 60
    MaxKeepAliveRequests 0
    ManagerBalancerName mycluster
    AdvertiseFrequency 5
    EnableMCPMReceive
</VirtualHost>
En este caso el virtual host estará asociado a la dirección localhost:8888.
Mediante la instrucción Include conf/ssl.conf lo que se hace es importar el fichero ssl.conf (uno de los nombrados anteriormente al hablar de la configuración del https). Es como copiar ese contenido ahí.

El location /mod_cluster-manager sirve para definir el contexto en el que se mostrará información del cluster. Es un aplicación incrustada dentro del propio mod_cluster y que así se hace accesible desde la url https://localhost:8888/mod_cluster-manager.

El location /certificadoApp se refiere a una de las aplicaciones que va a servir el cluster JBOSS, y que requiere un tratamiento especial. En este caso la particularidad es que va a obligar a que el usuario introduzca un certificado digital.

No hay que confundir la activación de HTTPS con la solicitud de certificado. En el primer caso simplemente se establece un SSL ONE WAY (tiene certificado el servidor) mientras que para esa aplicación se quiere que el usuario también aporte su certificado, SSL TWO WAY.
También se está encapsulando ese certificado dentro del parámetro X-ClientCert del header de la request. Esto servirá para que luego, el servidor pueda recuperarlo y autenticar al usuario.
Por último se añaden todas las directivas para activar la configuración del cluster.
Para probar que por el momento todo va bien, basta con arrancar Apache y comprobar la url del cluster. Debería salir algo así:

Configuración de JBOSS
Como es un ejemplo básico, la configuración se hará en standalone, si bien es aplicable también a un dominio, que es precisamente el escenario de trabajo más habitual. En este caso se hará un cluster de un único nodo.
Los pasos a seguir son:
  1. Preparar los keystore de certificados de confianza
  2. Preparar keystore de certificados de servidor
  3. Configurar el cluster
Se necesitan dos keystores (aunque con uno sólo también bastaría, creo que queda más claro tenerlo separados).

Preparar los keystore de certificados de confianza
Se va a crear un keystore jboss-trustStore.jks con la lista de los certificados en los que confiará JBOSS. En este caso sólo se necesita uno, que es el del Apache.
Se exporta el certificado del servidor y se mete en un keystore importándolo como certificado de confianza.

Para sacar el certificado del servidor se puede hacer directamente desde el navegador. Al pulsar sobre el icono de conexión cifrada en la barra de navegación se da la opción de ver los detalles del certificado y exportarlo a un archivo crt.


Con el keystoreExplorer se crea un nuevo keystore de tipo JKS y se inserta este certificado como de confianza.



Al final se tendrá algo como esto:

Al guardar el archivo va a pedir que se introduzca una password. Ésta deberá ser la misma que el próximo keystore (cosas de JBOSS...)

Se guarda el fichero como jboss-trustStore.jks, con la password jboss.

Preparar keystore de certificados de servidor
Ahora hay que crear un par de claves propias del JBOSS, y meterlas también en un keystore.
Con el keystoreExplorer se vuelve a crear un keystore de tipo JKS y se pulsa sobre la opción de generar nuevo par de claves, se cubren los datos y se introduce el alias y la password del certificado.


Se ponen los siguientes datos:
  • Alias del certificado: jboss-alias
  • Password del certificado: jboss
  • Password del keystore: jboss
Se guarda el fichero en jboss.jks

Configurar el servidor
De los perfiles de standalone, se utilizará standalone-ha (alta disponibilidad), ya que es el que trae preconfigurado el mod_cluster.
Por defecto, al arrancar JBOSS se inicia con el fichero de configuración standalone.xml. Para cambiarlo hay que indicarle cuál debe usar. Abrir una ventana de comandos en la carpeta bin del servidor y escribir:
  • standalone.bat -c standalone-ha.xml
Desde eclipse también se puede configurar. A la hora de crear el runtime enviorement de JBOSS se le puede especificar el fichero de configuración que debe usar. Así, al crear y arrancar el server ya siempre usa ese.
Una vez arrancado, se accede a la consola de administración web en http://localhost:9990/Se utilizará la consola web en vez de tocar el fichero xml a mano, porque es la forma más segura, y así también vale para configuraciones en dominio.
En la consola, ir a Profile > System Properties y añadir las siguientes variables:
  • key: javax.net.ssl.trustStore - value: [ruta absoluta a jboss-trustStore.jks]
  • key: javax.net.ssl.trustStorePassword - value=jboss
Se pone la ruta del trustStore que se creó anteriormente, y se le pone otra clave para su password.

Ahora hay que configurar los datos del cluster.
Dentro de Profile > Web > mod_cluster > SSL se añaden las siguientes variables:
  • key Alias: jboss-alias
  • Password: jboss
  • key File: [ruta absoluta a jboss.jks]
  • Cipher Suite: ALL
  • Protocol: TLSv1

Ahora hay que reiniciar el servidor.
El resto de parámetros quedan por defecto, o no es necesario indicarlos porque ya están preeacordados entre Apache y JBOSS
  • IP Multicast: 224.0.1.105
  • Puerto Multicast: 23364
  • Nombre del balanceador: mycluster

Aplicación de pruebas
Se hace una aplicación Spring-mvc muy sencilla con un único controller que lea el certificado de la request y lo pinte en una JSP.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RequestMapping(method = RequestMethod.GET)
public ModelAndView prueba(HttpServletRequest request) {
    //Certificate certificado = null;
    X509Certificate certificado = null;
    //Recuperar el certificado de la cabecera
    String xClientCert = request.getHeader("x-clientcert");
    if (StringUtils.isEmpty(xClientCert)) {
        return crearVistaError("No existe certificado en la cabecera 'x-clientcert'");
    }
 
    //Quitarle el separador de comienzo y fin
    String base64Certificate = xClientCert.replaceAll("-----BEGIN CERTIFICATE-----", "").replaceAll("-----END CERTIFICATE-----", "");
    Base64 b64 = new Base64();
    byte [] decoded = b64.decode(base64Certificate);
    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        certificado = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decoded));
    }
    catch(Exception e) {
        e.printStackTrace();
        return crearVistaError("Error al parsear el certificado: " + e.getMessage());
    }
    return crearVista(xClientCert, certificado);
}

Probar todo
Se parte de Apache y JBOSS parados. Y se inician primero JBOSS y luego Apache.
Al arrancar Apache debería aparecer el siguiente mensaje en la consola de JBOSS:

Se muestra un mensaje de mod_cluster indicando que ya se enchufó automáticamente con Apache por medio de las llamadas multicast. Aquí se hace un proceso de autodescubrimiento, lo que es muy útil al trabajar en dominio e ir quitando o añadiendo nodos.

Por otro lado, en Apache, al acceder a la URL del manager de mod_cluster se tendrá que ver algo así:


Con esto ya sabemos que se estableción conexión por las dos partes.

Ahora se puede desplegar un war de pruebas en JBOSS y llamarlo a través del proxy. En vez de ir a http://localhost:8080/certificadoApp, que es la dirección de JBOSS, se irá a https://localhost:8888/certificadoApp.

Si todo ha ido bien, al entrar en la página, primero Apache va a pedir un certificado válido, lo validará, y se luego redireccionará a JBOSS metiendo ese certificado en la request. JBOSS lo leerá y lo pintará en una JSP.


Además, si se vuelve a entrar en el manager del mod_cluster de Apache, se puede ver que ya ha registrado esa aplicación.

No hay comentarios:

Publicar un comentario