Sunday, September 9, 2012

SSL Offloading with mod_jk part 6

Document  Version 1.0
   Copyright © 2012-2013 beijing.beijing.012@gmail.com

Keywords:
SSLOffloading SSL-Offloading, SSL Termination, Apache, Tomcat, mod_jk configuration, multiple vhosts, multiple SSL certificates one ip



Configure Tomcat to accept SSL handling of mod_jk


We will now configure "SSL Termination" for "TestWebSec20" application.
We need to: 

1. Generate a self-signed SSL certificate.
   This includes creating a ".key" file, a ".csr" file and ".crt file".
2. Configure Apache virtual host i.e. host "ahaha.com" to use SSL
3. Configure Tomcat to accept SSL handling of Apache and mod_jk.


6.1 Generate a self-signed SSL certificate

The following link is the best Tutorial I have ever found for creating self-signed SSL certificate:
http://www.akadia.com/services/ssh_test_certificate.html

Please follow the link to create 3 files in following folders:
  • "/etc/apache2/ssl.key/ahaha.com.key", here "ahaha.com.key" is the key file name. 
  • "/etc/apache2/ssl.csr/ahaha.com.csr",  here "ahaha.com.csr" is the csr file name.
"/etc/apache2/ssl.crt/ahaha.com.crt",   here "ahaha.com.crt" is the crt file name.

6.2 Configure Apache virtual host for SSL

Configure Apache virtual host for "ahaha.com" to use SSL.
Add a "vhost-ssl.conf" file to Apache's "vhost.d" folder, and add following content to the file:


####START vhost-ssl.conf
NameVirtualHost *:443
<IfDefine SSL>
<IfDefine !NOSSL>

<VirtualHost *:443>
#  General setup for the virtual host
DocumentRoot "/srv/www/vhosts/ahaha.com"
ServerName www.ahaha.com
#ServerAdmin webmaster@example.com
ErrorLog /var/log/apache2/error_log
TransferLog /var/log/apache2/access_log

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
SSLEngine on

#  SSL protocols
#  Supporting TLS only is adequate nowadays
SSLProtocol all -SSLv2 -SSLv3

#   SSL Cipher Suite:
SSLCipherSuite ALL:!aNULL:!eNULL:!SSLv2:!LOW:!EXP:!MD5:@STRENGTH

#   Server Certificate:
SSLCertificateFile /etc/apache2/ssl.crt/ahaha.com.crt

#   Server Private Key:
SSLCertificateKeyFile /etc/apache2/ssl.key/ahaha.com.key

