6

I'm trying to set up a load balancer via an Nginx reverse proxy. My application uses client certificates to authenticate clients. I would like my reverse proxy to forward the client certificate to my back-end servers. I have added this line to my reverse proxy's configuration to store the client certificate information in a custom HTTP header:

proxy_set_header X-SSL-CERT $ssl_client_cert

However, $ssl_client_cert uses multiple lines to store the certificate, and my back-end nginx server does not recognize this properly as one HTTP header. What is the best way to achieve forward my client certificates?

This question has been asked in 2013 on this forum, but so far no real solution: https://forum.nginx.org/read.php?2,236546,236546

Thanks!

0

5 Answers 5

5

So I have found a solution. I remove all newlines in the certificate and send them as a single HTTP Header from the proxy to the back-end, similar as explained here:

https://forum.nginx.org/read.php?2,236546,236546

In my back-end I reconstruct the certificate by adding a newline every 64 characters. The updated code for the reverse proxy is the following and works up to 26 lines:

map $ssl_client_raw_cert $a {
   "~^(-.*-\n)(?<st>[^\n]+)\n((?<b>[^\n]+)\n)?((?<c>[^\n]+)\n)?((?<d>[^\n]+)\n)?((?<e>[^\n]+)\n)?((?<f>[^\n]+)\n)?((?<g>[^\n]+)\n)?((?<h>[^\n]+)\n)?((?<i>[^\n]+)\n)?((?<j>[^\n]+)\n)?((?<k>[^\n]+)\n)?((?<l>[^\n]+)\n)?((?<m>[^\n]+)\n)?((?<n>[^\n]+)\n)?((?<o>[^\n]+)\n)?((?<p>[^\n]+)\n)?((?<q>[^\n]+)\n)?((?<r>[^\n]+)\n)?((?<s>[^\n]+)\n)?((?<t>[^\n]+)\n)?((?<v>[^\n]+)\n)?((?<u>[^\n]+)\n)?((?<w>[^\n]+)\n)?((?<x>[^\n]+)\n)?((?<y>[^\n]+)\n)?((?<z>[^\n]+)\n)?(-.*-)$" $st;
}

server {
   location / {
      proxy_set_header X-cert $a$b$c$d$e$f$g$h$i$j$k$l$m$n$o$p$q$r$s$t$v$u$w$x$y$z;
      proxy_pass http://localhost:8000;
   }
}

(note that I have removed the variable starting with a number) While this solution is not ideal, it works for me at this moment. Another solution would be to only send the certificate's DN info, which is a single line. This does not work for me at this time, as I have not stored every DN in my database.

3
  • 1
    This sounds and feels "hackish", but nevertheless, +1 for finding this solution.
    – gxx
    Jul 10, 2016 at 13:51
  • This is extremely hackish. What if you have a much longer certificate or receive a chain? Jul 10, 2016 at 18:29
  • You're right. However, in my case this will not occur as the certificates are given out by me and I know how long they are. It does come with an extra possibility to break. If there will be a fix in Nginx for the $ssl_client_cert being able to handle line breaks properly, that would be better!
    – Hidde
    Jul 11, 2016 at 17:10
3

It looks like newer versions of nginx change all \n to \t for you in the variable $ssl_client_cert. The variable $ssl_client_raw_cert is available if you don't want that transformation applied.

See: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables

2

I believe this is now the way to go solving the original problem:

proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;

According to the docs:

$ssl_client_escaped_cert returns the client certificate in the PEM format (urlencoded) for an established SSL connection (1.13.5);

1

I see 2 solutions here:

  1. Enable LUA scripting and reformat the string in a no-end-of-line format.
  2. Use the Set Misc plugin and use base64_encode on that variable.
1
  • Thanks! I'll try to see if the Misc plugin can provide any help.
    – Hidde
    Jul 9, 2016 at 16:19
1

Here is the LUA solution that worked for me:

set_by_lua $client_cert "return ngx.var.ssl_client_raw_cert and ngx.var.ssl_client_raw_cert:gsub('\\n',' ') or nil";
proxy_set_header X-SSL-CERT $client_cert;

Also, if you use Ubuntu, nginx-extra has LUA plugin by default so there's no need for additional configuration: https://stackoverflow.com/questions/22193852/running-lua-in-nginx-config

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .