Add posibility to set rate limiting to locations
Add possibility to override rate limits to custom location
on ngix proxy.
fixes-bug: PROD-36891
Change-Id: I5668818b691089304cd7242a1c795d9c6109ca27
diff --git a/README.rst b/README.rst
index aa9875f..d7f004b 100644
--- a/README.rst
+++ b/README.rst
@@ -460,6 +460,36 @@
burst: 5
enabled: true
+To apply request limiting to particular location of particular site `limit` should be
+applied on location level. Pay attention that location level overrides site level,
+Two methods are supported:
+ - By IP
+ - By http requst method (get, post ...)
+for example:
+
+.. code-block:: yaml
+
+ nginx:
+ server:
+ site:
+ nginx_proxy_openstack_api_keystone:
+ location:
+ /some_location/:
+ limit:
+ enabled: true
+ methods:
+ ip:
+ enabled: True
+ get:
+ enabled: True
+ rate: 120r/s
+ burst: 600
+ size: 20m
+ nodelay: True
+ post:
+ enabled: True
+ rate: 50r/m
+ burst: 80
Use `ngx_http_limit_conn_module` module that is used to set the shared memory
zone and the maximum allowed number of connections for a given key value.
diff --git a/nginx/files/_limit.conf b/nginx/files/_limit.conf
index e0ff102..b60406b 100644
--- a/nginx/files/_limit.conf
+++ b/nginx/files/_limit.conf
@@ -29,3 +29,41 @@
{%- endfor %}
{%- endif %}
+
+ {%- set location = {} %}
+ {%- if site.get('location') %}
+ {%- do location.update(site.location) %}
+ {%- for path, location in location.items() %}
+ {%- if location.limit is defined %}
+ {%- if location.get('limit', {}).get('enabled', False) and location.limit.methods is defined %}
+ {%- if location.limit.methods.ip is defined and location.limit.methods.get('ip').get('enabled',False) %}
+ # Create whitelist for ip addresses
+geo $ip_{{ site_name }}_{{ path|replace('/','_') }} {
+ default "enforce";
+ {%- for ip in location.limit.methods.ip.get('ip_whitelist', []) %}
+ {{ ip }} "whitelist";
+ {%- endfor %}
+}
+ # First, map all whitelisted IP's to the request query
+map $ip_{{ site_name }}_{{ path|replace('/','_') }} $limit_{{ site_name }}_{{ path|replace('/','_') }} {
+ default {{ location.limit.methods.ip.get('query', '$binary_remote_addr') }};
+ "whitelist" "";
+}
+
+limit_req_zone $limit_{{ site_name }}_{{ path|replace('/','_') }} zone=ip_{{ site_name }}_{{ path|replace('/','_') }}:{{ location.limit.methods.ip.get('size', '10m') }} rate={{ location.limit.methods.ip.get('rate','10r/s') }};
+ {%- endif %}
+
+{%- for method, method_data in location.limit.methods.items() %}
+{%- if method != 'ip' %}
+map $request_method $limit_{{ method }}_{{ site_name }}_{{ path|replace('/','_') }} {
+ default "";
+ {{ method|upper }} "limit_{{ method }}";
+}
+limit_req_zone $limit_{{ method }}_{{ site_name }}_{{ path|replace('/','_') }} zone={{ method }}_{{ site_name }}_{{ path|replace('/','_') }}:{{ location.limit.methods.get(method,{}).get('size', '10m') }} rate={{ location.limit.methods.get(method,{}).get('rate','10r/s') }};
+{%- endif %}
+{%- endfor %}
+ {%- endif %}
+ {%- endif %}
+ {%- endfor %}
+ {%- endif %}
+
diff --git a/nginx/files/proxy.conf b/nginx/files/proxy.conf
index 8d57fd8..7aac4a4 100644
--- a/nginx/files/proxy.conf
+++ b/nginx/files/proxy.conf
@@ -146,11 +146,18 @@
{# The approach below is deprecated, as it was limited funtionality #}
{# compare to flexibility that nginx provide. site:limit_req_module:limit_req shall be used instead. #}
- {%- if site.get('limit', {}).get('enabled', False) %}
+ {%- if location.limit is defined and location.limit.methods is defined %}
+ {%- for method, method_data in location.limit.methods.items() %}
+ {%- if method_data.get('enabled', False) %}
+ limit_req zone={{ method }}_{{ site_name+'_'+path|replace('/','_') }}{% if method_data.get('burst', False) %} burst={{ method_data.burst }}{% endif %}{% if method_data.get('nodelay', False) %} nodelay{% endif %};
+ {%- endif %}
+ {%- endfor %}
+
+ {%- elif site.get('limit', {}).get('enabled', False) %}
limit_req zone={{ site_name }}{% if site.limit.get('burst', False) %} burst={{ site.limit.burst }}{% endif %}{% if site.limit.get('nodelay', False) %} nodelay{% endif %};
- {%- for subfilter_name, subfilter in site.limit.get('subfilters', {}).items() %}
+ {%- for subfilter_name, subfilter in site.limit.get('subfilters', {}).items() %}
limit_req zone={{ site_name }}_{{ subfilter_name }}{% if subfilter.get('burst', False) %} burst={{ subfilter.burst }}{% endif %}{% if subfilter.get('nodelay', False) %} nodelay{% endif %};
- {%- endfor %}
+ {%- endfor %}
{%- endif %}
}
{%- endfor %}