How to authenticate ssl client certificates with nginx front-end?
If you want Apache to handle the SSL verification, then you'll need to put it in front of nginx, or else do some crazy stuff with passing the client DN to Apache via a custom header or something -- an awful lot of work.
There are some facilities for doing DN checking in nginx, though; the Nginx HTTP SSL module docs give the possible variables (right down the bottom, and unfortunately the markup's stuffed so there's no header for it) but $ssl_client_s_dn
should be what you're looking for, and you can use nginx's programming-like directives (if $ssl_client_s_dn ~= CN=something_or_other
kind of thing) to redirect or return a 403 if you don't like the certificate presented. It'll be very different to what you're used to with Apache, but ultimately Apache's way of doing this sort of thing isn't an oil painting either, so it all depends on which ugly you prefer...
I'm curious, though, as to why you'd put nginx in front of Apache... either of them should be capable of doing the whole job of serving web pages.
Related videos on Youtube
vertti
I'm a Python developer with over 30 years of programming experience. My current focus is using Django for development of business SaaS applications, but I like other Python frameworks: Pylons, Flask, and Webcore. I also spend a lot of time dealing with security and implementing counter-measures.
Updated on September 17, 2022Comments
-
vertti over 1 year
I have some URL's that I like protecting with ssl client certificates using directives like these in my apache configs:
SSLVerifyClient require SSLVerifyDepth 10 SSLRequireSSL SSLOptions +StrictRequire SSLRequire %{REMOTE_ADDR} =~ m/^127\.0\.0\.1$/ \ or ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \ and %{SSL_CLIENT_I_DN_CN} eq "xxx" \ and %{SSL_CLIENT_S_DN_Email} in {"[email protected]", "[email protected]",} )
There don't seem to be any nginx directives to handle this, so I assume I have to pass everything on to Apache backend.
Which brings me to my question, how to pass encrypted ssl? All the proxying is decrypting the ssl packets at nginx level before passing them on to Apache.
-
David Betz about 8 yearsYou should ask a question about how to do what you want with Nginx. Downgrading back to Apache is not the solution. Using Django (you said mod_wsgi in another comment) can be done in Nginx easily. I do this for MANY sites. Look into uwsgi and Nginx. If you find Apache to be faster, your config is wrong. Ask those questions.
-
-
vertti over 14 yearsOk, I'll look into the directives bit. I'm running nginx in front of Apache because I need multiple "all ssl" virtual hosts and SNI seems pretty sketchy. I still need Apache primarily because of mod_wsgi for Django apps as well as passenger for RoR and php-fpm. I had a highly tuned Apache before needing multiple SSL sites so wouldn't have changed otherwise. As it turns out nginx reduced my ssl page loads by around .3 secs or so and is fantastic on the static files so it was a great change.
-
vertti over 14 yearsOk, got it working using something pretty close to the direction you pointed.
-
Doktor J almost 7 yearsThe link in your answer is broken, it appears nginx.org/en/docs/http/ngx_http_ssl_module.html#variables is the correct location. Also, you can pass these variables to your interpreter via
fastcgi_param DN $ssl_client_s_dn
if you're using fastcgi, If you're using proxy_pass instead, you can define arbitrary headers, e.g.proxy_set_header nginx-ssl-client-dn $ssl_client_s_dn
and have the upstream server act on those headers (e.g. PHP behind an Apache upstream server would expose it as$_SERVER['NGINX_SSL_CLIENT_DN']
)