Nginx mutual SSL with WSO2 ESB/API Manager

Jenananthan
4 min readJun 8, 2016

--

Prerequisite

  • Nginx server 1.8 (version > 1.7.8, proxy_ssl_certificate directive is available from 1.7.8 only)

Installing nginx server 1.8 can be found here
https://www.jamescoyle.net/how-to/1678-install-nginx-on-debian-ubuntu

To uninstall the existing nginx ,execute following command
sudo apt-get purge nginx nginx-common nginx-full

  • Environment -ubuntu
  • wso2apim(or wso2esb/wso2appmanager)
  • curl

STEP 1

Configure Nginx for One way ssl from Client to Nginx

(Client) ←One Way SSL → (Nginx Server)

  1. Create public and private key for Nginx

Execute the following command and create the public and private key by providing

Necessary information.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx.key -out nginx.crt

This will create nginx.key (private key) and ninx.crt(public key) files.

  1. Add certificate to Nginx
  2. Navigate to /etc/nginx
  3. Create directory called ‘ssl’ if not exists. (sudo mkdir ssl)
  4. Create directory called nginx under ‘ssl’ (sudo mkdir ssl/nginx)
  5. Copy the nginx.crt and nginx.key files to nginx directory
  6. Add configuration

Add following host map in /etc/hosts file

 127.0.0.1 nginx.proxy.com
  • Add following configuration to /etc/nginx/conf.d/default.conf
server {listen 443;
server_name nginx.proxy.com;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx/nginx.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#This location section is to test and verify the client to server ssl connection
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
  1. Verify
    Restart the nginx
    Execute : curl -k https://nginx.proxy.com
    Result -
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p><p>For online documentation and support please refer to<a href=”http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href=”http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>

STEP 2

Configure Nginx for mutual ssl/two way ssl between client and Nginx

(Client) ←Mutual SSL/TWO Way SSL → (Nginx Server)

  1. Create public and private key for client(here we use curl as client)

Execute the following command and create the public and private key by providing necessary information

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout client.key -out client.crt

This will create client.key (private key) and client.crt(public key) files.

  1. Add client’s certificate to Nginx
  2. Navigate to /etc/nginx
  3. Create directory called ‘ssl’ if not exists. (sudo mkdir ssl)
  4. Create directory called nginx under ‘trust’ (sudo mkdir ssl/trust)
  5. Copy the client.crt file to nginx directory
  6. Add configuration to enable mutual ssl (nginx requests client certificate in SSL handshake)

Modify the configuration(/etc/nginx/conf.d/default.conf) done in STEP 1 by adding

#setting for mutual ssl with client
ssl_client_certificate /etc/nginx/ssl/trust/client.crt;
ssl_verify_client on;

Configuration after modification

server {listen 443;
server_name nginx.proxy.com;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx/nginx.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#setting for mutual ssl with client
ssl_client_certificate /etc/nginx/ssl/trust/client.crt;
ssl_verify_client on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}

7. Verify
Restart the nginx
Execute command : curl -k https://nginx.proxy.com
Result :

<html><head><title>400 No required SSL certificate was sent</title></head><body bgcolor=”white”><center><h1>400 Bad Request</h1></center><center>No required SSL certificate was sent</center><hr><center>nginx/1.8.1</center></body></html>

Getting above message from server. Because server(Nginx) expecting the client’s certificate in SSL handshake, but curl doesn’t have the cert to provide.

So correct curl command should be like this ,

curl -k — key client.key — cert client.crt https://nginx.proxy.com

This will give success response as got in STEP 1

STEP 3

Configure Nginx for one way ssl from Nginx to backend server(upstream)

(Client) ←Mutual SSL → (Nginx Server) ←One way SSL →(Backend server)

  1. Create a inline prototype api for GET method in API Manager. We are going to invoke this api though nginx.
  2. Add configuration to Proxy the gateway

Modify the configuration(/etc/nginx/conf.d/default.conf) done in STEP 2 by adding

location /gateway/ {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://localhost:8243/;
proxy_redirect https://localhost:8243/ https://nginx.proxy.com/
gateway/;
}

Configuration after modification

server {listen 443;
server_name nginx.proxy.com;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx/nginx.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#setting for mutual ssl with client
ssl_client_certificate /etc/nginx/ssl/trust/client.crt;
ssl_verify_client on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}location /gateway/ {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://localhost:8243/;
proxy_redirect https://localhost:8243/ https://nginx.proxy.com/
gateway/;
}}

3. Verify

Restart the nginx
If created api’s gateway url is https://nginx.proxy.com/gateway/test/1
Execute :curl -k — key client.key — cert client.crt https://nginx.proxy.com/gateway/test/1

Result : { “data” : “sample JSON”}

STEP 4

Configure Nginx for mutual ssl between Nginx and Backend server/upstream

(Client) ←Mutual SSL → (Nginx Server) ←Mutual →(Backend server)

  1. Modify the configuration(/etc/nginx/conf.d/default.conf) done in STEP 3 by adding
#setting for mutual ssl with upstream/backend server
proxy_ssl_certificate /etc/nginx/ssl/nginx/nginx.crt;
proxy_ssl_certificate_key /etc/nginx/ssl/nginx/nginx.key;

Configuration after modification

server {listen 443;
server_name nginx.proxy.com;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx/nginx.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#setting for mutual ssl with client
ssl_client_certificate /etc/nginx/ssl/trust/client.crt;
ssl_verify_client on;
location /gateway/ {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://localhost:8243/;
proxy_redirect https://localhost:8243/ https://nginx.proxy.com
/gateway/;
#setting for mutual ssl with upstream/backend server
proxy_ssl_certificate /etc/nginx/ssl/nginx/nginx.crt;
proxy_ssl_certificate_key /etc/nginx/ssl/nginx/nginx.key;
}}

2. Configure API Manager for mutual ssl

  • Enable mutual ssl in /repository/conf/axis2/axis2.xml by adding

<parameter name=”SSLVerifyClient”>require</parameter>

under https transportReceiver

  • Import nginx certificate to wso2 server’s (nginx.crt) trust store

keytool -import -file nginx.crt -alias nginx -keystore client-truststore.jks

3. Verify

Restart the nginx and APIM

Execute :curl -k — key client.key — cert client.crt https://nginx.proxy.com/gateway/test/1

Result : { “data” : “sample JSON”}

Note : We use -k option in curl to access in insecure way . if not using this option need to point a trust store to curl and trust store should have the public cert we generated for nginx.

Also nigx access the backend in insecure way , to verify the back end’s certificate in SSL handshake following configuration should be added to upstream’s location section.

#verify server certificate in ssl handshake
proxy_ssl_verify on;
proxy_ssl_trusted_certificate etc/nginx/ssl/upstream/wso2carbon.pem;

Where backend servers certificate should be in pem format.

For openssl 1.1.0 this will not work on ubuntu since there is following bug

http://serverfault.com/questions/389197/ssl-routinesssl23-writessl-handshake-failure

Nginx — commands

sudo /etc/init.d/nginx startsudo /etc/init.d/nginx stopsudo /etc/init.d/nginx restartsudo /etc/init.d/nginx reload

--

--