setup nginx to require certain conditions of a location for all but a given source IP
I'm looking for a setup where I'd like to have SSL client certificates for all but one source IP.
My idea is to set
ssl_verify_client optional;
and to add an elaborate if statement to the locations. However I don't know how to write such an if statement.
# this requires ssl client certificates for all locations
location / {
if ($ssl_client_verify != "SUCCESS") {
return 403;
...
}
# now what to write to require ssl certs except if source IP is e.g. 1.2.3.4
location /two {
if (?????) {
return 403;
...
}
Edit: Additional information
The switch ssl_verify_client with the value optional
tells clients, that they can but don't have to send client certificates.
So by checking the variable $var_ssl_client_verify I can see whether a client certificate was presented and valid (SUCCESS
) or not.
This rule shall be applied for all clients, that do not have a given source IP. For one specific source IP I do not want to verify client certificates.
What I need is something like
if ($ssl_client_verify != "SUCCESS" and source_ip != 1.2.3.4 ) {
return 403;
}
Edit 2: I changed the title from
setup nginx to require client certs for all but a given source IP
to
setup nginx to require certain conditions of a location for all but a given source IP
as what I am really struggling with has nothing to do with client certificates, but with combining if statements and filtering conditionally on the source IP address.
Multiple conditions aren't supported in Nginx for if
statement. So, as a workaround and as client IP is evaluated in our usecase, the solution could be achieved similar to how it was achieved at https://www.nginx.com/blog/rate-limiting-nginx/#Advanced-Configuration-Examples . Basically, the solution goes like this...
geo $limit {
default 1;
1.2.3.4 0; #please replace the example IP with the actual IP.
}
ssl_verify_client optional;
ssl_client_certificate /path/to/cert.pem;
map $limit $limit_key {
0 "SUCCESS";
1 $ssl_client_verify;
}
server {
# ... other directives
location / {
if ( $limit_key != 'SUCCESS' ) { return 403; }
# ... other directives
}
}
Basically, we assign the value "SUCCESS" to the variable for a specific IP. For every other IP, we assign the actual value of $ssl_client_verify
.
Alternative Answer
ssl_verify_client optional;
ssl_client_certificate /path/to/cert.pem;
server {
# ... other directives
# initial value of $variable is the actual value of $ssl_client_verify
set $variable $ssl_client_verify;
# here we re-assign $variable with "SUCCESS" for our specific IP
# please replace 1.2.3.4 with the actual IP
if ( $remote_addr = "1.2.3.4" ) {
set $variable "SUCCESS";
}
location / {
if ( $variable != 'SUCCESS' ) { return 403; }
# ... other directives
}
}