Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add annotation to set value for burst multiplier on rate limit #6101

Merged
merged 1 commit into from
Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/user-guide/nginx-configuration/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,9 @@ By default the controller redirects all requests to an existing service that pro
These annotations define limits on connections and transmission rates. These can be used to mitigate [DDoS Attacks](https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus).

* `nginx.ingress.kubernetes.io/limit-connections`: number of concurrent connections allowed from a single IP address. A 503 error is returned when exceeding this limit.
* `nginx.ingress.kubernetes.io/limit-rps`: number of requests accepted from a given IP each second. The burst limit is set to 5 times the limit. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned.
* `nginx.ingress.kubernetes.io/limit-rpm`: number of requests accepted from a given IP each minute. The burst limit is set to 5 times the limit. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned.
* `nginx.ingress.kubernetes.io/limit-rps`: number of requests accepted from a given IP each second. The burst limit is set to this limit multiplied by the burst multiplier, the default multiplier is 5. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned.
* `nginx.ingress.kubernetes.io/limit-rpm`: number of requests accepted from a given IP each minute. The burst limit is set to this limit multiplied by the burst multiplier, the default multiplier is 5. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned.
* `nginx.ingress.kubernetes.io/limit-burst-multiplier`: multiplier of the limit rate for burst size. The default burst multiplier is 5, this annotation override the default multiplier. When clients exceed this limit, [limit-req-status-code](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#limit-req-status-code) ***default:*** 503 is returned.
* `nginx.ingress.kubernetes.io/limit-rate-after`: initial number of kilobytes after which the further transmission of a response to a given connection will be rate limited. This feature must be used with [proxy-buffering](#proxy-buffering) enabled.
* `nginx.ingress.kubernetes.io/limit-rate`: number of kilobytes per second allowed to send to a given connection. The zero value disables rate limiting. This feature must be used with [proxy-buffering](#proxy-buffering) enabled.
* `nginx.ingress.kubernetes.io/limit-whitelist`: client IP source ranges to be excluded from rate-limiting. The value is a comma separated list of CIDRs.
Expand Down
10 changes: 7 additions & 3 deletions internal/ingress/annotations/ratelimit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ func (a ratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
rpm, _ := parser.GetIntAnnotation("limit-rpm", ing)
rps, _ := parser.GetIntAnnotation("limit-rps", ing)
conn, _ := parser.GetIntAnnotation("limit-connections", ing)
burstMultiplier, err := parser.GetIntAnnotation("limit-burst-multiplier", ing)
if err != nil {
burstMultiplier = defBurst
}

val, _ := parser.GetStringAnnotation("limit-whitelist", ing)

Expand All @@ -181,19 +185,19 @@ func (a ratelimit) Parse(ing *networking.Ingress) (interface{}, error) {
Connections: Zone{
Name: fmt.Sprintf("%v_conn", zoneName),
Limit: conn,
Burst: conn * defBurst,
Burst: conn * burstMultiplier,
SharedSize: defSharedSize,
},
RPS: Zone{
Name: fmt.Sprintf("%v_rps", zoneName),
Limit: rps,
Burst: rps * defBurst,
Burst: rps * burstMultiplier,
SharedSize: defSharedSize,
},
RPM: Zone{
Name: fmt.Sprintf("%v_rpm", zoneName),
Limit: rpm,
Burst: rpm * defBurst,
Burst: rpm * burstMultiplier,
SharedSize: defSharedSize,
},
LimitRate: lr,
Expand Down
52 changes: 52 additions & 0 deletions internal/ingress/annotations/ratelimit/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,64 @@ func TestRateLimiting(t *testing.T) {
if rateLimit.Connections.Limit != 5 {
t.Errorf("expected 5 in limit by ip but %v was returend", rateLimit.Connections)
}
if rateLimit.Connections.Burst != 5*5 {
t.Errorf("expected %d in burst limit by ip but %v was returend", 5*3, rateLimit.Connections)
}
if rateLimit.RPS.Limit != 100 {
t.Errorf("expected 100 in limit by rps but %v was returend", rateLimit.RPS)
}
if rateLimit.RPS.Burst != 100*5 {
t.Errorf("expected %d in burst limit by rps but %v was returend", 100*3, rateLimit.RPS)
}
if rateLimit.RPM.Limit != 10 {
t.Errorf("expected 10 in limit by rpm but %v was returend", rateLimit.RPM)
}
if rateLimit.RPM.Burst != 10*5 {
t.Errorf("expected %d in burst limit by rpm but %v was returend", 10*3, rateLimit.RPM)
}
if rateLimit.LimitRateAfter != 100 {
t.Errorf("expected 100 in limit by limitrateafter but %v was returend", rateLimit.LimitRateAfter)
}
if rateLimit.LimitRate != 10 {
t.Errorf("expected 10 in limit by limitrate but %v was returend", rateLimit.LimitRate)
}

data = map[string]string{}
data[parser.GetAnnotationWithPrefix("limit-connections")] = "5"
data[parser.GetAnnotationWithPrefix("limit-rps")] = "100"
data[parser.GetAnnotationWithPrefix("limit-rpm")] = "10"
data[parser.GetAnnotationWithPrefix("limit-rate-after")] = "100"
data[parser.GetAnnotationWithPrefix("limit-rate")] = "10"
data[parser.GetAnnotationWithPrefix("limit-burst-multiplier")] = "3"

ing.SetAnnotations(data)

i, err = NewParser(mockBackend{}).Parse(ing)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
rateLimit, ok = i.(*Config)
if !ok {
t.Errorf("expected a RateLimit type")
}
if rateLimit.Connections.Limit != 5 {
t.Errorf("expected 5 in limit by ip but %v was returend", rateLimit.Connections)
}
if rateLimit.Connections.Burst != 5*3 {
t.Errorf("expected %d in burst limit by ip but %v was returend", 5*3, rateLimit.Connections)
}
if rateLimit.RPS.Limit != 100 {
t.Errorf("expected 100 in limit by rps but %v was returend", rateLimit.RPS)
}
if rateLimit.RPS.Burst != 100*3 {
t.Errorf("expected %d in burst limit by rps but %v was returend", 100*3, rateLimit.RPS)
}
if rateLimit.RPM.Limit != 10 {
t.Errorf("expected 10 in limit by rpm but %v was returend", rateLimit.RPM)
}
if rateLimit.RPM.Burst != 10*3 {
t.Errorf("expected %d in burst limit by rpm but %v was returend", 10*3, rateLimit.RPM)
}
if rateLimit.LimitRateAfter != 100 {
t.Errorf("expected 100 in limit by limitrateafter but %v was returend", rateLimit.LimitRateAfter)
}
Expand Down