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:
Syed Nihal 2024-06-12 17:16:47 +05:30
parent 0269c89e03
commit 65be72e8ad
3 changed files with 97 additions and 4 deletions

34
lib/httputils/url.go Normal file
View 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
View 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)
}
})
}
}

View file

@ -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" {