You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
buildx/vendor/github.com/Microsoft/hcsshim/internal/log/scrub.go

185 lines
4.3 KiB
Go

package log
import (
"bytes"
"encoding/json"
"errors"
"sync/atomic"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
)
// This package scrubs objects of potentially sensitive information to pass to logging
type genMap = map[string]interface{}
type scrubberFunc func(genMap) error
const _scrubbedReplacement = "<scrubbed>"
var (
ErrUnknownType = errors.New("encoded object is of unknown type")
// case sensitive keywords, so "env" is not a substring on "Environment"
_scrubKeywords = [][]byte{[]byte("env"), []byte("Environment")}
_scrub int32
)
// SetScrubbing enables scrubbing
func SetScrubbing(enable bool) {
v := int32(0) // cant convert from bool to int32 directly
if enable {
v = 1
}
atomic.StoreInt32(&_scrub, v)
}
// IsScrubbingEnabled checks if scrubbing is enabled
func IsScrubbingEnabled() bool {
v := atomic.LoadInt32(&_scrub)
return v != 0
}
// ScrubProcessParameters scrubs HCS Create Process requests with config parameters of
// type internal/hcs/schema2.ScrubProcessParameters (aka hcsshema.ScrubProcessParameters)
func ScrubProcessParameters(s string) (string, error) {
// todo: deal with v1 ProcessConfig
b := []byte(s)
if !IsScrubbingEnabled() || !hasKeywords(b) || !json.Valid(b) {
return s, nil
}
pp := hcsschema.ProcessParameters{}
if err := json.Unmarshal(b, &pp); err != nil {
return "", err
}
pp.Environment = map[string]string{_scrubbedReplacement: _scrubbedReplacement}
b, err := encodeBuffer(bytes.NewBuffer(b[:0]), pp)
if err != nil {
return "", err
}
return string(b), nil
}
// ScrubBridgeCreate scrubs requests sent over the bridge of type
// internal/gcs/protocol.containerCreate wrapping an internal/hcsoci.linuxHostedSystem
func ScrubBridgeCreate(b []byte) ([]byte, error) {
return scrubBytes(b, scrubBridgeCreate)
}
func scrubBridgeCreate(m genMap) error {
if !isRequestBase(m) {
return ErrUnknownType
}
if ss, ok := m["ContainerConfig"]; ok {
// ContainerConfig is a json encoded struct passed as a regular string field
s, ok := ss.(string)
if !ok {
return ErrUnknownType
}
b, err := scrubBytes([]byte(s), scrubLinuxHostedSystem)
if err != nil {
return err
}
m["ContainerConfig"] = string(b)
return nil
}
return ErrUnknownType
}
func scrubLinuxHostedSystem(m genMap) error {
if m, ok := index(m, "OciSpecification"); ok {
if _, ok := m["annotations"]; ok {
m["annotations"] = map[string]string{_scrubbedReplacement: _scrubbedReplacement}
}
if m, ok := index(m, "process"); ok {
if _, ok := m["env"]; ok {
m["env"] = []string{_scrubbedReplacement}
return nil
}
}
}
return ErrUnknownType
}
// ScrubBridgeExecProcess scrubs requests sent over the bridge of type
// internal/gcs/protocol.containerExecuteProcess
func ScrubBridgeExecProcess(b []byte) ([]byte, error) {
return scrubBytes(b, scrubExecuteProcess)
}
func scrubExecuteProcess(m genMap) error {
if !isRequestBase(m) {
return ErrUnknownType
}
if m, ok := index(m, "Settings"); ok {
if ss, ok := m["ProcessParameters"]; ok {
// ProcessParameters is a json encoded struct passed as a regular sting field
s, ok := ss.(string)
if !ok {
return ErrUnknownType
}
s, err := ScrubProcessParameters(s)
if err != nil {
return err
}
m["ProcessParameters"] = s
return nil
}
}
return ErrUnknownType
}
func scrubBytes(b []byte, scrub scrubberFunc) ([]byte, error) {
if !IsScrubbingEnabled() || !hasKeywords(b) || !json.Valid(b) {
return b, nil
}
m := make(genMap)
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
// could use regexp, but if the env strings contain braces, the regexp fails
// parsing into individual structs would require access to private structs
if err := scrub(m); err != nil {
return nil, err
}
b, err := encode(m)
if err != nil {
return nil, err
}
return b, nil
}
func isRequestBase(m genMap) bool {
// neither of these are (currently) `omitempty`
_, a := m["ActivityId"]
_, c := m["ContainerId"]
return a && c
}
// combination `m, ok := m[s]` and `m, ok := m.(genMap)`
func index(m genMap, s string) (genMap, bool) {
if m, ok := m[s]; ok {
mm, ok := m.(genMap)
return mm, ok
}
return m, false
}
func hasKeywords(b []byte) bool {
for _, bb := range _scrubKeywords {
if bytes.Contains(b, bb) {
return true
}
}
return false
}