<p>I'm trying to setup rate limiting option <code>limit_req</code> for specific path in Kubernetes ingress-nginx to prevent brute-forcing authentication.</p>

<p>I've defined <code>limit_req_zone</code> using ConfigMap:</p>

<pre><code>http-snippet: |
      limit_req_zone $the_real_ip zone=authentication_ratelimit:10m rate=1r/s;
</code></pre>

<p>Next, I'm using annotation to add a custom location block:</p>

<pre><code>nginx.ingress.kubernetes.io/configuration-snippet: |
  location ~* "^/authenticate$" {
    limit_req zone=authentication_ratelimit nodelay;
    more_set_headers "x-test: matched";
  }
</code></pre>

<p>This produces nginx.conf:</p>

<pre><code>server {
# - - 8&lt; - -

  location / {
    # - - 8&lt; - -

    location ~* "^/authenticate$" {
      limit_req zone=authentication_ratelimit nodelay;
      more_set_headers "x-test: matched";
    }

    proxy_pass http://upstream_balancer;

    proxy_redirect                          off;
}
</code></pre>

<p>The result is that <code>/authenticate</code> always returns HTTP 503 (with x-test header). Message from ingress access logs:</p>

<pre><code>&lt;ip&gt; - [&lt;ip&gt;] - - [04/Jan/2019:15:22:07 +0000] "POST /authenticate HTTP/2.0" 503 197 "-" "curl/7.54.0" 172 0.000 [-] - - - - 1a63c9825c9795be1378b2547e29992d
</code></pre>

<p>I suspect this might be because of conflict between nested location block and <code>proxy_pass</code> (but this is just a wild guess).</p>

<p>What other options have I tried?</p>

<ul>
<li>use <code>server-snippet</code> annotation instead of <code>configuration-snippet</code> - <code>/authenticate</code> returns 404 because <code>proxy_pass</code> is not configured</li>
<li>use <code>nginx.ingress.kubernetes.io/limit-rpm</code> annotation - forces ratelimit on whole application which is not what I want.</li>
</ul>

<p>Question is why custom location block responds with 503? How can I debug this? Will increasing nginx logging level give more details about 503?
Or more general question: can I inject custom location blocks in ingress-nginx?</p>

jazgot
<p>This can be done by using map and that fact that <a href="http://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone" rel="noreferrer">Requests with an empty key value are not accounted.</a></p>

<pre><code>http-snippets: |
  map $uri $with_limit_req {
    default 0;
    "~*^/authenticate$" 1;
  }
  map $with_limit_req $auth_limit_req_key {
    default '';
    '1'     $binary_remote_addr; # the limit key
  }
  limit_req_zone $auth_limit_req_key zone=authentication_ratelimit:10m rate=1r/s;

</code></pre>

<p>And use annotation to add a custom location block:</p>

<pre><code>nginx.ingress.kubernetes.io/configuration-snippet: |
  limit_req zone=authentication_ratelimit nodelay;
</code></pre>

<p>Or if you use ingress from nginxinc</p>

<pre><code>nginx.org/location-snippets:
  limit_req zone=authentication_ratelimit nodelay;
</code></pre>

<p>in this case check if requests need to be ratelimited processed on map level.</p>

<p>And my opinion: better to limit requests on app level as if you made rate limit on ingress level, it depends on count of ingress pods.</p>
