Skip to content

Instantly share code, notes, and snippets.

@schtobia
Last active August 22, 2023 11:18
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save schtobia/302cd39c0332240163f6 to your computer and use it in GitHub Desktop.
Save schtobia/302cd39c0332240163f6 to your computer and use it in GitHub Desktop.
CN-based client authentification with nginx. This emulates Apache's SSLRequire (%{SSL_CLIENT_S_DN_CN} in {"Really Me"})
map $ssl_client_s_dn $ssl_client_s_dn_cn {
default "";
~/CN=(?<CN>[^/]+) $CN;
}
server {
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
server_name foo.bar.com;
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
ssl_certificate /etc/ssl/$server_name;
ssl_certificate_key /some/where/private;
ssl_client_certificate /the/root/of/all/client/cas.pem
ssl_verify_depth 3;
ssl_verify_client optional;
location ~ ^/safe {
if ($ssl_client_verify != SUCCESS) {
return 401;
}
if ($ssl_client_s_dn_cn !~ "Really Me") {
return 401;
}
}
}
@tvdinh
Copy link

tvdinh commented Nov 8, 2018

@schtobia: Thanks for the gist. Have you considered this https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/, which basically concerns using "if" in "location" ? It does surprise me how this common CN-based client access control scenario is not so straight-forward in nginx...

@tvdinh
Copy link

tvdinh commented Nov 14, 2018

Update: Even "if" directive is troublesome as mentioned in the doc, they also said it would be ok if using with only "return" or "rewrite...". So the gist is still ok.

Thanks for the gist again.

@schtobia
Copy link
Author

Thanks for the comment. 👍 I know that if is considered evil, but at that time there was no other solution. Maybe there is now, but as this is a very exotic case for nginx, I doubt that. Hope you found it helpful!

@maresb
Copy link

maresb commented Aug 13, 2019

Since nginx release 1.11.6, the formatting of $ssl_client_s_dn has changed to use commas instead of slashes.

In this case, the following line should work:

~(^|,)CN=(?<CN>[^,]+) $CN;

(Note the two cases that CN= could occur either at the beginning of the line or following a , character.)

@arpan57
Copy link

arpan57 commented Feb 14, 2022

Hi @schtobia ,

Awesome example.
I am trying similar thing but I get the value of $ssl_client_s_dn as blank in nginx when I connect to nginx via curl ( I am passing valid key and the cert as well as capath) Do you know where I might be going wrong?
I have added a question in more details here : https://serverfault.com/questions/1093641/rejecting-connections-based-on-a-pattern-in-nginx

Thanks,
Arpan

@schtobia
Copy link
Author

Hi @arpan57,

I'm sorry, i didn't look into nginx for quite some time - I move my entire frontend to traefik.

@arpan57
Copy link

arpan57 commented Feb 15, 2022

hi @schtobia ,
Thank you for the quick response.

I managed to fix it. Posting solution here just in case it could aid someone.

In my configurations missing bit was ssl_verify_client optional; until we specify I learnt that unless we mention ssl_verify_client on or optional, the $ssl_client_s_dn variable is not set. It will keep printing blank.
A bit strange that nginx logs didn't say it, I had to figure it out by trial and error.
Hindsight it makes sense that without enabling client verification, what server will do with the client client subject DN.

Regards,
Arpan

@schtobia
Copy link
Author

Thanks for the follow-up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment