Wednesday, April 6, 2016

Two-Way SSL Authentication : Client to Mule

Introduction
This page describes how two-way ssl authentication can be implemented for calls from a client to Mule.  Here the client is referred to as ServiceMax.

Overview

The following diagram compares one-way with two-way ssl authentication, as described in configuring-https-mule.

For two-way ssl authentication to work, the mule application must
  1. Expose an https endpoint
  2. Reference a keystore containing the certificate+private key for the https endpoint
  3. Reference a truststore containing ServiceMax's certificate
and ServiceMax must
  1. Have its own certifcate+private key
  2. Trust the certificate of the mule endpoint
The mule application's https endpoint must be configured as described in configuring-https-mule

HAProxy

In this scenario, ServiceMax does not talk directly to Mule, it communicates through an HAProxy instance.
HAProxy is configured to do SSL Termination (ie. the traffic transitions between encrypted for ServiceMax<->HAProxy and unencrypted for HAProxy<->Mule).
frontend www-https
   bind :443 ssl crt /haproxy/HAPROXY_CERT.pem
   reqadd X-Forwarded-Proto:\ https
   acl mule-hello path_beg /mule/hello
   use_backend mule-hello-backend if mule-hello

If Mule was to handle two-way ssl communication, HAProxy would need to be reconfigured to do simple tcp forwarding.
However, if we could perform two-way ssl authentication in HAProxy, HAProxy could continue to perform SSL offload and Mule wouldn’t need any certificate setup and could simply expose an http endpoint.
It turns out that HAProxy can be configured with client certificates, as discussed in ssl-client-certificate-management-at-application-level/.

Investigation

To test two-way ssl authentication in HAProxy

CURL Client

In this test, we mock the ServiceMax client using cURL.
In your work directory:
openssl genrsa -des3 2048 > mockservicemax.pem
openssl req -new -key mockservicemax.pem -out mockservicemax.csr
openssl x509 -req -days 3650 -in mockservicemax.csr -signkey mockservicemax.pem -out mockservicemax.crt

2) Copy the HAPROXY_CERT.pem certificate to your working directory (remove the private key if present).
3) Configure HAProxy:
frontend www-https
   bind :443 ssl crt /haproxy/HAPROXY_CERT.pem ca-file ./client.crt verify required
   ...

4) Add the mockservicemax certificate to the client.crt file:
cat mockservicemax.crt > /haproxy/client.crt
5) Restart HAProxy.
6) Simulate a call from ServiceMax.  Here, --cacert defines the trusted certificates (i.e. the haproxy certificate), --cert defines the client certificate, --key defines client certificate private key.
curl https://HAPROXY_HOST.com/mule/hello --trace trace.txt --cert ./mockservicemax.crt:password --key ./mockservicemax.pem --cacert HAPROXY_CERT.pem
If we do not provide a client certificate, the command fails with handshake failure.
If we generate another mock service max certificate, and use it in the command above, the command fails with unknown ca because the certificate has not been added to the haproxy truststore (client.crt file).