Skip to content

Commit

Permalink
scrub struct before log
Browse files Browse the repository at this point in the history
  • Loading branch information
iQQBot committed Oct 11, 2023
1 parent 9343dbe commit a64322f
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 12 deletions.
136 changes: 136 additions & 0 deletions components/scrubber/scrubber.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"reflect"
"regexp"
"strings"
"unsafe"

"github.com/mitchellh/reflectwalk"
)
Expand Down Expand Up @@ -48,6 +49,16 @@ type TrustedValue interface {
IsTrustedValue()
}

type TrustedValueWrap struct {
Value any
}

func (TrustedValueWrap) IsTrustedValue() {}

func (t TrustedValueWrap) MarshalJSON() ([]byte, error) {
return json.Marshal(t.Value)
}

// Scrubber defines the interface for a scrubber, which can sanitise various types of data.
// The scrubbing process involves removing or replacing sensitive data to prevent it from being exposed.
//
Expand Down Expand Up @@ -86,6 +97,8 @@ type Scrubber interface {
// }
//
Struct(val any) error

DeepCopyStruct(val any) any
}

// Default is the default scrubber consumers of this package should use
Expand Down Expand Up @@ -189,6 +202,129 @@ func (s *scrubberImpl) Struct(val any) error {
return nil
}

func (s *scrubberImpl) deepCopyStruct(fieldName string, src reflect.Value, scrubTag string) reflect.Value {
if src.Kind() == reflect.Ptr && src.IsNil() {
return reflect.New(src.Type()).Elem()
}

if src.Kind() == reflect.String {
dst := reflect.New(src.Type())
var (
setExplicitValue bool
explicitValue string
)
switch scrubTag {
case "ignore":
return dst
case "hash":
setExplicitValue = true
explicitValue = SanitiseHash(src.String())
case "redact":
setExplicitValue = true
explicitValue = SanitiseRedact(src.String())
}

if setExplicitValue {
dst.Elem().SetString(explicitValue)
} else {
sanitisatiser := s.getSanitisatiser(fieldName)
if sanitisatiser != nil {
dst.Elem().SetString(sanitisatiser(src.String()))
} else {
dst.Elem().SetString(s.Value(src.String()))
}
}
if !dst.CanInterface() {
return dst
}
return dst.Elem()
}

switch src.Kind() {

case reflect.Struct:
dst := reflect.New(src.Type())
t := src.Type()

for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
srcValue := src.Field(i)
dstValue := dst.Elem().Field(i)

if !srcValue.CanInterface() {
dstValue = reflect.NewAt(dstValue.Type(), unsafe.Pointer(dstValue.UnsafeAddr())).Elem()

if !srcValue.CanAddr() {
switch {
case srcValue.CanInt():
dstValue.SetInt(srcValue.Int())
case srcValue.CanUint():
dstValue.SetUint(srcValue.Uint())
case srcValue.CanFloat():
dstValue.SetFloat(srcValue.Float())
case srcValue.CanComplex():
dstValue.SetComplex(srcValue.Complex())
case srcValue.Kind() == reflect.Bool:
dstValue.SetBool(srcValue.Bool())
}

continue
}

srcValue = reflect.NewAt(srcValue.Type(), unsafe.Pointer(srcValue.UnsafeAddr())).Elem()
}

tagValue := f.Tag.Get("scrub")
copied := s.deepCopyStruct(f.Name, srcValue, tagValue)
dstValue.Set(copied)
}
return dst.Elem()

case reflect.Map:
dst := reflect.MakeMap(src.Type())
keys := src.MapKeys()
for i := 0; i < src.Len(); i++ {
mValue := src.MapIndex(keys[i])
dst.SetMapIndex(keys[i], s.deepCopyStruct(keys[i].String(), mValue, ""))
}
return dst

case reflect.Slice:
dst := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
for i := 0; i < src.Len(); i++ {
dst.Index(i).Set(s.deepCopyStruct(fieldName, src.Index(i), ""))
}
return dst

case reflect.Array:
if src.Len() == 0 {
return src // can not access to src.Index(0)
}

dst := reflect.New(src.Type()).Elem()
for i := 0; i < src.Len(); i++ {
dst.Index(i).Set(s.deepCopyStruct(fieldName, src.Index(i), ""))
}
return dst

case reflect.Ptr:
dst := reflect.New(src.Elem().Type())
copied := s.deepCopyStruct(fieldName, src.Elem(), scrubTag)
dst.Elem().Set(copied)
return dst

default:
dst := reflect.New(src.Type())
dst.Elem().Set(src)
return dst.Elem()
}
}

// Struct implements Scrubber
func (s *scrubberImpl) DeepCopyStruct(val any) any {
return s.deepCopyStruct("", reflect.ValueOf(val), "").Interface()
}

func (s *scrubberImpl) scrubJsonObject(val map[string]interface{}) error {
// fix https://github.com/gitpod-io/security/issues/64
name, _ := val["name"].(string)
Expand Down
14 changes: 3 additions & 11 deletions components/ws-manager-mk2/controllers/workspace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"

wsk8s "github.com/gitpod-io/gitpod/common-go/kubernetes"
"github.com/gitpod-io/gitpod/components/scrubber"
"github.com/gitpod-io/gitpod/ws-manager-mk2/pkg/maintenance"
config "github.com/gitpod-io/gitpod/ws-manager/api/config"
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"
Expand Down Expand Up @@ -126,20 +125,13 @@ func (r *WorkspaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
r.updateMetrics(ctx, &workspace)
r.emitPhaseEvents(ctx, &workspace, oldStatus)

var scrubbedPodStatus *corev1.PodStatus
var podStatus *corev1.PodStatus
if len(workspacePods.Items) > 0 {
scrubbedPodStatus = workspacePods.Items[0].Status.DeepCopy()
if err = scrubber.Default.Struct(scrubbedPodStatus); err != nil {
log.Error(err, "failed to scrub pod status")
}
}
scrubbedStatus := workspace.Status.DeepCopy()
if err = scrubber.Default.Struct(scrubbedStatus); err != nil {
log.Error(err, "failed to scrub workspace status")
podStatus = &workspacePods.Items[0].Status
}

if !equality.Semantic.DeepDerivative(oldStatus, workspace.Status) {
log.Info("updating workspace status", "status", scrubbedStatus, "podStatus", scrubbedPodStatus)
log.Info("updating workspace status", "status", workspace.Status, "podStatus", podStatus)
}

err = r.Status().Update(ctx, &workspace)
Expand Down
5 changes: 4 additions & 1 deletion components/ws-manager-mk2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
config "github.com/gitpod-io/gitpod/ws-manager/api/config"
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"

"github.com/gitpod-io/gitpod/components/scrubber"
"github.com/gitpod-io/gitpod/ws-manager-mk2/controllers"
"github.com/gitpod-io/gitpod/ws-manager-mk2/pkg/maintenance"
imgproxy "github.com/gitpod-io/gitpod/ws-manager-mk2/pkg/proxy"
Expand Down Expand Up @@ -77,7 +78,9 @@ func main() {
flag.Parse()

log.Init(ServiceName, Version, jsonLog, verbose)
baseLogger := logrusr.New(log.Log)
baseLogger := logrusr.New(log.Log, logrusr.WithFormatter(func(i interface{}) interface{} {
return &scrubber.TrustedValueWrap{Value: scrubber.Default.DeepCopyStruct(i)}
}))
ctrl.SetLogger(baseLogger)
// Set the logger used by k8s (e.g. client-go).
klog.SetLogger(baseLogger)
Expand Down

0 comments on commit a64322f

Please sign in to comment.