CustomLog /var/log/apache2/ssl_request_log   ssl_combined
       JkMountCopy On
       JkMount / worker1
       JkMount /* worker1

</VirtualHost>                                  

</IfDefine>
</IfDefine>
####END vhost-ssl.conf


With this vhost configuration for SSL, a SSL request to "ahahacom" will be first processed by mod_jk. mod_jk will take care of the SSL communication:

  •    providing client with the corresponding SSL certifiacte 
  •    do the SSL hand shake
  •   do encryption and decryption
  •   and forward it to Tomcat

The communication between mod_jk and Tomcat are in "plain" text,  NO SSL.  


6.3 Configure Tomcat  to accept SSL handling of mod_jk.

With the SSL configuration in "vhost-ssl.conf", mod_jk will take care of the SSL conmunication to browser, and forward client request to Tomcat. Tomcat need to be configured to believe the request from mod_jk is "secured".

Remembe in part5, we configured tomcat for a "ajp connector". 

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


To make Tomcat accept mod_jk SSL handling is easy, we just need to change the redirectPort of the above ajp connector to 433:


...
<Connector port="8009" protocol="AJP/1.3" redirectPort="443"/>
...


No restart Apache and Tomcat. Try accessing "secure/HalloSec" again:
http://ahaha.com/TestWebSec20/secure/HalloSec

Your browser will be redirected to HTPPS, and now the server certificate is shown  corectly, and SSL port is not shown any more:




part1 part2 part3 part4 part5

SSL Offloading with mod_jk part 5

Document  Version 1.0
  Copyright © 2012-2013 beijing.beijing.012@gmail.com

Keywords:
SSLOffloading SSL-Offloading, SSL Termination, Apache, Tomcat, mod_jk configuration, multiple vhosts, multiple SSL certificates one ip


SSL Port Problem

In part4 of this serial, we have successfully configured, a virtual host "ahaha.com", we have configured Apache and mod_jk, so that when a request comes form browser(clien), mod_jk will try to communicate this request to Tomcat. mod_jk talks "ajp language" to Tomcat. Now we need to configure Tomcat so that, he can also understand "ajp".
This could be accmplished by uncommenting following lines of "server.xml" of tomcat:



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


Now restart Tomcat and try accessing the "TestWebSec20"applicaiton again:
"http://www.ahaha.com/TestWebSec20/HalloNormal

And now you will see: 




Now you could access the "TestWebSec20" web applicaiton through a "real" domain name.
And you do NOT see the port 8080 in browser input any more!

Let's try accessing the secured resource, namly:
http://www.ahaha.com/TestWebSec20/secure/HalloSec

And you will see in you browser:


Cool! Isn't it?

The brower was redirected to HTTPS, and after confirmation of th SSL certificate, we see the protected resource!


But, wait a minute! There is still something wrong!
  • The  browser was redirected to HTTPS, but we see now another port numer 8443 (which is configured  for Tomcat https),  but we actually don't want to show users the port number in browser. We are expecting something like this
           https:///www.ahaha.com/TestWebSec20/secure/HalloSec
  • When we take a closer look at the SSL certificate details, we will see that the certificate here is the certificate of Tomcat, not the certificate of "www.ahaha.com".

To sum it up, we do NOT want to show the SSL port to brower; we want to show the user our "real" certificate that we created for domain "ahaha.com". 

To solve these two problems, we need to introduce a new "term", i.e. so called "SSL offload" or "SSL Termination". This is actually the main purpose of  the  "SSL Offloading with mod_jk" serial I am writing!


So what is SSLTermination / Offloading? 

SSL Termination is used take care of  everything about SSL in a centralized position in a system, at the border between secured and unsecured areas. "SSL Terminator" takes care of the SSL things between client and Servers, and all the traffic behinde "SSL Terminator" is not encrypted but thought to be secure.

To make it simple,  in our case we want apache / mod_jk to take care of the SSL handling, and by NOT Tomcat.


SSL Offloading with mod_jk part 6
part1 part2 part3 part4

SSL Offloading with mod_jk part 4

Document  Version 1.0
  Copyright © 2012-2013 beijing.beijing.012@gmail.com

Keywords:
SSLOffloading SSL-Offloading, SSL Termination, Apache, Tomcat, mod_jk configuration, multiple vhosts, multiple SSL certificates one ip



Fronting Tomcat with Apache and mod_jk

Now, we will  try to front Tomcat with Apache and mod_jk. The target OS is Linux -OpenSuse12.1. The procedure might be slightly different between different Linux systems.


4.1 Install Apache2

Normmally Apache2 is included in OpenSuse12.1 package. If Apache is installed , there will be an apache2 folder under "etc":
/etc/apache2/

When you can't find this folder, just try to install Apache2 and mod_jk with "Yast".
After installation, start apache2:


#  cd /etc/init.d
# ./apache2 start

Now when you type following URL in brower input "http://localhost", you will land on  the apache2 default page.

Just now we have also installed mod_jk ( Yast, search mod_jk, and install). But mod_jk is not loaded by apache via default. 


4.2 Configure Apache to load/use mod_jk

Configuration of Apache to use mod_jk, three things need to be done:

1.  Add a file "mod_jk. conf" to Apache. This will load mod_jk module and specify "worker.properties" file for mod_jk
2.  Add a "worker.properties" file to configure mod_jk workers
3.  Add vritual host which will use mod_jk


4.2.1 mod_jk.conf

Create a "mod_jk.conf" file in folder "/etc/apache2/conf.d/".
You could also name the file "sample.sss.conf", but important is, the file name must have ".conf" at the end, and the is put in "conf.d" folder. In this way, the file will be found and loaded by apache.

Content of the "mod_jk.conf" file:



#### START mod_jk.conf
# mod_jk configuration for Apache
# Load mod_jk module
LoadModule jk_module /usr/lib/apache2/mod_jk.so

# Tell Apache where to find workers.properties. We assume Tomcat runs on a differerent machine than # Apache. and put workers.properties file near to apache
JkWorkersFile /etc/apache2/conf.d/workers.properties

# mod_jk log configuration
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel debug
jkLogStampFormat "[%a %b %H:%M:%S %Y]"

# JkOptions indicate to send SSL KEY SIZE,
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories

# JkRequestLogFormat set the request format
JkRequestLogFormat "%W %V %T"

# Send everything for context /TestWebSec20 to worker ajp13
JkMount /TestWebSec20 worker1
JkMount /TestWebSec20/* worker1

# Send everything for context /sampple to worker ajp13
#JkMount /sample worker1
#JkMound /sample/* worker1

##### END mod_jk.conf




Explanation to the "mod_jk.conf" file

1. LoadModule tells Apache to load  mod_jk module.
2. JkWorkersFile specifies the worker file location. Workers file tells mod_jk, where to find the real 
    application (i.e. ip and port of the Server / application). 
3. JkMount, have 2 entries, one with another without "*"


4.2.2 workers.properties file

Create a "workers.properties" file in conf.d folder with following content:



##### SATART works.properties
# Define a worker named "worker1"
# Several worker names are separated by ","
worker.list=worker1

# Set properties for worker1 to use ajp13 protocol and run on port 8009
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
worker.worker1.lbfactor=50
worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.socket_timeout=300

##### END works.properties




Explanation to the workers.properties file:

1. We just configured one worker. In case of more workers, worker names are separated by ",". 
   For example: 
   worker.list=worker1, worker2
 2. Workers are configured to use / communicate to certain host and port using "ajp" protocol.
     When a request comes to apache /mod_jk  via http or https, mod_jk will redirect the request  NOT to   
     HTTP or HTTPS ports, but to AJP ports.(We will configure Tomcat to use AJP connector).



4.2.3 Create virtual host and configure the virtual host to use mod_jk

Assume we will configure a new virtual host "ahahacom", two steps are needed:

   Step 1
    Add virtual host to "hosts" file. Edit "hosts" file under "/etc/", add following lines:
   127.0.0.1  ahaha.com www.ahaha.com

   Step 2
   Create a vhost.conf file under "/etc/apache2/vhost.d/" with following content



#### STAART vhost.conf
   <VirtualHost *:80>    
         ServerAdmin info@ahaha.com
         ServerName ahaha.com

        # DocumentRoot: The directory out of which you will serve your
        # documents. By default, all requests are taken from this directory, but
        # symbolic links and aliases may be used to point to other locations.
        DocumentRoot /srv/www/vhosts/ahaha.com

        # if not specified, the global error log is used
        ErrorLog /var/log/apache2/ahaha.com_error.log
        CustomLog /var/log/apache2/ahaha.com_access.log combined

        JkMount / worker1
        JkMount /* worker1  
   </VirtualHost>  
   #### END vhost.conf



With vhost configured, the "TestWebSec20" web application could be accessed "later" using following URL:

http://www.ahaha.com/TestWebSec20 

Now restart apache:

./apache2 restart

Try accessing the "http://www.ahaha.com/TestWebSec20/HalloNormal" with your browser.

The browser will show an error "Service Temporarily Unavailable"

Check the mod_jk error log we just configured "
/var/log/apache2/ahaha.com_error.log"

You will see a new error log entry like this:





[Mon Sep 03 20:36:32 2012] [error] [client 127.0.0.1] (2)No such file or directory: cannot access type map file: HTTP_SERVICE_UNAVAILABLE.html.var 




When you see this error, your virtual host configuration and  mod_jk configuration at Apache/mod_jk side are correct!

This above error says that mod_jk can not find the worker, i.e. it can not find the Tomcat server. Remember, mod_jk tries to talk to Tomcat with "ajp" protocol, to certain host name and port (as configured in "workers.properties"), so the question is now, does Tomcat know about the "ajp" thing? 
No not yet!

Configure Tomcat to communicate with mod_jk, using AJP
SSL Offloading with mod_jk part 5
part1 part2 part3 part6

SSL Offloading with mod_jk part 3

Document  Version 1.0
   Copyright © 2012-2013 beijing.beijing.012@gmail.com

Keywords:
SSLOffloading SSL-Offloading, SSL Termination, Apache, Tomcat, mod_jk configuration, multiple vhosts, multiple SSL certificates one ip



Till now we have successfuly protected our TestWevSec20 Web application with SSL.

The 2 servlets are accessed via following links:

http://localhost:8080/TestWebSec20/HalloNormal

And 

http://localhost:8080/TestWebSec20/secure/HalloSec, which is redirected to 
https://localhost:8443/TestWebSec20/secure/HalloSec

However, for a real web page, we expect to visit the page via a "real" domain name like "www.sample.com", and NOT localhost. We also don't want browser show http/https ports to user. 

So we need to hide the application behinde some proxy/load_balancer... what ever, make the "TestWevSec20" to be accessed using following URLs: 

http://www.ahaha.com/TestWebSec20/HalloNormal

And 

http://www.ahaha.com/TestWebSec20/secure/HalloSec

For this purpose, we need to front Tomcat with Apache and mod_jk


SSL Offloading with mod_jk part 4
part1 part2 part5 part6

SSL Offloading with mod_jk part 2


Document  Version 1.0
Keywords:
SSLOffloading SSL-Offloading, SSL Termination, Apache, Tomcat, mod_jk configuration, multiple vhosts, multiple SSL certificates one ip


In part1, we have created a sample web application TestWebSec20, and could successfully access the servlet "HalloNormal".
Now we will try to access the "HalloSec" servlet. Since the "HalloSec" servlet is declared to be accessd via URL pattern "/secure/HalloSec". So we put following URL in brower input:

http://localhost:8080/TestWebSec20/HalloSec


We get error like "..can not connect to localhost...".  And when we have a look  at Tomcat's log, we will see that Tomcat has logged a fatal error at start (and we ignored it in part1):

java.io.FileNotFoundException: /home/xx/.keystore (No such file or directory)


This is because, Tomcat detected that a resource is protected with HTTPS, so it tries to locad the SSL keystore (keystore is needed by JAAS) in the users home location (Linux). But for the default Tomcat instllation there is no keystore file available yet.

Create and configure keystore for Tomcat

Creating keystore

In standard JDK package there is "keytool" under JAVA_HOME/bin/. This keytool could be used to create a keystore for Tomcat/JAAS. Run following conmand:

keytool -genkey -alias localhost -keyalg RSA -keystore /opt/local_keystore/localhost_keystore
  

Now a keystore file named "localhost_keystore" is created. (with  password "test1234", we will need the password to configure Tomcat SSL)
Here instead of using default  ".keystore" location, we used customer keystore location and keystore name. Now we need to configure Tomcat's ssl connector in server.xml:


...
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150"
               clientAuth="false" sslProtocol="TLS"
      keystoreFile="/opt/local_keystore/localhost_keystore" keystorePass="test1234"/>
...


Start Tomcat and try accessing the secured servlet again:



Browser is redirected to HTTPS, and we need to confirm the SSL certificate:

Click the left side area of browser input to show the certificate.  It is the certificate we just created! Successful!!


SSL Offloading with mod_jk part 3
part1 part4 part5 part6

Saturday, September 8, 2012

SSL Offloading with mod_jk part 1

Document  Version 1.0
   Copyright © 2012-2013 beijing.beijing.012@gmail.com


Keywords:
SSLOffloading SSL-Offloading, SSL Termination, Apache, Tomcat, mod_jk configuration, multiple vhosts, SSL certificate, multiple SSL certificates one ip



Table of Contents

Part 1 :  Create a simple servlet based Web Application "TestWebSec20"
              1.1  System Architect
              1.2  Technical Infrastructure
              1.3  "HalloNormal" Servlet
              1.4   web.xml

Part 2 :  Create and configure keystore for Tomcat

Part 3 :  Run "HalloNormal" and "HalloSec" Web Application

Part 4 : Fronting Tomcat with Apache and mod_jk
             4.1    Install Apache2
             4.2    Configure Apache to load / use mod_jk
             4.2.1 mod_jk.conf  file
             4.2.2 workers.properties file
             4.2.3 Create virtual hosts and configure the virtual host to use mod_jk

Part 5 : SSL port problem

Part 6 : Configure Tomcat to accept SSL handling of mod_jk
             6.1 Generate a self-signed SSL certificate
             6.2 Configure Apache virtual host for SSL
             6.3 Configure Tomcat to accept SSL handling of mod_jk



There seems alway  to be a gap between the people who write applications, and those to take care of the running applications, i.e. the operation guys. 
It was surprising to find, how things could be misunderstand, even done wrong, because lack of the whole understanding of both areas, concering topics like applicaiton load balancing,  scaling, failover, security, SSL ...

Recently I had the chance again in a project to review the system architecture and security concept, and this made me to decide to "document" some of my experinence and considerations, practices ....,  not only about this project, but also back to the years, in the hope to help those who just looking for a solution to some problmes.


Lets begin with SSL Termination /  SSL Offloading, and this is the part 1/7 


With a simple servlet based Web Applicaion, we will trying to make it run like a real world web application, which has its own domain name(s), which run behind a locad balancer, which has resources protected by SSL, and SSL handled  by SSL offloading ...


1.1 System Architect:





When we finished, we will have:

1. A simple Web application with partially ssl protected resources
2. Web Applicaiton running in Tomcat, and Tomcat fronted with Apache + mod_jk
3. Web Applicaiton  being accessed using  "virtual host",  with its own SSL certificate
4. Multiple "virtual host" addressing the same Web Application, each having it own certificate


1.2 The necessary technical infrastructure:


1. Linux (openSuse 12.1) with Apache2 installed
2. Tomcat (7.x)
3. Eclispe IDE for Java


Part 1 : Create a simple servlet based Web Application "TestWebSec20"

We will create a servlet based Web Application called "TestWebSec20" with Eclipse IDE.
TestWebSec20 Web Application has 2 servlets:
 "HalloNormal" servlet 
  "HalloSec" servlet. "HalloNormal" will be protected with SSL.


1.3 "HalloNormal" servlet:




import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HalloSec
 */
