3

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!

4

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.

  • This sounds and feels "hackish", but nevertheless, +1 for finding this solution. – gf_ Jul 10 '16 at 13:51
  • This is extremely hackish. What if you have a much longer certificate or receive a chain? – Florin Asăvoaie Jul 10 '16 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 '16 at 17:10
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.
  • Thanks! I'll try to see if the Misc plugin can provide any help. – Hidde Jul 9 '16 at 16:19
1

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

0

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.