mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-03-11 15:34:56 +00:00
vmbackup:changes to mask sensitive info from the logs related to snapshot create and delete URLs
Signed-off-by: Syed Nihal <syed.nihal@nokia.com>
This commit is contained in:
parent
0269c89e03
commit
65be72e8ad
3 changed files with 97 additions and 4 deletions
34
lib/httputils/url.go
Normal file
34
lib/httputils/url.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package httputils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var secretWordsRe = regexp.MustCompile("auth|pass|key|secret|token")
|
||||
|
||||
// RedactedURL redacts sensitive information like basic auth credentials
|
||||
// and query parameters containing sensitive info from a URL object (*url.URL).
|
||||
// It searches for query parameter names containing words commonly associated
|
||||
// with authentication credentials (like "auth", "pass", "key", "secret", or "token").
|
||||
// These words are matched in a case-insensitive manner. If there is a match, such sensitive information will be mased with 'xxxxx'
|
||||
func RedactedURL(u *url.URL) string {
|
||||
if u == nil {
|
||||
return ""
|
||||
}
|
||||
ru := *u
|
||||
values := ru.Query()
|
||||
for k, vs := range values {
|
||||
if secretWordsRe.MatchString(strings.ToLower(k)) {
|
||||
for i := range vs {
|
||||
vs[i] = "xxxxx"
|
||||
}
|
||||
}
|
||||
}
|
||||
ru.RawQuery = values.Encode()
|
||||
if _, has := ru.User.Password(); has {
|
||||
ru.User = url.UserPassword("xxxxx", "xxxxx")
|
||||
}
|
||||
return ru.String()
|
||||
}
|
59
lib/httputils/url_test.go
Normal file
59
lib/httputils/url_test.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package httputils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRedactedURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inputURL string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "empty URL",
|
||||
inputURL: "",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "no secrets",
|
||||
inputURL: "https://example.com/path/to/resource",
|
||||
expected: "https://example.com/path/to/resource",
|
||||
},
|
||||
{
|
||||
name: "secret query parameter",
|
||||
inputURL: "https://example.com/path/to/resource?authKey=foobar",
|
||||
expected: "https://example.com/path/to/resource?authKey=xxxxx",
|
||||
},
|
||||
{
|
||||
name: "secret query parameters (case insensitive)",
|
||||
inputURL: "https://example.com/path/to/resource?TOKEN=foobar",
|
||||
expected: "https://example.com/path/to/resource?TOKEN=xxxxx",
|
||||
},
|
||||
{
|
||||
name: "with basic auth secrets",
|
||||
inputURL: "https://username:secretPassword@example.com/path/to/resource",
|
||||
expected: "https://xxxxx:xxxxx@example.com/path/to/resource",
|
||||
},
|
||||
{
|
||||
name: "with basic auth and query parameters secrets",
|
||||
inputURL: "https://username:secretPassword@example.com/path/to/resource?authKey=foobar",
|
||||
expected: "https://xxxxx:xxxxx@example.com/path/to/resource?authKey=xxxxx",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
parsedURL, err := url.Parse(test.inputURL)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
return
|
||||
}
|
||||
actual := RedactedURL(parsedURL)
|
||||
if actual != test.expected {
|
||||
t.Errorf("Expected: %s, Actual: %s", test.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -51,13 +51,13 @@ func Create(createSnapshotURL string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("unexpected status code returned from %q: %d; expecting %d; response body: %q", u.Redacted(), resp.StatusCode, http.StatusOK, body)
|
||||
return "", fmt.Errorf("unexpected status code returned from %q: %d; expecting %d; response body: %q", httputils.RedactedURL(u), resp.StatusCode, http.StatusOK, body)
|
||||
}
|
||||
|
||||
snap := snapshot{}
|
||||
err = json.Unmarshal(body, &snap)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot parse JSON response from %q: %w; response body: %q", u.Redacted(), err, body)
|
||||
return "", fmt.Errorf("cannot parse JSON response from %q: %w; response body: %q", httputils.RedactedURL(u), err, body)
|
||||
}
|
||||
|
||||
if snap.Status == "ok" {
|
||||
|
@ -95,13 +95,13 @@ func Delete(deleteSnapshotURL string, snapshotName string) error {
|
|||
return err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected status code returned from %q: %d; expecting %d; response body: %q", u.Redacted(), resp.StatusCode, http.StatusOK, body)
|
||||
return fmt.Errorf("unexpected status code returned from %q: %d; expecting %d; response body: %q", httputils.RedactedURL(u), resp.StatusCode, http.StatusOK, body)
|
||||
}
|
||||
|
||||
snap := snapshot{}
|
||||
err = json.Unmarshal(body, &snap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse JSON response from %q: %w; response body: %q", u.Redacted(), err, body)
|
||||
return fmt.Errorf("cannot parse JSON response from %q: %w; response body: %q", httputils.RedactedURL(u), err, body)
|
||||
}
|
||||
|
||||
if snap.Status == "ok" {
|
||||
|
|
Loading…
Reference in a new issue