5

I'm sure this is an FAQ but I couldn't find anything I recognized as being the same question.

I have several web-apps running in Tomcat, with some pages e.g. the login page protected by SSL as defined by confidentiality elements in their web.xmls. One of the apps also accepts client-authentication via certificate. I also have a rather extensive JAAS-based authorization & authentication scheme, and there is all kinds of shared code and different JAAS configurations etc between the various webapps.

I really don't want to disturb any of that while accomplishing the below.

I am now in the process of inserting Apache HTTPD with mod-proxy and mod-proxy-balancer in front of Tomcat as a load balancer, prior to adding more Tomcat instances.

What I want to accomplish for HTTPS requests is that they are redirected 'blind' to Tomcat without HTTPD being the SSL endpoint, i.e. HTTPD just passes ciphertext directly to Tomcat so that TC can keep doing what it is already doing with logins, SSL, web.xml confidentialty guarantees, and most importantly client authentication.

Is this possible with the configuration I've described?

I am very familiar with the webapps and SSL and HTTPS and Tomcat, but my knowledge of the outer reaches of Apache HTTPD is limited.

Happy to have this moved if necessary but it is kind of programming with config files ;)

user207421
  • 305,947
  • 44
  • 307
  • 483

1 Answers1

7

This sounds similar to this question, where I've answered that it's not possible:

You can't just relay the SSL/TLS traffic to Tomcat from Apache. Either your SSL connection ends at Apache, and then you should reverse proxy the traffic to Tomcat (SSL [between Httpd and Tomcat] is rarely useful in this case), or you make the clients connect to Tomcat directly and let it handle the SSL connection.

I admit it's a bit short of links to back this claim. I guess I might be wrong (I've just never seen this done, but that doesn't strictly mean it doesn't exist...).

As you know, you need a direct connection, or a connection entirely relayed, between the user-agent and the SSL endpoint (in this case, you want it to be Tomcat). This means that Apache Httpd won't be able to look into the URL: it will know the host name at best (when using Server Name Indication).

The only option that doesn't seem to depend on a URL in the mod_proxy documentation is AllowCONNECT, which is what's used for forward proxy servers for HTTPS.

Even the options in mod_proxy_balancer expect a path at some point of the configuration. Its documentation doesn't mention SSL/HTTPS ("It provides load balancing support for HTTP, FTP and AJP13 protocols"), whereas mod_proxy talks at least about SSL when mentioning CONNECT.

I would suggest a couple of options:

  • Using an iptables-based load-balancer, without going through Httpd, ending the connections in Tomcat directly.

  • Ending the SSL/TLS connection at Httpd and using a plain HTTP reverse proxy to Tomcat.

This second option requires a bit more configuration to deal with the client certificates and Tomcat's security constraints.

If you have configured your webapp with <transport-guarantee>CONFIDENTIAL</transport-guarantee>, you will need to make Tomcat flag the connections as secure, despite the fact it sees them coming from its plain HTTP port. For Tomcat 5, here is an article (originally in French, but the automatic translations isn't too bad) describing how to implement a valve to set isSecure(). (If you're not familiar with valves, they are similar to filters, but operate within Tomcat itself, before the request is propagated to the webapp. They can be configured within Catalina) I think from Tomcat 5.5, the HTTP connector secure option does exactly that, without requiring your own valve. The AJP connector also has a similar option (if using mod_proxy_ajp or mod_jk).

If using the AJP connector, mod_proxy_ajp will forward the first certificate in the chain and make it available within Tomcat (via the normal request attribute). You'll probably need SSLOptions +ExportCertData +StdEnvVars. mod_jk (although deprecated as far as I know) can also forward the entire chain sent by the client (using JkOptions +ForwardSSLCertChain). This can be necessary when using proxy certificates (which are meaningless without the chain up to their end-entity certificate).

If you want to use mod_proxy_http, a trick is to pass the certificate via an HTTP header (mod_header), using something like RequestHeader set X-ClientCert %{SSL_CLIENT_CERT}s. I can't remember the exact details, but it's important to make sure that this header is cleared so that it never comes from the client's browser (who could forge it otherwise). If you need the full chain, you can try out this Httpd patch attempt. This approach would probably need an extra valve/filter to turn the header into the javax.servlet.request.X509Certificate (by parsing the PEM blocks).

A couple of other points that may be of interest:

  • If I remember well, you need to download the CRL files explicitly for Httpd and configure it to use them. Depending on the version of Httpd you're using, you may have to restart it to reload the CRLs.
  • If you're using re-negotiation to get your client-certificate, a CLIENT-CERT directive will not make Httpd request a client certificate as far as I know (this is otherwise done via a valve that can access the SSLSession when using the JSSE connector directly). You may have to configure the matching path in Httpd to request the client-certificate.
Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Thanks Bruno. It sounds like I should (a) use plaintext between HTTPD and Tomcat as you suggest, with HTTPD as the SSL endpoint to the client, (b) get rid of `CONFIDENTIAL`, which doesn't bother me, and search and destroy `isSecure()` in the code, and (d) use `mod_proxy_ajp` so the certificate comes through, which in fact I was already doing. I can handle configuring HTTPD for HTTPS and the certs etc. – user207421 Apr 13 '12 at 02:38
  • The only major problem I can see so far is with the client certificates. I have Tomcat configured not to ask for them so as to avoid browser popups, and there is a piece of Tomcat magic that does a rehandshake for a client of an application with client-certificate authentication, if it doesn't already have the cert. I would have to figure out how if possible to get the HTTPD to do that, or else maybe just not put that application in the cluster: it's a low volume one anyway. Other than that I think this looks good. – user207421 Apr 13 '12 at 03:07
  • 1
    You might be able to put `SSLVerifyClient none` globally and `SSLVerifyClient optional/require` in a `` element (but the path may have to be specific to what the webapp expects). – Bruno Apr 13 '12 at 15:54
  • Thanks, sounds like what I need. Tomcat doesn't have that level of granularity, which already caused me another problem. – user207421 Apr 14 '12 at 02:36
  • [This](http://markmail.org/message/vrodby2kcstfod27) might help if you wanted to do it directly in Tomcat. I haven't done this for a long time, so I can't remember the details. I remember having some stability problems with `mod_jk`+Jetty/AJP at some point under heavy load (not that heavy in fact, but for a burst of requests, about 200 within 30s): the AJP connections would just drop with nothing in the logs (Httpd or Jetty). Making Jetty (even BIO) handle the requests directly via JSSE turned out to be more stable (I didn't fully investigate the cause at the time, you may get better results). – Bruno Apr 14 '12 at 13:48
  • Yep. I am already using a custom Tomcat Authenticator or perhaps even Valve, JAAS, all kinds of things. SSLProxyVerify can indeed be specified at the server, virtual host, and directory levels, but I will probably let this one through directly to the web app concerned: I doubt that one needs load balancing. Thanks for your help. – user207421 Apr 15 '12 at 05:42