Score:1

setup nginx to require certain conditions of a location for all but a given source IP

de flag

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.

us flag
Using `if` inside locations doesn't work like you would expect: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
Score:1
sv flag

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
    }
}
sv flag
@gelonida Apologies for misunderstanding your question initially.
gelonida avatar
de flag
Thanks for your answer. This should do the job. So the idea is to use `geo` for source ip adress mapping, `map` statements to create one variable, which can finally be used in an `if ( $variable != "SUCCESS") { return 403; }` Concerning the initial misunderstanding. It made me rewrite my question in (hopefully) a less ambiguous and more generic way. Will mark question as OK as soon as I have the opportunity to test in my environment. In reality my scenario is a little more complicated as the ip address will be determined via the proxy protocol.
sv flag
@gelonida You are right. Please see the updated answer that includes an alternative solution.
gelonida avatar
de flag
Alternative Answer is working for me. Didn't try so far the first one.
sv flag
Glad to know it worked.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.