public class HalloSec extends HttpServlet {
      private static final long serialVersionUID = 1L;
      
      /**
       * @see HttpServlet#HttpServlet()
       */
       public HalloSec() {
            super();
            // TODO Auto-generated constructor stub
       }

      /**
       * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
       */
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws     ServletException, IOException {
          doPost(request, response);
      }

      /**
       * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
       */
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // TODO Auto-generated method stub
        PrintWriter writer =response.getWriter();
        writer.write("Hallo Sec");
        writer.flush();
        writer.close();
        }
   }
 


1.4 web.xml:



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app id="WebApp_ID">
<display-name>TestWebSec20</display-name>
        <servlet>
                <servlet-name>HalloNormal</servlet-name>
                <display-name>HalloNormal</display-name>
                <description>TestWebSec20</description>
                <servlet-class>web.sec.HalloNormal</servlet-class>
        </servlet>
        <servlet>
                <servlet-name>HalloSec</servlet-name>
                <display-name>HalloSec</display-name>
                <description></description>
                <servlet-class>web.sec.HalloSec</servlet-class>
        </servlet>

        <servlet-mapping>
                <servlet-name>HalloNormal</servlet-name>
                <url-pattern>/HalloNormal</url-pattern>
        </servlet-mapping>

        <servlet-mapping>
                <servlet-name>HalloSec</servlet-name>
                <url-pattern>/secure/HalloSec</url-pattern>
        </servlet-mapping>

        <welcome-file-list>
                <welcome-file>index.html</welcome-file>
        </welcome-file-list>

        <security-constraint>
                <display-name>Example Security Constraint</display-name>
                <web-resource-collection>
                        <web-resource-name>Secure Area</web-resource-name>
                        <url-pattern>/secure/*</url-pattern>
                                <http-method>GET</http-method>
                                <http-method>POST</http-method>
               </web-resource-collection>
               
              <!-- 
             <auth-constraint>
                      <role-name>*</role-name>
            </auth-constraint>
             -->

            <user-data-constraint>
                    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
             </user-data-constraint>
        </security-constraint>
</web-app>



Explanation to web.xml

    *  "HalloSec" servlet will be accessed using url "/secure/HalloSec". 

       This RUL is protected by "security-constraint".
    *  "auth-constraint" is commented out, so that here no "login form" is required.
    *  transport-guarantee CONFIDENTIAL makes the path protected by SSL.
       A HTTP request to this path /secure/* will be redirected to HTTPS


Deploy the TestWebSec20 Web Application(TestWebSec20.war) to Tomcat (v.7.x). 

Start Tomcat. Now try accessing the HalloNormal servlet using following URL:
http://localhost:8080/TestWebSec20/HalloNormal, You willl now see text "Hallo Normal" in your browser:


SSL Offloading with mod_jk part 2
part3 part4 part5 part6