...

Source file src/github.com/Microsoft/hcsshim/internal/log/scrub.go

Documentation: github.com/Microsoft/hcsshim/internal/log

     1  package log
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"sync/atomic"
     8  
     9  	hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
    10  )
    11  
    12  // This package scrubs objects of potentially sensitive information to pass to logging
    13  
    14  type genMap = map[string]interface{}
    15  type scrubberFunc func(genMap) error
    16  
    17  const _scrubbedReplacement = "<scrubbed>"
    18  
    19  var (
    20  	ErrUnknownType = errors.New("encoded object is of unknown type")
    21  
    22  	// case sensitive keywords, so "env" is not a substring on "Environment"
    23  	_scrubKeywords = [][]byte{[]byte("env"), []byte("Environment")}
    24  
    25  	_scrub int32
    26  )
    27  
    28  // SetScrubbing enables scrubbing
    29  func SetScrubbing(enable bool) {
    30  	v := int32(0) // cant convert from bool to int32 directly
    31  	if enable {
    32  		v = 1
    33  	}
    34  	atomic.StoreInt32(&_scrub, v)
    35  }
    36  
    37  // IsScrubbingEnabled checks if scrubbing is enabled
    38  func IsScrubbingEnabled() bool {
    39  	v := atomic.LoadInt32(&_scrub)
    40  	return v != 0
    41  }
    42  
    43  // ScrubProcessParameters scrubs HCS Create Process requests with config parameters of
    44  // type internal/hcs/schema2.ScrubProcessParameters (aka hcsshema.ScrubProcessParameters)
    45  func ScrubProcessParameters(s string) (string, error) {
    46  	// todo: deal with v1 ProcessConfig
    47  	b := []byte(s)
    48  	if !IsScrubbingEnabled() || !hasKeywords(b) || !json.Valid(b) {
    49  		return s, nil
    50  	}
    51  
    52  	pp := hcsschema.ProcessParameters{}
    53  	if err := json.Unmarshal(b, &pp); err != nil {
    54  		return "", err
    55  	}
    56  	pp.Environment = map[string]string{_scrubbedReplacement: _scrubbedReplacement}
    57  
    58  	b, err := encodeBuffer(bytes.NewBuffer(b[:0]), pp)
    59  	if err != nil {
    60  		return "", err
    61  	}
    62  	return string(b), nil
    63  }
    64  
    65  // ScrubBridgeCreate scrubs requests sent over the bridge of type
    66  // internal/gcs/protocol.containerCreate wrapping an internal/hcsoci.linuxHostedSystem
    67  func ScrubBridgeCreate(b []byte) ([]byte, error) {
    68  	return scrubBytes(b, scrubBridgeCreate)
    69  }
    70  
    71  func scrubBridgeCreate(m genMap) error {
    72  	if !isRequestBase(m) {
    73  		return ErrUnknownType
    74  	}
    75  	if ss, ok := m["ContainerConfig"]; ok {
    76  		// ContainerConfig is a json encoded struct passed as a regular string field
    77  		s, ok := ss.(string)
    78  		if !ok {
    79  			return ErrUnknownType
    80  		}
    81  		b, err := scrubBytes([]byte(s), scrubLinuxHostedSystem)
    82  		if err != nil {
    83  			return err
    84  		}
    85  		m["ContainerConfig"] = string(b)
    86  		return nil
    87  	}
    88  	return ErrUnknownType
    89  }
    90  
    91  func scrubLinuxHostedSystem(m genMap) error {
    92  	if m, ok := index(m, "OciSpecification"); ok {
    93  		if _, ok := m["annotations"]; ok {
    94  			m["annotations"] = map[string]string{_scrubbedReplacement: _scrubbedReplacement}
    95  		}
    96  		if m, ok := index(m, "process"); ok {
    97  			if _, ok := m["env"]; ok {
    98  				m["env"] = []string{_scrubbedReplacement}
    99  				return nil
   100  			}
   101  		}
   102  	}
   103  	return ErrUnknownType
   104  }
   105  
   106  // ScrubBridgeExecProcess scrubs requests sent over the bridge of type
   107  // internal/gcs/protocol.containerExecuteProcess
   108  func ScrubBridgeExecProcess(b []byte) ([]byte, error) {
   109  	return scrubBytes(b, scrubExecuteProcess)
   110  }
   111  
   112  func scrubExecuteProcess(m genMap) error {
   113  	if !isRequestBase(m) {
   114  		return ErrUnknownType
   115  	}
   116  	if m, ok := index(m, "Settings"); ok {
   117  		if ss, ok := m["ProcessParameters"]; ok {
   118  			// ProcessParameters is a json encoded struct passed as a regular sting field
   119  			s, ok := ss.(string)
   120  			if !ok {
   121  				return ErrUnknownType
   122  			}
   123  
   124  			s, err := ScrubProcessParameters(s)
   125  			if err != nil {
   126  				return err
   127  			}
   128  
   129  			m["ProcessParameters"] = s
   130  			return nil
   131  		}
   132  	}
   133  	return ErrUnknownType
   134  }
   135  
   136  func scrubBytes(b []byte, scrub scrubberFunc) ([]byte, error) {
   137  	if !IsScrubbingEnabled() || !hasKeywords(b) || !json.Valid(b) {
   138  		return b, nil
   139  	}
   140  
   141  	m := make(genMap)
   142  	if err := json.Unmarshal(b, &m); err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	// could use regexp, but if the env strings contain braces, the regexp fails
   147  	// parsing into individual structs would require access to private structs
   148  	if err := scrub(m); err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	b, err := encode(m)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	return b, nil
   158  }
   159  
   160  func isRequestBase(m genMap) bool {
   161  	// neither of these are (currently) `omitempty`
   162  	_, a := m["ActivityId"]
   163  	_, c := m["ContainerId"]
   164  	return a && c
   165  }
   166  
   167  // combination `m, ok := m[s]` and `m, ok := m.(genMap)`
   168  func index(m genMap, s string) (genMap, bool) {
   169  	if m, ok := m[s]; ok {
   170  		mm, ok := m.(genMap)
   171  		return mm, ok
   172  	}
   173  
   174  	return m, false
   175  }
   176  
   177  func hasKeywords(b []byte) bool {
   178  	for _, bb := range _scrubKeywords {
   179  		if bytes.Contains(b, bb) {
   180  			return true
   181  		}
   182  	}
   183  	return false
   184  }
   185  

View as plain text