diff --git a/.changelog/2170.txt b/.changelog/2170.txt new file mode 100644 index 0000000000..6d10ae1097 --- /dev/null +++ b/.changelog/2170.txt @@ -0,0 +1,2 @@ +```release-note:feature +Add support for configuring global level server rate limiting. diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index f7dd85f166..1ad04a42b5 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -1,4 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} +{{- if (not (or (eq .Values.server.limits.requestLimits.mode "disabled") (eq .Values.server.limits.requestLimits.mode "permissive") (eq .Values.server.limits.requestLimits.mode "enforce"))) }}{{fail "server.limits.requestLimits.mode must be one of the following values: disabled, permissive, and enforce." }}{{ end -}} + # StatefulSet to run the actual Consul server cluster. apiVersion: v1 kind: ConfigMap @@ -26,6 +28,13 @@ data: "datacenter": "{{ .Values.global.datacenter }}", "data_dir": "/consul/data", "domain": "{{ .Values.global.domain }}", + "limits": { + "request_limits": { + "mode": "{{ .Values.server.limits.requestLimits.mode }}", + "read_rate": {{ .Values.server.limits.requestLimits.readRate }}, + "write_rate": {{ .Values.server.limits.requestLimits.writeRate }} + } + }, "ports": { {{- if not .Values.global.tls.enabled }} "grpc": 8502, diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 5e849d5a4f..2c8a83f4ca 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -965,3 +965,95 @@ load _helpers [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# server.limits.requestLimits + +@test "server/ConfigMap: server.limits.requestLimits.mode is disabled by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) + + [ "${actual}" = "disabled" ] +} + +@test "server/ConfigMap: server.limits.requestLimits.mode accepts disabled, permissive, and enforce" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.limits.requestLimits.mode=disabled' \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) + + [ "${actual}" = "disabled" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.limits.requestLimits.mode=permissive' \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) + + [ "${actual}" = "permissive" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.limits.requestLimits.mode=enforce' \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.mode | tee /dev/stderr) + + [ "${actual}" = "enforce" ] +} + +@test "server/ConfigMap: server.limits.requestLimits.mode errors with value other than disabled, permissive, and enforce" { + cd `chart_dir` + run helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.limits.requestLimits.mode=notvalid' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "server.limits.requestLimits.mode must be one of the following values: disabled, permissive, and enforce" ]] +} + +@test "server/ConfigMap: server.limits.request_limits.read_rate is -1 by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.read_rate | tee /dev/stderr) + + [ "${actual}" = "-1" ] +} + +@test "server/ConfigMap: server.limits.request_limits.read_rate is set properly when specified " { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.limits.requestLimits.readRate=100' \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.read_rate | tee /dev/stderr) + + [ "${actual}" = "100" ] +} + +@test "server/ConfigMap: server.limits.request_limits.write_rate is -1 by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.write_rate | tee /dev/stderr) + + [ "${actual}" = "-1" ] +} + +@test "server/ConfigMap: server.limits.request_limits.write_rate is set properly when specified " { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'server.limits.requestLimits.writeRate=100' \ + . | tee /dev/stderr | + yq -r '.data["server.json"]' | jq -r .limits.request_limits.write_rate | tee /dev/stderr) + + [ "${actual}" = "100" ] +} diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 2d21cf7c1e..f0a8b0112b 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -686,7 +686,7 @@ load _helpers -s templates/server-statefulset.yaml \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 251dd23c6cc44bf8362acddc24c78440b6a65c4618785d027fae526958af5dde ] + [ "${actual}" = 3714bf1fbca840dcd10b5aeb40c6ef35e349bd534727abe80b831c77f88da7da ] } @test "server/StatefulSet: adds config-checksum annotation when extraConfig is provided" { @@ -696,7 +696,7 @@ load _helpers --set 'server.extraConfig="{\"hello\": \"world\"}"' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 473d54d05b794be1526d42ef04fdc049f4f979a75d3394c897eef149d399207d ] + [ "${actual}" = 87126fac3c7704fba1d4265201ad0345f4d972d2123df6e6fb416b40c5823d80 ] } @test "server/StatefulSet: adds config-checksum annotation when config is updated" { @@ -706,7 +706,7 @@ load _helpers --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 6acd3761c0981d4d6194b3375b0f7a291e3927602ce7857344c26010381d3a61 ] + [ "${actual}" = d98ff135c5dee661058f33e29970675761ecf235676db0d4d24f354908eee425 ] } #-------------------------------------------------------------------- @@ -2773,4 +2773,4 @@ MIICFjCCAZsCCQCdwLtdjbzlYzAKBggqhkjOPQQDAjB0MQswCQYDVQQGEwJDQTEL' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[1].command[2] | contains("-interval=10h34m5s")' | tee /dev/stderr) [ "${actual}" = "true" ] -} \ No newline at end of file +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index edf36a41f0..a0660c5020 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1131,6 +1131,43 @@ server: # @type: string caCert: null + # Settings for potentially limiting timeouts, rate limiting on clients as well + # as servers, and other settings to limit exposure too many requests, requests + # waiting for too long, and other runtime considerations. + limits: + # This object specifies configurations that limit the rate of RPC and gRPC + # requests on the Consul server. Limiting the rate of gRPC and RPC requests + # also limits HTTP requests to the Consul server. + # https://developer.hashicorp.com/consul/docs/agent/config/config-files#request_limits + requestLimits: + # Setting for disabling or enabling rate limiting. If not disabled, it + # enforces the action that will occur when RequestLimitsReadRate + # or RequestLimitsWriteRate is exceeded. The default value of "disabled" will + # prevent any rate limiting from occuring. A value of "enforce" will block + # the request from processings by returning an error. A value of + # "permissive" will not block the request and will allow the request to + # continue processing. + # @type: string + mode: "disabled" + + # Setting that controls how frequently RPC, gRPC, and HTTP + # queries are allowed to happen. In any large enough time interval, rate + # limiter limits the rate to RequestLimitsReadRate tokens per second. + # + # See https://en.wikipedia.org/wiki/Token_bucket for more about token + # buckets. + # @type: integer + readRate: -1 + + # Setting that controls how frequently RPC, gRPC, and HTTP + # writes are allowed to happen. In any large enough time interval, rate + # limiter limits the rate to RequestLimitsWriteRate tokens per second. + # + # See https://en.wikipedia.org/wiki/Token_bucket for more about token + # buckets. + # @type: integer + writeRate: -1 + # Configuration for Consul servers when the servers are running outside of Kubernetes. # When running external servers, configuring these values is recommended # if setting `global.tls.enableAutoEncrypt` to true