diff options
author | Vladimir Shushlin <v.shushlin@gmail.com> | 2022-02-17 13:27:27 +0300 |
---|---|---|
committer | Vladimir Shushlin <v.shushlin@gmail.com> | 2022-02-21 16:44:20 +0300 |
commit | 62a6491652aa6975d9ecf3b9e258766c886d49d4 (patch) | |
tree | 18a2ddf45d3e997dbb8ea6a6c27a7da26d6f88be /test | |
parent | 92fb5e54ad42ed489c4dd93eec69fb5876d11efe (diff) |
feat: Add TLS rate limits
Changelog: added
Diffstat (limited to 'test')
-rw-r--r-- | test/acceptance/helpers_test.go | 12 | ||||
-rw-r--r-- | test/acceptance/ratelimiter_test.go | 157 |
2 files changed, 168 insertions, 1 deletions
diff --git a/test/acceptance/helpers_test.go b/test/acceptance/helpers_test.go index c44058ba..1b514a85 100644 --- a/test/acceptance/helpers_test.go +++ b/test/acceptance/helpers_test.go @@ -602,3 +602,15 @@ func copyFile(dest, src string) error { _, err = io.Copy(destFile, srcFile) return err } + +// RequireMetricEqual requests prometheus metrics and makes sure metric is there +func RequireMetricEqual(t *testing.T, metricsAddress, metricWithValue string) { + resp, err := http.Get(fmt.Sprintf("http://%s/metrics", metricsAddress)) + require.NoError(t, err) + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + require.Contains(t, string(body), metricWithValue) +} diff --git a/test/acceptance/ratelimiter_test.go b/test/acceptance/ratelimiter_test.go index 02ba54f5..365ba4cd 100644 --- a/test/acceptance/ratelimiter_test.go +++ b/test/acceptance/ratelimiter_test.go @@ -3,6 +3,7 @@ package acceptance_test import ( "fmt" "net/http" + "strconv" "testing" "time" @@ -77,7 +78,7 @@ func TestIPRateLimits(t *testing.T) { } } -func TestDomainateLimits(t *testing.T) { +func TestDomainRateLimits(t *testing.T) { testhelpers.StubFeatureFlagValue(t, feature.EnforceDomainRateLimits.EnvVariable, true) for name, tc := range ratelimitedListeners { @@ -112,6 +113,160 @@ func TestDomainateLimits(t *testing.T) { } } +func TestTLSRateLimits(t *testing.T) { + rateLimit := 5 + + tests := map[string]struct { + spec ListenSpec + options []processOption + sourceIP string + featureName string + enforceEnabled bool + limitName string + }{ + "https_with_domain_limit": { + spec: httpsListener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-domain", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-domain-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "127.0.0.1", + featureName: feature.EnforceDomainTLSRateLimits.EnvVariable, + enforceEnabled: true, + limitName: "tls_connections_by_domain", + }, + "https_with_domain_limit_not_enforced": { + spec: httpsListener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-domain", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-domain-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "127.0.0.1", + featureName: feature.EnforceDomainTLSRateLimits.EnvVariable, + enforceEnabled: false, + limitName: "tls_connections_by_domain", + }, + "https_with_ip_limit": { + spec: httpsListener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-source-ip", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-source-ip-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "127.0.0.1", + featureName: feature.EnforceIPTLSRateLimits.EnvVariable, + enforceEnabled: true, + limitName: "tls_connections_by_source_ip", + }, + "https_with_ip_limit_not_enforced": { + spec: httpsListener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-source-ip", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-source-ip-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "127.0.0.1", + featureName: feature.EnforceIPTLSRateLimits.EnvVariable, + enforceEnabled: false, + limitName: "tls_connections_by_source_ip", + }, + "proxyv2_with_domain_limit": { + spec: httpsProxyv2Listener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-domain", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-domain-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "10.1.1.1", + featureName: feature.EnforceDomainTLSRateLimits.EnvVariable, + enforceEnabled: true, + limitName: "tls_connections_by_domain", + }, + "proxyv2_with_domain_limit_not_enforced": { + spec: httpsProxyv2Listener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-domain", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-domain-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "10.1.1.1", + featureName: feature.EnforceDomainTLSRateLimits.EnvVariable, + enforceEnabled: false, + limitName: "tls_connections_by_domain", + }, + "proxyv2_with_ip_limit": { + spec: httpsProxyv2Listener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-source-ip", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-source-ip-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "10.1.1.1", + featureName: feature.EnforceIPTLSRateLimits.EnvVariable, + enforceEnabled: true, + limitName: "tls_connections_by_source_ip", + }, + "proxyv2_with_ip_limit_not_enforced": { + spec: httpsProxyv2Listener, + options: []processOption{ + withExtraArgument("metrics-address", ":42345"), + withExtraArgument("rate-limit-tls-source-ip", fmt.Sprint(rateLimit)), + withExtraArgument("rate-limit-tls-source-ip-burst", fmt.Sprint(rateLimit)), + }, + sourceIP: "10.1.1.1", + featureName: feature.EnforceIPTLSRateLimits.EnvVariable, + enforceEnabled: false, + limitName: "tls_connections_by_source_ip", + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + testhelpers.StubFeatureFlagValue(t, tt.featureName, tt.enforceEnabled) + + options := append(tt.options, withListeners([]ListenSpec{tt.spec})) + logBuf := RunPagesProcess(t, options...) + + for i := 0; i < 10; i++ { + rsp, err := makeTLSRequest(t, tt.spec) + + if i >= rateLimit { + assertLogFound(t, logBuf, []string{ + "TLS connection rate-limited", + "\"req_host\":\"group.gitlab-example.com\"", + fmt.Sprintf("\"source_ip\":\"%s\"", tt.sourceIP), + "\"enforced\":" + strconv.FormatBool(tt.enforceEnabled)}) + + if tt.enforceEnabled { + require.Error(t, err) + require.Contains(t, err.Error(), "remote error: tls: internal error") + } + + continue + } + + require.NoError(t, err) + require.NoError(t, rsp.Body.Close()) + require.Equal(t, http.StatusOK, rsp.StatusCode, "request: %d failed", i) + } + expectedMetric := fmt.Sprintf( + "gitlab_pages_rate_limit_blocked_count{enforced=\"%t\",limit_name=\"%s\"} 5", + tt.enforceEnabled, tt.limitName) + + RequireMetricEqual(t, "127.0.0.1:42345", expectedMetric) + }) + } +} + +func makeTLSRequest(t *testing.T, spec ListenSpec) (*http.Response, error) { + req, err := http.NewRequest("GET", "https://group.gitlab-example.com/project", nil) + require.NoError(t, err) + + return spec.Client().Do(req) +} + func assertLogFound(t *testing.T, logBuf *LogCaptureBuffer, expectedLogs []string) { t.Helper() |