123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- 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
- }
|