Medium severity4.3GHSA Advisory· Published Oct 29, 2025· Updated Apr 15, 2026
CVE-2024-58269
CVE-2024-58269
Description
A vulnerability has been identified in Rancher Manager, where sensitive information, including secret data, cluster import URLs, and registration tokens, is exposed to any entity with access to Rancher audit logs.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/rancher/rancherGo | < 0.0.0-20251013203444-50dc516a19ea | 0.0.0-20251013203444-50dc516a19ea |
Affected products
1Patches
250dc516a19eaAdd additional redaction for some Request headers (#52297)
3 files changed · +216 −7
pkg/auth/audit/default_test.go+25 −5 modified@@ -43,11 +43,12 @@ func TestDefaultPolicies(t *testing.T) { machineDataWant[len(machineDataWant)-1] = byte('}') type testCase struct { - Name string - Uri string - Headers http.Header - Body []byte - ExpectedBody []byte + Name string + Uri string + Headers http.Header + ExpectedHeaders http.Header + Body []byte + ExpectedBody []byte } cases := []testCase{ @@ -509,6 +510,20 @@ func TestDefaultPolicies(t *testing.T) { Body: []byte(`{"normalField": "some data", "manifestUrl": "https://localhost:8443/v3/import/abcd.yaml", "insecureWindowsNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "insecureNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "insecureCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "command": "curl https://localhost:8443/v3/import/abcd.yaml", "windowsNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml"}`), ExpectedBody: []byte(fmt.Sprintf(`{"normalField": "some data", "manifestUrl": "%s", "insecureWindowsNodeCommand": "%[1]s", "insecureNodeCommand": "%[1]s", "insecureCommand": "%[1]s", "command": "%[1]s", "windowsNodeCommand": "%[1]s"}`, redacted)), }, + { + Name: "With redactable Referer header", + Headers: http.Header{"Content-Type": {contentTypeJSON}, "Referer": {"/v3/import/redactMe.yaml"}}, + ExpectedHeaders: http.Header{"Content-Type": {contentTypeJSON}, "Referer": {"/v3/import/[redacted]"}}, + Body: []byte(`{"normalField": "some data", "manifestUrl": "https://localhost:8443/v3/import/abcd.yaml", "insecureWindowsNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "insecureNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "insecureCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "command": "curl https://localhost:8443/v3/import/abcd.yaml", "windowsNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"normalField": "some data", "manifestUrl": "%s", "insecureWindowsNodeCommand": "%[1]s", "insecureNodeCommand": "%[1]s", "insecureCommand": "%[1]s", "command": "%[1]s", "windowsNodeCommand": "%[1]s"}`, redacted)), + }, + { + Name: "With non-redactable Referrer header", + Headers: http.Header{"Content-Type": {contentTypeJSON}, "Referrer": {"/v3/import/redactMe.yaml"}}, + ExpectedHeaders: http.Header{"Content-Type": {contentTypeJSON}, "Referrer": {"/v3/import/redactMe.yaml"}}, + Body: []byte(`{"normalField": "some data", "manifestUrl": "https://localhost:8443/v3/import/abcd.yaml", "insecureWindowsNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "insecureNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "insecureCommand": "curl https://localhost:8443/v3/import/abcd.yaml", "command": "curl https://localhost:8443/v3/import/abcd.yaml", "windowsNodeCommand": "curl https://localhost:8443/v3/import/abcd.yaml"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"normalField": "some data", "manifestUrl": "%s", "insecureWindowsNodeCommand": "%[1]s", "insecureNodeCommand": "%[1]s", "insecureCommand": "%[1]s", "command": "%[1]s", "windowsNodeCommand": "%[1]s"}`, redacted)), + }, } buffer := bytes.NewBuffer(nil) @@ -540,6 +555,11 @@ func TestDefaultPolicies(t *testing.T) { assert.Equal(t, expected, actual) + if c.ExpectedHeaders != nil { + actualHeaders := log.RequestHeader + assert.Equal(t, c.ExpectedHeaders, actualHeaders) + } + buffer.Reset() }) }
pkg/auth/audit/redact.go+46 −2 modified@@ -8,6 +8,7 @@ import ( jsonpath "github.com/rancher/jsonpath/pkg" auditlogv1 "github.com/rancher/rancher/pkg/apis/auditlog.cattle.io/v1" + "github.com/rancher/rancher/pkg/settings" ) const ( @@ -231,10 +232,53 @@ func regexRedactor(patterns []string) (Redactor, error) { }), nil } +const ( + redactPrefix = "/v3/import" + redactedImportUrl = redactPrefix + "/" + redacted + refererHeader = "Referer" +) + func redactImportUrl(l *log) error { - if strings.HasPrefix(l.RequestURI, "/v3/import") { - l.RequestURI = "/v3/import/" + redacted + l.RequestURI = redactImportUrlPath(l.RequestURI) + + if err := redactImportUrlHeader(l, refererHeader); err != nil { + return err + } + + return nil +} + +func redactImportUrlPath(path string) string { + if strings.HasPrefix(path, redactPrefix) { + return redactedImportUrl + } + + return path +} + +func redactImportUrlHeader(l *log, headerName string) error { + referrer, ok := l.RequestHeader[headerName] + if !ok { + return nil + } + l.RequestHeader.Del(headerName) + + for _, ref := range referrer { + l.RequestHeader.Add(headerName, redactImportUrlString(ref)) } return nil } + +func redactImportUrlString(urlIn string) string { + serverUrl := settings.ServerURL.Get() + redactIndex := strings.Index(urlIn, serverUrl) + if redactIndex == -1 { + return urlIn + } + + pathIndex := redactIndex + len(serverUrl) + urlPath := urlIn[pathIndex:] + + return urlIn[:pathIndex] + redactImportUrlPath(urlPath) +}
pkg/auth/audit/redact_test.go+145 −0 modified@@ -4,6 +4,7 @@ import ( "testing" auditlogv1 "github.com/rancher/rancher/pkg/apis/auditlog.cattle.io/v1" + "github.com/rancher/rancher/pkg/settings" "github.com/stretchr/testify/assert" ) @@ -152,3 +153,147 @@ func TestPolicyRedactor(t *testing.T) { }) } } + +const ( + redactableV3URL = "/v3/import/redactME.yaml" + expectedV3RedactedURL = "/v3/import/[redacted]" +) + +func Test_redactImportUrlPath(t *testing.T) { + cases := []struct { + input string + expected string + }{ + { + "/v3/import", + expectedV3RedactedURL, + }, + { + "/v3/import/", + expectedV3RedactedURL, + }, + { + redactableV3URL, + expectedV3RedactedURL, + }, + { + "/foo/bar" + redactableV3URL, + "/foo/bar" + redactableV3URL, + }, + { + "/v3/import/yellow.yaml", + expectedV3RedactedURL, + }, + { + "/v4/import/redactME.yaml", + "/v4/import/redactME.yaml", + }, + } + + for _, tt := range cases { + tt := tt + t.Run(tt.input, func(t *testing.T) { + assert.Equal(t, tt.expected, redactImportUrlPath(tt.input)) + }) + } + + noRedaction := redactImportUrlPath("/v4/import/redactME.yaml") + assert.Equal(t, noRedaction, "/v4/import/redactME.yaml") + assert.NotEqual(t, noRedaction, expectedV3RedactedURL) +} + +const testingServerURL = "https://127.0.0.1.sslip.io:8443" + +func Test_redactImportUrlString(t *testing.T) { + asserts := assert.New(t) + + cases := []struct { + input string + serverUrl string + expected string + }{ + { + testingServerURL + "/v3/import", + testingServerURL, + testingServerURL + expectedV3RedactedURL, + }, + { + testingServerURL + "/v3/import/", + testingServerURL, + testingServerURL + expectedV3RedactedURL, + }, + { + testingServerURL + redactableV3URL, + testingServerURL, + testingServerURL + expectedV3RedactedURL, + }, + { + testingServerURL + "/foo/bar" + redactableV3URL, + testingServerURL, + testingServerURL + "/foo/bar" + redactableV3URL, + }, + { + testingServerURL + "/v3/import/yellow.yaml", + testingServerURL, + testingServerURL + expectedV3RedactedURL, + }, + { + testingServerURL + "/v4/import/will-not-redactME.yaml", + testingServerURL, + testingServerURL + "/v4/import/will-not-redactME.yaml", + }, + { + "https://some-other-domain.localhost/v4/import/will-not-redactME.yaml", + testingServerURL, + "https://some-other-domain.localhost/v4/import/will-not-redactME.yaml", + }, + } + + for _, tt := range cases { + tt := tt + t.Run(tt.input, func(t *testing.T) { + originalServerURL := settings.ServerURL.Get() + + _ = settings.ServerURL.Set(tt.serverUrl) + asserts.Equal(tt.expected, redactImportUrlString(tt.input)) + + t.Cleanup(func() { + _ = settings.ServerURL.Set(originalServerURL) + }) + }) + } + +} + +func Test_redactImportUrl(t *testing.T) { + asserts := assert.New(t) + originalServerURL := settings.ServerURL.Get() + + testLog := sampleLog() + asserts.Equal("", testLog.RequestURI) + + referrerHeader := testLog.RequestHeader.Get(refererHeader) + asserts.Equal("", referrerHeader) + + _ = settings.ServerURL.Set(testingServerURL) + + testLog.RequestURI = redactableV3URL + asserts.Equal(redactableV3URL, testLog.RequestURI) + + testLog.RequestHeader.Set(refererHeader, testingServerURL+redactableV3URL) + referrerHeader = testLog.RequestHeader.Get(refererHeader) + asserts.Equal(testingServerURL+redactableV3URL, referrerHeader) + + err := redactImportUrl(&testLog) + asserts.NoError(err) + asserts.NotEqual(redactableV3URL, testLog.RequestURI) + asserts.Equal(expectedV3RedactedURL, testLog.RequestURI) + + referrerHeader = testLog.RequestHeader.Get(refererHeader) + asserts.NotEqual(redactableV3URL, referrerHeader) + asserts.Equal(testingServerURL+expectedV3RedactedURL, referrerHeader) + + t.Cleanup(func() { + _ = settings.ServerURL.Set(originalServerURL) + }) +}
26ad9216e94fImprove how auditlog handles specific redactions (#52301)
3 files changed · +301 −293
pkg/auth/audit/default.go+1 −1 modified@@ -116,7 +116,7 @@ func DefaultPolicies() []auditlogv1.AuditPolicy { AdditionalRedactions: []auditlogv1.Redaction{ { Paths: []string{ - "$.metadata.annotations['kubectl.kubernetes.io/last-applied-configuration']", + "$..metadata.annotations['kubectl.kubernetes.io/last-applied-configuration']", }, }, },
pkg/auth/audit/default_test.go+299 −291 modified@@ -43,463 +43,471 @@ func TestDefaultPolicies(t *testing.T) { machineDataWant[len(machineDataWant)-1] = byte('}') type testCase struct { - Name string - Uri string - Headers http.Header - Body []byte - Expected []byte + Name string + Uri string + Headers http.Header + Body []byte + ExpectedBody []byte } cases := []testCase{ { - Name: "password entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"password":"fake_password","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), + Name: "password entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"password":"fake_password","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Password entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"Password":"fake_password","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), + Name: "Password entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"Password":"fake_password","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "password entry no space", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"password":"whatever you want","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), + Name: "password entry no space", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"password":"whatever you want","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Password entry no space", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"Password":"A whole bunch of \"\"}{()","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), + Name: "Password entry no space", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"Password":"A whole bunch of \"\"}{()","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "currentPassword entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"currentPassword":"something super secret","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"currentPassword":"%s","user":"fake_user"}`, redacted)), + Name: "currentPassword entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"currentPassword":"something super secret","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"currentPassword":"%s","user":"fake_user"}`, redacted)), }, { - Name: "newPassword entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"newPassword":"don't share this","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"newPassword":"%s","user":"fake_user"}`, redacted)), + Name: "newPassword entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"newPassword":"don't share this","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"newPassword":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Multiple password entries", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"currentPassword":"fake_password","newPassword":"new_fake_password","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"currentPassword":"%s","newPassword":"%[1]s","user":"fake_user"}`, redacted)), + Name: "Multiple password entries", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"currentPassword":"fake_password","newPassword":"new_fake_password","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"currentPassword":"%s","newPassword":"%[1]s","user":"fake_user"}`, redacted)), }, { - Name: "No password entries", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), - Expected: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), + Name: "No password entries", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), + ExpectedBody: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), }, { - Name: "Strategic password examples", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"anotherPassword":"\"password\"","currentPassword":"password\":","newPassword":"newPassword\\\":","shortPassword":"'","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"anotherPassword":"%s","currentPassword":"%[1]s","newPassword":"%[1]s","shortPassword":"%[1]s","user":"fake_user"}`, redacted)), + Name: "Strategic password examples", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"anotherPassword":"\"password\"","currentPassword":"password\":","newPassword":"newPassword\\\":","shortPassword":"'","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"anotherPassword":"%s","currentPassword":"%[1]s","newPassword":"%[1]s","shortPassword":"%[1]s","user":"fake_user"}`, redacted)), }, { - Name: "Token entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"accessToken":"fake_access_token","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"accessToken":"%s","user":"fake_user"}`, redacted)), + Name: "Token entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"accessToken":"fake_access_token","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"accessToken":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Token entry in slice", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"data":[{"accessToken":"fake_access_token","user":"fake_user"}]}`), - Expected: []byte(fmt.Sprintf(`{"data":[{"accessToken":"%s","user":"fake_user"}]}`, redacted)), + Name: "Token entry in slice", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"data":[{"accessToken":"fake_access_token","user":"fake_user"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":[{"accessToken":"%s","user":"fake_user"}]}`, redacted)), }, { - Name: "Token entry in args slice", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"data":{"commands":["--user","user","--token","sometoken"]}}`), - Expected: []byte(fmt.Sprintf(`{"data":{"commands":["--user","user","--token","%s"]}}`, redacted)), + Name: "Token entry in args slice", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"data":{"commands":["--user","user","--token","sometoken"]}}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":{"commands":["--user","user","--token","%s"]}}`, redacted)), }, { - Name: "Token entry in args slice but is last element of slice", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"data":{"commands":["--user","user","--token"]}}`), - Expected: []byte(`{"data":{"commands":["--user","user","--token"]}}`), + Name: "Token entry in args slice but is last element of slice", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"data":{"commands":["--user","user","--token"]}}`), + ExpectedBody: []byte(`{"data":{"commands":["--user","user","--token"]}}`), }, { - Name: "With public fields", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"accessKey":"fake_access_key","secretKey":"fake_secret_key","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"accessKey":"fake_access_key","secretKey":"%s","user":"fake_user"}`, redacted)), + Name: "With public fields", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"accessKey":"fake_access_key","secretKey":"fake_secret_key","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"accessKey":"fake_access_key","secretKey":"%s","user":"fake_user"}`, redacted)), }, { - Name: "With secret data", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), - Expected: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s","accessToken" :"%[1]s"}`, redacted)), + Name: "With secret data", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s","accessToken" :"%[1]s"}`, redacted)), }, { - Name: "With secret list data", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), - Expected: []byte(fmt.Sprintf(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":"%[1]s"}]}`, redacted)), - Uri: "/v1/secrets", + Name: "With secret list data", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":"%[1]s"}]}`, redacted)), + Uri: "/v1/secrets", }, { // norman transforms some secret subtypes to where their data fields cannot be distinguished from non-sensitive fields. // In this case, all fields aside from id, created, and baseType should be redacted. - Name: "With secret list data but no data field for array elements", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"collection","data":[{"id":"p-12345:testsecret","baseType":"secret","type":"Opaque","_type":"Opaque","foo":"something","bar":"something","accessToken":"token"}]}`), - Expected: []byte(fmt.Sprintf(`{"data":[{"_type":"%s","accessToken":"%[1]s","bar":"%[1]s","baseType":"secret","foo":"%[1]s","id":"p-12345:testsecret","type":"%[1]s"}],"type":"collection"}`, redacted)), + Name: "With secret list data but no data field for array elements", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"collection","data":[{"id":"p-12345:testsecret","baseType":"secret","type":"Opaque","_type":"Opaque","foo":"something","bar":"something","accessToken":"token"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":[{"_type":"%s","accessToken":"%[1]s","bar":"%[1]s","baseType":"secret","foo":"%[1]s","id":"p-12345:testsecret","type":"%[1]s"}],"type":"collection"}`, redacted)), }, { - Name: "With secret list data from k8s proxy", - Uri: "/k8s/clusters/local/api/v1/secrets?limit=500", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), - Expected: []byte(fmt.Sprintf(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"}]}`, redacted)), + Name: "With secret list data from k8s proxy", + Uri: "/k8s/clusters/local/api/v1/secrets?limit=500", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"}]}`, redacted)), }, { - Name: "With secret data and wrong URI", - Uri: "/not-secret", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), - Expected: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"%s"}`, redacted)), + Name: "With secret data and wrong URI", + Uri: "/not-secret", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"%s"}`, redacted)), }, { - Name: "With nested sensitive information", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"sensitiveData": {"accessToken":"fake_access_token","user":"fake_user"}}`), - Expected: []byte(fmt.Sprintf(`{"sensitiveData": {"accessToken":"%s","user":"fake_user"}}`, redacted)), + Name: "With nested sensitive information", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"sensitiveData": {"accessToken":"fake_access_token","user":"fake_user"}}`), + ExpectedBody: []byte(fmt.Sprintf(`{"sensitiveData": {"accessToken":"%s","user":"fake_user"}}`, redacted)), }, { - Name: "With all machine driver fields", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: machineDataInput, - Expected: machineDataWant, + Name: "With all machine driver fields", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: machineDataInput, + ExpectedBody: machineDataWant, }, { - Name: "With no secret uri but secret base type slice", - Uri: `/v3/project/local:p-12345/namespacedcertificates?limit=-1&sort=name`, - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":{"testfield":"somesecretencodeddata"},"id":"cattle-system:test","kind":"Opaque"}]}`), - Expected: []byte(fmt.Sprintf(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":"%s","id":"cattle-system:test","kind":"Opaque"}]}`, redacted)), + Name: "With no secret uri but secret base type slice", + Uri: `/v3/project/local:p-12345/namespacedcertificates?limit=-1&sort=name`, + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":{"testfield":"somesecretencodeddata"},"id":"cattle-system:test","kind":"Opaque"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":"%s","id":"cattle-system:test","kind":"Opaque"}]}`, redacted)), }, { - Name: "With kubeconfig from generateKubeconfig action", - Uri: `/v3/clusters/c-xxxxx?action=generateKubeconfig`, - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"baseType":"generateKubeConfigOutput","config":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","type":"generateKubeConfigOutput"}`), - Expected: []byte(fmt.Sprintf(`{"baseType":"generateKubeConfigOutput","config":"%s","type":"generateKubeConfigOutput"}`, redacted)), + Name: "With kubeconfig from generateKubeconfig action", + Uri: `/v3/clusters/c-xxxxx?action=generateKubeconfig`, + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"baseType":"generateKubeConfigOutput","config":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","type":"generateKubeConfigOutput"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"baseType":"generateKubeConfigOutput","config":"%s","type":"generateKubeConfigOutput"}`, redacted)), }, { - Name: "With kubeconfig from connect agent", - Uri: `/v3/connect/agent`, - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), - Expected: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), + Name: "With kubeconfig from connect agent", + Uri: `/v3/connect/agent`, + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), }, { - Name: "With kubeconfig from random request", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), - Expected: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), + Name: "With kubeconfig from random request", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), }, { - Name: "With items from sensitiveBodyFields", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"credentials":"{'fakeCredName': 'fakeCred'}","applicationSecret":"fakeAppSecret","oauthCredential":"fakeOauth","serviceAccountCredential":"fakeSACred","spKey":"fakeSPKey","spCert":"fakeSPCERT","certificate":"fakeCert","privateKey":"fakeKey"}`), - Expected: []byte(fmt.Sprintf(`{"credentials":"%s","applicationSecret":"%[1]s","oauthCredential":"%[1]s","serviceAccountCredential":"%[1]s","spKey":"%[1]s","spCert":"%[1]s","certificate":"%[1]s","privateKey":"%[1]s"}`, redacted)), + Name: "With items from sensitiveBodyFields", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"credentials":"{'fakeCredName': 'fakeCred'}","applicationSecret":"fakeAppSecret","oauthCredential":"fakeOauth","serviceAccountCredential":"fakeSACred","spKey":"fakeSPKey","spCert":"fakeSPCERT","certificate":"fakeCert","privateKey":"fakeKey"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"credentials":"%s","applicationSecret":"%[1]s","oauthCredential":"%[1]s","serviceAccountCredential":"%[1]s","spKey":"%[1]s","spCert":"%[1]s","certificate":"%[1]s","privateKey":"%[1]s"}`, redacted)), }, { - Name: "With malformed input", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"key":"value","response":}`), - Expected: []byte(fmt.Sprintf(`{"%s":"failed to unmarshal request body: invalid character '}' looking for beginning of value"}`, auditLogErrorKey)), + Name: "With malformed input", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"key":"value","response":}`), + ExpectedBody: []byte(fmt.Sprintf(`{"%s":"failed to unmarshal request body: invalid character '}' looking for beginning of value"}`, auditLogErrorKey)), }, { - Name: "With secret string data with last-applied-configuration annotation", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"apiVersion": "v1", "stringData": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"stringData\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), - Expected: []byte(fmt.Sprintf(`{"apiVersion": "v1", "stringData": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), + Name: "With secret string data with last-applied-configuration annotation", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"apiVersion": "v1", "stringData": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"stringData\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"apiVersion": "v1", "stringData": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), }, { - Name: "With secret data with last-applied-configuration annotation", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"apiVersion": "v1", "data": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"data\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), - Expected: []byte(fmt.Sprintf(`{"apiVersion": "v1", "data": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), + Name: "With secret data with last-applied-configuration annotation", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"apiVersion": "v1", "data": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"data\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"apiVersion": "v1", "data": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), }, { - Name: "password entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"password":"fake_password","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), + Name: "password entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"password":"fake_password","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Password entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"Password":"fake_password","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), + Name: "Password entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"Password":"fake_password","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "password entry no space", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"password":"whatever you want","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), + Name: "password entry no space", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"password":"whatever you want","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Password entry no space", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"Password":"A whole bunch of \"\"}{()","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), + Name: "Password entry no space", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"Password":"A whole bunch of \"\"}{()","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"Password":"%s","user":"fake_user"}`, redacted)), }, { - Name: "currentPassword entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"currentPassword":"something super secret","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"currentPassword":"%s","user":"fake_user"}`, redacted)), + Name: "currentPassword entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"currentPassword":"something super secret","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"currentPassword":"%s","user":"fake_user"}`, redacted)), }, { - Name: "newPassword entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"newPassword":"don't share this","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"newPassword":"%s","user":"fake_user"}`, redacted)), + Name: "newPassword entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"newPassword":"don't share this","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"newPassword":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Multiple password entries", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"currentPassword":"fake_password","newPassword":"new_fake_password","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"currentPassword":"%s","newPassword":"%[1]s","user":"fake_user"}`, redacted)), + Name: "Multiple password entries", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"currentPassword":"fake_password","newPassword":"new_fake_password","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"currentPassword":"%s","newPassword":"%[1]s","user":"fake_user"}`, redacted)), }, { - Name: "No password entries", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), - Expected: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), + Name: "No password entries", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), + ExpectedBody: []byte(`{"user":"fake_user","user_info":"some information about the user","request_info":"some info about the request"}`), }, { - Name: "Strategic password examples", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"anotherPassword":"\"password\"","currentPassword":"password\":","newPassword":"newPassword\\\":","shortPassword":"'","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"anotherPassword":"%s","currentPassword":"%[1]s","newPassword":"%[1]s","shortPassword":"%[1]s","user":"fake_user"}`, redacted)), + Name: "Strategic password examples", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"anotherPassword":"\"password\"","currentPassword":"password\":","newPassword":"newPassword\\\":","shortPassword":"'","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"anotherPassword":"%s","currentPassword":"%[1]s","newPassword":"%[1]s","shortPassword":"%[1]s","user":"fake_user"}`, redacted)), }, { - Name: "Token entry", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"accessToken":"fake_access_token","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"accessToken":"%s","user":"fake_user"}`, redacted)), + Name: "Token entry", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"accessToken":"fake_access_token","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"accessToken":"%s","user":"fake_user"}`, redacted)), }, { - Name: "Token entry in slice", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"data":[{"accessToken":"fake_access_token","user":"fake_user"}]}`), - Expected: []byte(fmt.Sprintf(`{"data":[{"accessToken":"%s","user":"fake_user"}]}`, redacted)), + Name: "Token entry in slice", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"data":[{"accessToken":"fake_access_token","user":"fake_user"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":[{"accessToken":"%s","user":"fake_user"}]}`, redacted)), }, { - Name: "Token entry in args slice", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"data":{"commands":["--user","user","--token","sometoken"]}}`), - Expected: []byte(fmt.Sprintf(`{"data":{"commands":["--user","user","--token","%s"]}}`, redacted)), + Name: "Token entry in args slice", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"data":{"commands":["--user","user","--token","sometoken"]}}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":{"commands":["--user","user","--token","%s"]}}`, redacted)), }, { - Name: "Token entry in args slice but is last element of slice", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"data":{"commands":["--user","user","--token"]}}`), - Expected: []byte(`{"data":{"commands":["--user","user","--token"]}}`), + Name: "Token entry in args slice but is last element of slice", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"data":{"commands":["--user","user","--token"]}}`), + ExpectedBody: []byte(`{"data":{"commands":["--user","user","--token"]}}`), }, { - Name: "With public fields", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"accessKey":"fake_access_key","secretKey":"fake_secret_key","user":"fake_user"}`), - Expected: []byte(fmt.Sprintf(`{"accessKey":"fake_access_key","secretKey":"%s","user":"fake_user"}`, redacted)), + Name: "With public fields", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"accessKey":"fake_access_key","secretKey":"fake_secret_key","user":"fake_user"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"accessKey":"fake_access_key","secretKey":"%s","user":"fake_user"}`, redacted)), }, { - Name: "With secret data", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), - Expected: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s","accessToken" :"%[1]s"}`, redacted)), + Name: "With secret data", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s","accessToken" :"%[1]s"}`, redacted)), }, { - Name: "With secret list data", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), - Expected: []byte(fmt.Sprintf(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":"%[1]s"}]}`, redacted)), - Uri: "/v1/secrets", + Name: "With secret list data", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"collection","data":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"},{"type":"Opaque","metadata":{"namespace":"default","name":"my secret2"},"_type":"Opaque","data":"%[1]s"}]}`, redacted)), + Uri: "/v1/secrets", }, { // norman transforms some secret subtypes to where their data fields cannot be distinguished from non-sensitive fields. // In this case, all fields aside from id, created, and baseType should be redacted. - Name: "With secret list data but no data field for array elements", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"collection","data":[{"id":"p-12345:testsecret","baseType":"secret","type":"Opaque","_type":"Opaque","foo":"something","bar":"something","accessToken":"token"}]}`), - Expected: []byte(fmt.Sprintf(`{"data":[{"_type":"%s","accessToken":"%[1]s","bar":"%[1]s","baseType":"secret","foo":"%[1]s","id":"p-12345:testsecret","type":"%[1]s"}],"type":"collection"}`, redacted)), + Name: "With secret list data but no data field for array elements", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"collection","data":[{"id":"p-12345:testsecret","baseType":"secret","type":"Opaque","_type":"Opaque","foo":"something","bar":"something","accessToken":"token"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":[{"_type":"%s","accessToken":"%[1]s","bar":"%[1]s","baseType":"secret","foo":"%[1]s","id":"p-12345:testsecret","type":"%[1]s"}],"type":"collection"}`, redacted)), }, { - Name: "With secret list data from k8s proxy", - Uri: "/k8s/clusters/local/api/v1/secrets?limit=500", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), - Expected: []byte(fmt.Sprintf(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"}]}`, redacted)), + Name: "With secret list data from k8s proxy", + Uri: "/k8s/clusters/local/api/v1/secrets?limit=500", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kind":"SecretList","items":[{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":"%s"}]}`, redacted)), }, { - Name: "With secret data and wrong URI", - Uri: "/not-secret", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), - Expected: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"%s"}`, redacted)), + Name: "With secret data and wrong URI", + Uri: "/not-secret", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"fake_access_token"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"Opaque","metadata":{"namespace":"default","name":"my secret"},"_type":"Opaque","data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\","bar":"U3VwZXIgU2VjcmV0IERhdGEK"},"accessToken" :"%s"}`, redacted)), }, { - Name: "With nested sensitive information", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"sensitiveData": {"accessToken":"fake_access_token","user":"fake_user"}}`), - Expected: []byte(fmt.Sprintf(`{"sensitiveData": {"accessToken":"%s","user":"fake_user"}}`, redacted)), + Name: "With nested sensitive information", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"sensitiveData": {"accessToken":"fake_access_token","user":"fake_user"}}`), + ExpectedBody: []byte(fmt.Sprintf(`{"sensitiveData": {"accessToken":"%s","user":"fake_user"}}`, redacted)), }, { - Name: "With all machine driver fields", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: machineDataInput, - Expected: machineDataWant, + Name: "With all machine driver fields", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: machineDataInput, + ExpectedBody: machineDataWant, }, { - Name: "With no secret uri but secret base type slice", - Uri: `/v3/project/local:p-12345/namespacedcertificates?limit=-1&sort=name`, - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":{"testfield":"somesecretencodeddata"},"id":"cattle-system:test","kind":"Opaque"}]}`), - Expected: []byte(fmt.Sprintf(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":"%s","id":"cattle-system:test","kind":"Opaque"}]}`, redacted)), + Name: "With no secret uri but secret base type slice", + Uri: `/v3/project/local:p-12345/namespacedcertificates?limit=-1&sort=name`, + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":{"testfield":"somesecretencodeddata"},"id":"cattle-system:test","kind":"Opaque"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type":"collection","data":[{"baseType":"namespacedSecret","creatorId":null,"data":"%s","id":"cattle-system:test","kind":"Opaque"}]}`, redacted)), }, { - Name: "With kubeconfig from generateKubeconfig action", - Uri: `/v3/clusters/c-xxxxx?action=generateKubeconfig`, - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"baseType":"generateKubeConfigOutput","config":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","type":"generateKubeConfigOutput"}`), - Expected: []byte(fmt.Sprintf(`{"baseType":"generateKubeConfigOutput","config":"%s","type":"generateKubeConfigOutput"}`, redacted)), + Name: "With kubeconfig from generateKubeconfig action", + Uri: `/v3/clusters/c-xxxxx?action=generateKubeconfig`, + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"baseType":"generateKubeConfigOutput","config":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","type":"generateKubeConfigOutput"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"baseType":"generateKubeConfigOutput","config":"%s","type":"generateKubeConfigOutput"}`, redacted)), }, { - Name: "With kubeconfig from connect agent", - Uri: `/v3/connect/agent`, - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), - Expected: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), + Name: "With kubeconfig from connect agent", + Uri: `/v3/connect/agent`, + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), }, { - Name: "With kubeconfig from random request", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), - Expected: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), + Name: "With kubeconfig from random request", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kubeConfig":"apiVersion: v1\nkind: Config\nclusters:\n- name: \"somecluster-rke\"\n cluster:\n server: \"https://rancherurl.com/k8s/clusters/c-xxxxx\"\n- name: \"somecluster-rke-somecluster-rke1\"\n cluster:\n server: \"https://34.211.205.110:6443\"\n certificate-authority-data: \"somecadata\"\n\nusers:\n- name: \"somecluster-rke\"\n user:\n token: \"kubeconfig-user-12345:sometoken\"\n\n\ncontexts:\n- name: \"somecluster-rke\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke\"\n- name: \"somecluster-rke-somecluster-rke1\"\n context:\n user: \"somecluster-rke\"\n cluster: \"somecluster-rke-somecluster-rke1\"\n\ncurrent-context: \"somecluster-rke\"\n","namespace":"testns","secretName":"secret-name"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kubeConfig":"%s","namespace":"testns","secretName":"secret-name"}`, redacted)), }, { - Name: "With items from sensitiveBodyFields", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"credentials":"{'fakeCredName': 'fakeCred'}","applicationSecret":"fakeAppSecret","oauthCredential":"fakeOauth","serviceAccountCredential":"fakeSACred","spKey":"fakeSPKey","spCert":"fakeSPCERT","certificate":"fakeCert","privateKey":"fakeKey"}`), - Expected: []byte(fmt.Sprintf(`{"credentials":"%s","applicationSecret":"%[1]s","oauthCredential":"%[1]s","serviceAccountCredential":"%[1]s","spKey":"%[1]s","spCert":"%[1]s","certificate":"%[1]s","privateKey":"%[1]s"}`, redacted)), + Name: "With items from sensitiveBodyFields", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"credentials":"{'fakeCredName': 'fakeCred'}","applicationSecret":"fakeAppSecret","oauthCredential":"fakeOauth","serviceAccountCredential":"fakeSACred","spKey":"fakeSPKey","spCert":"fakeSPCERT","certificate":"fakeCert","privateKey":"fakeKey"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"credentials":"%s","applicationSecret":"%[1]s","oauthCredential":"%[1]s","serviceAccountCredential":"%[1]s","spKey":"%[1]s","spCert":"%[1]s","certificate":"%[1]s","privateKey":"%[1]s"}`, redacted)), }, { - Name: "With malformed input", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"key":"value","response":}`), - Expected: []byte(fmt.Sprintf(`{"%s":"failed to unmarshal request body: invalid character '}' looking for beginning of value"}`, auditLogErrorKey)), + Name: "With malformed input", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"key":"value","response":}`), + ExpectedBody: []byte(fmt.Sprintf(`{"%s":"failed to unmarshal request body: invalid character '}' looking for beginning of value"}`, auditLogErrorKey)), }, { - Name: "With secret string data with last-applied-configuration annotation", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"apiVersion": "v1", "stringData": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"stringData\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), - Expected: []byte(fmt.Sprintf(`{"apiVersion": "v1", "stringData": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), + Name: "With secret string data with last-applied-configuration annotation", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"apiVersion": "v1", "stringData": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"stringData\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"apiVersion": "v1", "stringData": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), }, { - Name: "With secret data with last-applied-configuration annotation", - Uri: "/secrets", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"apiVersion": "v1", "data": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"data\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), - Expected: []byte(fmt.Sprintf(`{"apiVersion": "v1", "data": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), + Name: "With secret data with last-applied-configuration annotation", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"apiVersion": "v1", "data": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"data\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"apiVersion": "v1", "data": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}`, redacted)), }, { - Name: "With configmap data", - Uri: "/configmaps", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}, "accessToken" : "fake_access_token"}`), - Expected: []byte(fmt.Sprintf(`{"metadata":{"namespace":"default","name":"my_configmap"},"data":"%s", "accessToken" : "%[1]s"}`, redacted)), + Name: "With secret list with last-applied-configuration annotation", + Uri: "/secrets", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type": "collection", "data": [{"apiVersion": "v1", "data": {"secret": "02020202020202020202"}, "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"opaque-secret2\",\"namespace\":\"default\"},\"data\":{\"secret\":\"02020202020202020202\"}}"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type": "collection", "data": [{"apiVersion": "v1", "data": "%s", "kind": "Secret", "metadata": {"annotations": {"kubectl.kubernetes.io/last-applied-configuration": "%[1]s"}, "name": "opaque-secret2", "namespace": "default"}, "type": "Opaque"}]}`, redacted)), + }, + + { + Name: "With configmap data", + Uri: "/configmaps", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}, "accessToken" : "fake_access_token"}`), + ExpectedBody: []byte(fmt.Sprintf(`{"metadata":{"namespace":"default","name":"my_configmap"},"data":"%s", "accessToken" : "%[1]s"}`, redacted)), }, { - Name: "With config map list data", - Uri: "/configmaps", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type": "collection", "data":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}},{"metadata":{"namespace":"default","name":"my_configmap_2"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), - Expected: []byte(fmt.Sprintf(`{"type": "collection", "data":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":"%s"},{"metadata":{"namespace":"default","name":"my_configmap_2"},"data":"%[1]s"}]}`, redacted)), + Name: "With config map list data", + Uri: "/configmaps", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type": "collection", "data":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}},{"metadata":{"namespace":"default","name":"my_configmap_2"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"type": "collection", "data":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":"%s"},{"metadata":{"namespace":"default","name":"my_configmap_2"},"data":"%[1]s"}]}`, redacted)), }, { // norman transforms some configmap subtypes to where their data fields cannot be distinguished from non-sensitive fields. // In this case, all fields aside from id, created, and baseType should be redacted. - Name: "With configmap list data but no data field for array elements", - Uri: "/configmaps", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"type": "collection", "data":[{"id":"p-12345:testconfigmap","baseType":"configmap","foo":"something","bar":"something","accessToken":"token"}]}`), - Expected: []byte(fmt.Sprintf(`{"data":[{"accessToken":"%[1]s","bar":"%[1]s","baseType":"configmap","foo":"%[1]s","id":"p-12345:testconfigmap"}],"type":"collection"}`, redacted)), + Name: "With configmap list data but no data field for array elements", + Uri: "/configmaps", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"type": "collection", "data":[{"id":"p-12345:testconfigmap","baseType":"configmap","foo":"something","bar":"something","accessToken":"token"}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"data":[{"accessToken":"%[1]s","bar":"%[1]s","baseType":"configmap","foo":"%[1]s","id":"p-12345:testconfigmap"}],"type":"collection"}`, redacted)), }, { - Name: "With secret list data from k8s proxy", - Uri: "/k8s/clusters/local/api/v1/configmaps?limit=500", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"kind": "ConfigMapList", "items":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), - Expected: []byte(fmt.Sprintf(`{"kind": "ConfigMapList", "items":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":"%s"}]}`, redacted)), + Name: "With secret list data from k8s proxy", + Uri: "/k8s/clusters/local/api/v1/configmaps?limit=500", + Headers: http.Header{"Content-Type": {contentTypeJSON}}, + Body: []byte(`{"kind": "ConfigMapList", "items":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}}]}`), + ExpectedBody: []byte(fmt.Sprintf(`{"kind": "ConfigMapList", "items":[{"metadata":{"namespace":"default","name":"my_configmap"},"data":"%s"}]}`, redacted)), }, { - Name: "With configmap data and wrong URI", - Uri: "nont-configmap", - Headers: http.Header{"Content-Type": {contentTypeJSON}}, - Body: []byte(`{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE=\\", "bar": "U3VwZXIgU2VjcmV0IERhdGEK"}, "accessToken" : "fake_access_token"}`), - Expected: []byte(fmt.Sprintf(`{"metadata":{"namespace":"default","name":"my_configmap"},"data":{"foo":"c3VwZXIgc2VjcmV0IGRhdGE= ... [truncated]
pkg/auth/audit/redact.go+1 −1 modified@@ -168,7 +168,7 @@ func redactSecret(log *log) error { } if strings.Contains(log.RequestURI, "secrets") || pairMatches(log.ResponseBody, checkForBasetype(secretBaseType)) { - redactDataFromBody(log, log.RequestBody, "SecretList") + redactDataFromBody(log, log.ResponseBody, "SecretList") } return nil
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-mw39-9qc2-f7mgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-58269ghsaADVISORY
- bugzilla.suse.com/show_bug.cginvdWEB
- github.com/rancher/rancher/commit/26ad9216e94f77b5471f638256a6989030572adcghsaWEB
- github.com/rancher/rancher/commit/50dc516a19ea216e270f738912dc8d0c9ca99d5dghsaWEB
- github.com/rancher/rancher/security/advisories/GHSA-mw39-9qc2-f7mgnvdWEB
News mentions
0No linked articles in our index yet.