Skip to content

Commit

Permalink
This is an automated cherry-pick of #55622
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
  • Loading branch information
RidRisR authored and ti-chi-bot committed Aug 30, 2024
1 parent 020802f commit 9482ace
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 2 deletions.
2 changes: 1 addition & 1 deletion br/pkg/streamhelper/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ go_test(
],
flaky = True,
race = "on",
shard_count = 32,
shard_count = 33,
deps = [
":streamhelper",
"//br/pkg/errors",
Expand Down
9 changes: 8 additions & 1 deletion br/pkg/streamhelper/advancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,15 @@ import (
"github.com/pingcap/tidb/br/pkg/streamhelper/config"
"github.com/pingcap/tidb/br/pkg/streamhelper/spans"
"github.com/pingcap/tidb/br/pkg/utils"
<<<<<<< HEAD
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/metrics"
=======
"github.com/pingcap/tidb/pkg/kv"
"github.com/pingcap/tidb/pkg/metrics"
"github.com/pingcap/tidb/pkg/util"
"github.com/pingcap/tidb/pkg/util/redact"
>>>>>>> 51ffa22365f (br: redact ak/sk in logging (#55622))
tikvstore "github.com/tikv/client-go/v2/kv"
"github.com/tikv/client-go/v2/oracle"
"github.com/tikv/client-go/v2/tikv"
Expand Down Expand Up @@ -437,7 +444,7 @@ func (c *CheckpointAdvancer) onTaskEvent(ctx context.Context, e TaskEvent) error
if err != nil {
log.Warn("failed to upload service GC safepoint, skipping.", logutil.ShortError(err))
}
log.Info("added event", zap.Stringer("task", e.Info),
log.Info("added event", zap.Stringer("task", redact.TaskInfoRedacted{Info: e.Info}),
zap.Stringer("ranges", logutil.StringifyKeys(c.taskRange)), zap.Uint64("current-checkpoint", p))
case EventDel:
utils.LogBackupTaskCountDec()
Expand Down
55 changes: 55 additions & 0 deletions br/pkg/streamhelper/advancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import (
"github.com/pingcap/tidb/br/pkg/streamhelper"
"github.com/pingcap/tidb/br/pkg/streamhelper/config"
"github.com/pingcap/tidb/br/pkg/streamhelper/spans"
<<<<<<< HEAD
"github.com/pingcap/tidb/kv"
=======
"github.com/pingcap/tidb/pkg/kv"
"github.com/pingcap/tidb/pkg/util/redact"
>>>>>>> 51ffa22365f (br: redact ak/sk in logging (#55622))
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tikv/client-go/v2/oracle"
Expand Down Expand Up @@ -824,3 +829,53 @@ func TestSubscriptionPanic(t *testing.T) {
cancel()
wg.Wait()
}

func TestRedactBackend(t *testing.T) {
info := new(backup.StreamBackupTaskInfo)
info.Name = "test"
info.Storage = &backup.StorageBackend{
Backend: &backup.StorageBackend_S3{
S3: &backup.S3{
Endpoint: "http://",
Bucket: "test",
Prefix: "test",
AccessKey: "12abCD!@#[]{}?/\\",
SecretAccessKey: "12abCD!@#[]{}?/\\",
},
},
}

redacted := redact.TaskInfoRedacted{Info: info}
require.Equal(t, "storage:<s3:<endpoint:\"http://\" bucket:\"test\" prefix:\"test\" access_key:\"[REDACTED]\" secret_access_key:\"[REDACTED]\" > > name:\"test\" ", redacted.String())

info.Storage = &backup.StorageBackend{
Backend: &backup.StorageBackend_Gcs{
Gcs: &backup.GCS{
Endpoint: "http://",
Bucket: "test",
Prefix: "test",
CredentialsBlob: "12abCD!@#[]{}?/\\",
},
},
}
redacted = redact.TaskInfoRedacted{Info: info}
require.Equal(t, "storage:<gcs:<endpoint:\"http://\" bucket:\"test\" prefix:\"test\" CredentialsBlob:\"[REDACTED]\" > > name:\"test\" ", redacted.String())

info.Storage = &backup.StorageBackend{
Backend: &backup.StorageBackend_AzureBlobStorage{
AzureBlobStorage: &backup.AzureBlobStorage{
Endpoint: "http://",
Bucket: "test",
Prefix: "test",
SharedKey: "12abCD!@#[]{}?/\\",
AccessSig: "12abCD!@#[]{}?/\\",
EncryptionKey: &backup.AzureCustomerKey{
EncryptionKey: "12abCD!@#[]{}?/\\",
EncryptionKeySha256: "12abCD!@#[]{}?/\\",
},
},
},
}
redacted = redact.TaskInfoRedacted{Info: info}
require.Equal(t, "storage:<azure_blob_storage:<endpoint:\"http://\" bucket:\"test\" prefix:\"test\" shared_key:\"[REDACTED]\" access_sig:\"[REDACTED]\" encryption_key:<[REDACTED]> > > name:\"test\" ", redacted.String())
}
256 changes: 256 additions & 0 deletions pkg/util/redact/redact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
// Copyright 2024 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redact

import (
"bufio"
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/pingcap/errors"
backup "github.com/pingcap/kvproto/pkg/brpb"
"github.com/pingcap/tidb/pkg/util/intest"
)

var (
_ fmt.Stringer = redactStringer{}

reAccessKey = regexp.MustCompile(`access_key:\"[^\"]*\"`)
reSecretAccessKey = regexp.MustCompile(`secret_access_key:\"[^\"]*\"`)
reSharedKey = regexp.MustCompile(`shared_key:\"[^\"]*\"`)
reCredentialsBlob = regexp.MustCompile(`credentials_blob:\"[^\"]*\"`)
reAccessSig = regexp.MustCompile(`access_sig:\"[^\"]*\"`)
reEncryptKey = regexp.MustCompile(`encryption_key:<.*?>`)
)

// String will redact the input string according to 'mode'. Check 'tidb_redact_log': https://github.com/pingcap/tidb/blob/acf9e3128693a5a13f31027f05f4de41edf8d7b2/pkg/sessionctx/variable/sysvar.go#L2154.
func String(mode string, input string) string {
switch mode {
case "MARKER":
b := &strings.Builder{}
b.Grow(len(input))
_, _ = b.WriteRune('‹')
for _, c := range input {
if c == '‹' || c == '›' {
_, _ = b.WriteRune(c)
_, _ = b.WriteRune(c)
} else {
_, _ = b.WriteRune(c)
}
}
_, _ = b.WriteRune('›')
return b.String()
case "OFF":
return input
case "ON":
return ""
default:
// should never happen
intest.Assert(false, "invalid redact mode")
return ""
}
}

type redactStringer struct {
mode string
stringer fmt.Stringer
}

func (s redactStringer) String() string {
return String(s.mode, s.stringer.String())
}

// Stringer will redact the input stringer according to 'mode', similar to String().
func Stringer(mode string, input fmt.Stringer) redactStringer {
return redactStringer{mode, input}
}

// DeRedactFile will deredact the input file, either removing marked contents, or remove the marker. It works line by line.
func DeRedactFile(remove bool, input string, output string) error {
ifile, err := os.Open(filepath.Clean(input))
if err != nil {
return errors.WithStack(err)
}
defer ifile.Close()

var ofile io.Writer
if output == "-" {
ofile = os.Stdout
} else {
//nolint: gosec
file, err := os.OpenFile(filepath.Clean(output), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return errors.WithStack(err)
}
defer file.Close()
ofile = file
}

return DeRedact(remove, ifile, ofile, "\n")
}

// DeRedact is similar to DeRedactFile, but act on reader/writer, it works line by line.
func DeRedact(remove bool, input io.Reader, output io.Writer, sep string) error {
sc := bufio.NewScanner(input)
out := bufio.NewWriter(output)
defer out.Flush()
buf := bytes.NewBuffer(nil)
s := bufio.NewReader(nil)

for sc.Scan() {
s.Reset(strings.NewReader(sc.Text()))
start := false
for {
ch, _, err := s.ReadRune()
if err == io.EOF {
break
}
if err != nil {
return errors.WithStack(err)
}
if ch == '‹' {
if start {
// must be '<'
pch, _, err := s.ReadRune()
if err != nil {
return errors.WithStack(err)
}
if pch == ch {
_, _ = buf.WriteRune(ch)
} else {
_, _ = buf.WriteRune(ch)
_, _ = buf.WriteRune(pch)
}
} else {
start = true
buf.Reset()
}
} else if ch == '›' {
if start {
// peek the next
pch, _, err := s.ReadRune()
if err != nil && err != io.EOF {
return errors.WithStack(err)
}
if pch == ch {
_, _ = buf.WriteRune(ch)
} else {
start = false
if err != io.EOF {
// unpeek it
if err := s.UnreadRune(); err != nil {
return errors.WithStack(err)
}
}
if remove {
_ = out.WriteByte('?')
} else {
_, err = io.Copy(out, buf)
if err != nil {
return errors.WithStack(err)
}
}
}
} else {
_, _ = out.WriteRune(ch)
}
} else if start {
_, _ = buf.WriteRune(ch)
} else {
_, _ = out.WriteRune(ch)
}
}
if start {
_, _ = out.WriteRune('‹')
_, _ = out.WriteString(buf.String())
}
_, _ = out.WriteString(sep)
}

return nil
}

// InitRedact inits the enableRedactLog
func InitRedact(redactLog bool) {
mode := errors.RedactLogDisable
if redactLog {
mode = errors.RedactLogEnable
}
errors.RedactLogEnabled.Store(mode)
}

// NeedRedact returns whether to redact log
func NeedRedact() bool {
mode := errors.RedactLogEnabled.Load()
return mode != errors.RedactLogDisable && mode != ""
}

// Value receives string argument and return omitted information if redact log enabled
func Value(arg string) string {
if NeedRedact() {
return "?"
}
return arg
}

// Key receives a key return omitted information if redact log enabled
func Key(key []byte) string {
if NeedRedact() {
return "?"
}
return strings.ToUpper(hex.EncodeToString(key))
}

// WriteRedact is to write string with redact into `strings.Builder`
func WriteRedact(build *strings.Builder, v string, redact string) {
if redact == errors.RedactLogMarker {
build.WriteString("‹")
build.WriteString(v)
build.WriteString("›")
return
} else if redact == errors.RedactLogEnable {
build.WriteString("?")
return
}
build.WriteString(v)
}

// TaskInfoRedacted is a wrapper of backup.StreamBackupTaskInfo to redact sensitive information
type TaskInfoRedacted struct {
Info *backup.StreamBackupTaskInfo
}

func (TaskInfoRedacted) redact(input string) string {
// Replace the matched fields with redacted versions
output := reAccessKey.ReplaceAllString(input, `access_key:"[REDACTED]"`)
output = reSecretAccessKey.ReplaceAllString(output, `secret_access_key:"[REDACTED]"`)
output = reSharedKey.ReplaceAllString(output, `shared_key:"[REDACTED]"`)
output = reCredentialsBlob.ReplaceAllString(output, `CredentialsBlob:"[REDACTED]"`)
output = reAccessSig.ReplaceAllString(output, `access_sig:"[REDACTED]"`)
output = reEncryptKey.ReplaceAllString(output, `encryption_key:<[REDACTED]>`)

return output
}

// String returns the redacted string of the task info
func (t TaskInfoRedacted) String() string {
return t.redact(t.Info.String())
}
1 change: 1 addition & 0 deletions util/column-mapping/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ go_library(
deps = [
"//util/table-rule-selector",
"@com_github_pingcap_errors//:errors",
"@com_github_pingcap_kvproto//pkg/brpb",
],
)

Expand Down

0 comments on commit 9482ace

Please sign in to comment.