Merge pull request #1210 from sethpollack/whitelist

add rate limit whitelist
This commit is contained in:
Manuel Alejandro de Brito Fontes 2017-08-22 08:23:45 -04:00 committed by GitHub
commit def5155aa6
4 changed files with 98 additions and 9 deletions

View file

@ -225,6 +225,8 @@ The annotations `ingress.kubernetes.io/limit-connections`, `ingress.kubernetes.i
`ingress.kubernetes.io/limit-rpm`: number of connections that may be accepted from a given IP each minute.
You can specify the client IP source ranges to be excluded from rate-limiting through the `ingress.kubernetes.io/limit-whitelist` annotation. The value is a comma separated list of CIDRs.
If you specify multiple annotations in a single Ingress rule, `limit-rpm`, and then `limit-rps` takes precedence.
The annotation `ingress.kubernetes.io/limit-rate`, `ingress.kubernetes.io/limit-rate-after` define a limit the rate of response transmission to a client. The rate is specified in bytes per second. The zero value disables rate limiting. The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit.
@ -239,7 +241,7 @@ To configure this setting globally for all Ingress rules, the `limit-rate-after`
The annotation `ingress.kubernetes.io/ssl-passthrough` allows to configure TLS termination in the pod and not in NGINX.
**Important:**
**Important:**
- Using the annotation `ingress.kubernetes.io/ssl-passthrough` invalidates all the other available annotations. This is because SSL Passthrough works in L4 (TCP).
- The use of this annotation requires the flag `--enable-ssl-passthrough` (By default it is disabled)

View file

@ -132,6 +132,7 @@ var (
"buildAuthLocation": buildAuthLocation,
"buildAuthResponseHeaders": buildAuthResponseHeaders,
"buildProxyPass": buildProxyPass,
"buildWhitelistVariable": buildWhitelistVariable,
"buildRateLimitZones": buildRateLimitZones,
"buildRateLimit": buildRateLimit,
"buildResolvers": buildResolvers,
@ -335,10 +336,23 @@ func buildProxyPass(host string, b interface{}, loc interface{}) string {
return defProxyPass
}
var (
whitelistVarMap = map[string]string{}
)
func buildWhitelistVariable(s string) string {
if _, ok := whitelistVarMap[s]; !ok {
str := base64.URLEncoding.EncodeToString([]byte(s))
whitelistVarMap[s] = strings.Replace(str, "=", "", -1)
}
return whitelistVarMap[s]
}
// buildRateLimitZones produces an array of limit_conn_zone in order to allow
// rate limiting of request. Each Ingress rule could have up to two zones, one
// for connection limit by IP address and other for limiting request per second
func buildRateLimitZones(variable string, input interface{}) []string {
func buildRateLimitZones(input interface{}) []string {
zones := sets.String{}
servers, ok := input.([]*ingress.Server)
@ -349,9 +363,11 @@ func buildRateLimitZones(variable string, input interface{}) []string {
for _, server := range servers {
for _, loc := range server.Locations {
whitelistVar := buildWhitelistVariable(loc.RateLimit.Name)
if loc.RateLimit.Connections.Limit > 0 {
zone := fmt.Sprintf("limit_conn_zone %v zone=%v:%vm;",
variable,
zone := fmt.Sprintf("limit_conn_zone $%s_limit zone=%v:%vm;",
whitelistVar,
loc.RateLimit.Connections.Name,
loc.RateLimit.Connections.SharedSize)
if !zones.Has(zone) {
@ -360,8 +376,8 @@ func buildRateLimitZones(variable string, input interface{}) []string {
}
if loc.RateLimit.RPM.Limit > 0 {
zone := fmt.Sprintf("limit_req_zone %v zone=%v:%vm rate=%vr/m;",
variable,
zone := fmt.Sprintf("limit_req_zone $%s_limit zone=%v:%vm rate=%vr/m;",
whitelistVar,
loc.RateLimit.RPM.Name,
loc.RateLimit.RPM.SharedSize,
loc.RateLimit.RPM.Limit)
@ -371,8 +387,8 @@ func buildRateLimitZones(variable string, input interface{}) []string {
}
if loc.RateLimit.RPS.Limit > 0 {
zone := fmt.Sprintf("limit_req_zone %v zone=%v:%vm rate=%vr/s;",
variable,
zone := fmt.Sprintf("limit_req_zone $%s_limit zone=%v:%vm rate=%vr/s;",
whitelistVar,
loc.RateLimit.RPS.Name,
loc.RateLimit.RPS.SharedSize,
loc.RateLimit.RPS.Limit)

View file

@ -288,12 +288,24 @@ http {
}
{{ end }}
{{ end }}
{{ if ne $location.RateLimit.Name "" }}
geo ${{ buildWhitelistVariable $location.RateLimit.Name }}_whitelist {
default 0;
{{ range $ip := $location.RateLimit.Whitelist }}
{{ $ip }} 1;{{ end }}
}
map ${{ buildWhitelistVariable $location.RateLimit.Name }}_whitelist ${{ buildWhitelistVariable $location.RateLimit.Name }}_limit {
0 {{ $cfg.LimitConnZoneVariable }};
1 "";
}
{{ end }}
{{ end }}
{{ end }}
{{/* build all the required rate limit zones. Each annotation requires a dedicated zone */}}
{{/* 1MB -> 16 thousand 64-byte states or about 8 thousand 128-byte states */}}
{{ range $zone := (buildRateLimitZones $cfg.LimitConnZoneVariable $servers) }}
{{ range $zone := (buildRateLimitZones $servers) }}
{{ $zone }}
{{ end }}