How to encrypt the connection between Apache mod_proxy or mod_cluster and EAP 4 or 5 with SSL
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 4
- 5
- Red Hat JBoss Enterprise Web Server (EWS)
- 1.0.x
- Apache
- 2.2
- mod_proxy
- mod_cluster
Issue
- How do I encrypt the connection between Apache
mod_proxyormod_clusterand JBoss withSSL? - How do I forward
SSLenvironment information inmod_proxyormod_cluster when usingHTTPS? - I need a suggestion for HTTPS-based
mod_clusterbetween Apache HTTPD and JBoss EAP server. Currently, we are usingAJP. If we need to useHTTPS, then what are the changes required? - I request you to provide the steps to configure
SSLbetween the web server and JBoss EAP 5.2.
Resolution
Disclaimer: Links contained herein to external website(s) are provided for convenience only. Red Hat has not reviewed the links and is not responsible for the content or its availability. The inclusion of any link to an external website does not imply endorsement by Red Hat of the website or their entities, products or services. You agree that Red Hat is not responsible or liable for any loss or expenses that may result due to your use of (or reliance on) the external site or content.
First and foremost, the recommended solution, if you are using the EAP 5, is to use mod_cluster which is the successor to mod_proxy and as a much cleaner ability to encrypt the connection. See: Content from docs.jboss.org is not included.Using SSL in mod_cluster for instructions on using SSL with mod_cluster to encrypt the connection between Apache HTTPD and JBossWeb.
mod_proxy
Encrypting the connection between HTTPD and JBoss Web using mod_proxy
In httpd.conf you need something like:
SSLProxyEngine On
SSLProxyVerify require
SSLProxyCACertificateFile conf/cacert.pem
SSLProxyMachineCertificateFile conf/proxy.pem
ProxyPass / https://127.0.0.1:8443/
ProxyPassReverse / https://127.0.0.1:8443/
Note: conf/cacert.pem must contain the CA that signed the Tomcat certificate.
Note: conf/proxy.pem should contain both key and certificate (and the certificate must be trusted by Tomcat).
Note: The ProxyPass, etc. configuration for HTTPS connections should be defined inside the SSL VirtualHost in Apache. This is how Apache knows to send the requests from HTTPS on port 443 to the HTTPS port on EAP.
Red Hat Enterprise Linux (RHEL)
When running in RHEL there are default localhost certs already on the operating system that can be used to quickly get an SSL setup up and running. The certs should be generated for a production machine, but the default certs are good for testing purposes. A full setup for this is the following:
- Make sure you have Apache and Tomcat installed from the JBoss Enterprise Web Server channel. You will need to subscribe to that channel in RHN for your sytem.
yum -y install httpd
yum -y install httpd-devel
yum -y install openssl
yum -y install tomcat6*
service httpd restart
- Open your browser and hit http://localhost/ Make sure in httpd.conf that you are Listening on the right ip, ex. Listen 127.0.0.1:80
- Setup SSL between Apache and JBoss with mod_proxy
SSLProxyEngine On
ProxyPass / https://127.0.0.1:8443/
ProxyPassReverse / https://127.0.0.1:8443/
- In
/etc/tomcat6/server.xmluncomment the 8443 connector and change it to:
<Connector port="8443" maxHttpHeaderSize="8192"
maxThreads="150"
protocol="org.apache.coyote.http11.Http11AprProtocol"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
SSLEnabled="true"
SSLCertificateFile="/etc/pki/tls/certs/localhost.crt"
SSLCertificateKeyFile="/etc/pki/tls/private/localhost.key" />
- If you get the following in your catalina.out or tomcat.log in
/var/log/tomcat6:
java.lang.Exception: Unable to load certificate key /etc/pki/tls/private/localhost.key (error:0200100D:system library:fopen:Permission denied)
- Make sure that
localhost.keyandlocalhost.crtare readable by Tomcat:
chmod 644 /etc/pki/tls/certs/localhost.crt
chmod 644 /etc/pki/tls/private/localhost.key
- Now both Apache and Tomcat should be using SSL you can hit https://localhost/ to verify, you should get the Tomcat page.
Forwarding the SSL environment information to JBoss Web
The variables supported by the servlet interface are the following
- javax.servlet.request.X509Certificate
- javax.servlet.request.cipher_suite
- javax.servlet.request.ssl_session
- javax.servlet.request.key_size
To get the client certificate or any SSL information from the broswer you have to use mod_header to add the SSL information to header. To do that add in httpd.conf of Apache HTTPD the following:
RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
RequestHeader set SSL_CIPHER "%{SSL_CIPHER}s"
RequestHeader set SSL_SESSION_ID "%{SSL_SESSION_ID}s"
RequestHeader set SSL_CIPHER_USEKEYSIZE "%{SSL_CIPHER_USEKEYSIZE}s"
EAP5: Then you need a valve in Tomcat to extract the information from the request Headers. Add: <className="SSLValve"/> to the <Engine/> part of the server.xml
Note: The Fedora version of Java6 does not have EC ciphers
Note: There is a known issue with mod_proxy_ssl + NIO + the Cisco PIX hardware firewall, the workaround is to use JBoss or TC Native and avoid NIO
mod_cluster
Encrypting the connection between httpd and JBoss Web using mod_cluster
If using SSL between mod_cluster and JBoss, take note of SSL Proxy connect failed and mod_cluster returns "Bad Gateway" HTTP ErrorCode 502. If load drops and connections idle, they can go into a bad state from SSL handshake timeouts to cause 502s. This will be fixed in a later release but can be worked around by disabling connection keepalive and reuse between Apache/JBoss and/or increasing JBoss's HTTP connectionTimeout.
The relevant pieces of the configuration for SSL configuration with mod_cluster are as follows:
mod-cluster.conf:
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
#Be a client to another server and use ssl to connect to it
SSLProxyEngine On
SSLProxyVerify require
SSLProxyCACertificateFile conf/cacert.pem
SSLProxyMachineCertificateFile conf/proxy.pem
Listen 127.0.0.1:6666
<VirtualHost 127.0.0.1:6666>
# Be a server for mod_cluster in JBoss
SSLEngine on
SSLCipherSuite AES128-SHA:ALL:!ADH:!LOW:!MD5:!SSLV2:!NULL
SSLCertificateFile conf/server.crt
SSLCertificateKeyFile conf/server.key
SSLCACertificateFile conf/server-ca.crt
# If just testing can comment out the below (not secure)
SSLVerifyClient require
SSLVerifyDepth 10
<Directory />
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Directory>
KeepAliveTimeout 60
MaxKeepAliveRequests 0
ManagerBalancerName mycluster
AdvertiseFrequency 5
</VirtualHost>
<Location /mod_cluster-manager>
SetHandler mod_cluster-manager
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
In $JBOSS\_HOME/server/$PROFILE/deploy/mod_cluster.sar/META-INF/mod-cluster-jboss-beans.xml modify the ModClusterServiced being used, either ModClusterService or HAModClusterService:
<bean name="ModClusterService" class="org.jboss.modcluster.ModClusterService" mode="On Demand">
...
<property name="ssl">true</property>
<property name="sslKeyStorePass">test</property>
<property name="sslKeyStore">/home/smendenh/sandbox/CERTS/Client/test.p12</property>
<property name="sslKeyStoreType">pkcs12</property>
<property name="sslTrustStore">/home/smendenh/sandbox/CERTS/ca.p12</property>
<property name="sslTrustStoreType">pkcs12</property>
<property name="sslTrustStorePassword">test</property>
...
</beans>
$JBOSS_HOME/server/$PROFILE/deploy/$JBOSSWEB/server.xml:
<Server>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.jboss.web.tomcat.service.deployers.MicrocontainerIntegrationLifecycleListener" delegateBeanName="ModClusterService" />
<Service name="jboss.web">
<!-- Currently for mod_cluster to only use 8443 for communication port 8080 and 8009 must be commented out -->
<!--
<Connector protocol="HTTP/1.1" port="8080" address="${jboss.bind.address}" connectionTimeout="20000" redirectPort="8443" />
-->
<!--
<Connector protocol="AJP/1.3" port="8009" address="${jboss.bind.address}" redirectPort="8443" />
-->
<Connector port="8443"
protocol="HTTP/1.1"
SSLEnabled="true"
truststoreFile="/etc/pki/java/cacerts"
truststorePass="changeit"
truststoreType="JKS"
keystoreType="PKCS12"
keystoreFile="/home/smendenh/sandbox/CERTS/Client/test.p12"
keystorePass="test"
maxThreads="150"
scheme="https"
secure="true"
clientAuth="true"
sslProtocol="TLS" />
<Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1">
<Realm className="org.jboss.web.tomcat.security.JBossWebRealm"
certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
allRolesMode="authOnly"
/>
<Host name="localhost">
<Valve className="org.jboss.web.tomcat.service.jca.CachedConnectionValve"
cachedConnectionManagerObjectName="jboss.jca:service=CachedConnectionManager"
transactionManagerObjectName="jboss:service=TransactionManager" />
</Host>
</Engine>
</Service>
</Server>
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.