github.com/cilium/cilium@v1.16.2/pkg/hubble/parser/seven/http.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Hubble 3 4 package seven 5 6 import ( 7 "fmt" 8 "net/url" 9 "sort" 10 "strings" 11 12 flowpb "github.com/cilium/cilium/api/v1/flow" 13 "github.com/cilium/cilium/pkg/hubble/defaults" 14 "github.com/cilium/cilium/pkg/hubble/parser/options" 15 "github.com/cilium/cilium/pkg/proxy/accesslog" 16 "github.com/cilium/cilium/pkg/time" 17 ) 18 19 func decodeHTTP(flowType accesslog.FlowType, http *accesslog.LogRecordHTTP, opts *options.Options) *flowpb.Layer7_Http { 20 var headers []*flowpb.HTTPHeader 21 keys := make([]string, 0, len(http.Headers)) 22 for key := range http.Headers { 23 keys = append(keys, key) 24 } 25 sort.Strings(keys) 26 for _, key := range keys { 27 for _, value := range http.Headers[key] { 28 filteredValue := filterHeader(key, value, opts.HubbleRedactSettings) 29 headers = append(headers, &flowpb.HTTPHeader{Key: key, Value: filteredValue}) 30 } 31 } 32 uri := filteredURL(http.URL, opts.HubbleRedactSettings) 33 34 if flowType == accesslog.TypeRequest { 35 // Set only fields that are relevant for requests. 36 return &flowpb.Layer7_Http{ 37 Http: &flowpb.HTTP{ 38 Method: http.Method, 39 Protocol: http.Protocol, 40 Url: uri.String(), 41 Headers: headers, 42 }, 43 } 44 } 45 46 return &flowpb.Layer7_Http{ 47 Http: &flowpb.HTTP{ 48 Code: uint32(http.Code), 49 Method: http.Method, 50 Protocol: http.Protocol, 51 Url: uri.String(), 52 Headers: headers, 53 }, 54 } 55 } 56 57 func (p *Parser) httpSummary(flowType accesslog.FlowType, http *accesslog.LogRecordHTTP, flow *flowpb.Flow) string { 58 uri := filteredURL(http.URL, p.opts.HubbleRedactSettings) 59 httpRequest := http.Method + " " + uri.String() 60 switch flowType { 61 case accesslog.TypeRequest: 62 return fmt.Sprintf("%s %s", http.Protocol, httpRequest) 63 case accesslog.TypeResponse: 64 return fmt.Sprintf("%s %d %dms (%s)", http.Protocol, http.Code, uint64(time.Duration(flow.GetL7().LatencyNs)/time.Millisecond), httpRequest) 65 } 66 return "" 67 } 68 69 // filterHeader receives a key-value pair of an http header along with an HubbleRedactSettings. 70 // Based on the allow/deny lists of the provided HttpHeadersList it returns the original value 71 // or the redacted constant "HUBBLE_REDACTED" accordingly: 72 // 1. If HubbleRedactSettings is enabled (meaning that hubble.redact feature is enabled) but both allow/deny lists are empty then the value of the 73 // header is redacted by default. 74 // 2. If the header's key is contained in the allow list then the value 75 // of the header will not be redacted. 76 // 3. If the header's key is contained in the deny list then the value 77 // of the header will be redacted. 78 // 4. If none of the above happens, then if there is any allow list defined then the value will be redacted 79 // otherwise if there is a deny list defined the value will not be redacted. 80 func filterHeader(key string, value string, redactSettings options.HubbleRedactSettings) string { 81 if !redactSettings.Enabled { 82 return value 83 } 84 if len(redactSettings.RedactHttpHeaders.Allow) == 0 && len(redactSettings.RedactHttpHeaders.Deny) == 0 { 85 // That's the default case, where redact is generally enabled but not headers' lists 86 // have been specified. In that case we redact everything by default. 87 return defaults.SensitiveValueRedacted 88 } 89 if _, ok := redactSettings.RedactHttpHeaders.Allow[strings.ToLower(key)]; ok { 90 return value 91 } 92 if _, ok := redactSettings.RedactHttpHeaders.Deny[strings.ToLower(key)]; ok { 93 return defaults.SensitiveValueRedacted 94 } 95 96 if len(redactSettings.RedactHttpHeaders.Allow) > 0 { 97 return defaults.SensitiveValueRedacted 98 } 99 return value 100 } 101 102 // filteredURL return a copy of the given URL potentially mutated depending on 103 // Hubble redact settings. 104 // If configured and user info exists, it removes the password from the flow. 105 // If configured, it removes the URL's query parts from the flow. 106 func filteredURL(uri *url.URL, redactSettings options.HubbleRedactSettings) *url.URL { 107 if uri == nil { 108 // NOTE: return a non-nil URL so that we can always call String() on 109 // it. 110 return &url.URL{} 111 } 112 u2 := cloneURL(uri) 113 if redactSettings.RedactHTTPUserInfo && u2.User != nil { 114 if _, ok := u2.User.Password(); ok { 115 u2.User = url.UserPassword(u2.User.Username(), defaults.SensitiveValueRedacted) 116 } 117 } 118 if redactSettings.RedactHTTPQuery { 119 u2.RawQuery = "" 120 u2.Fragment = "" 121 } 122 return u2 123 } 124 125 // cloneURL return a copy of the given URL. Copied from src/net/http/clone.go. 126 func cloneURL(u *url.URL) *url.URL { 127 if u == nil { 128 return nil 129 } 130 u2 := new(url.URL) 131 *u2 = *u 132 if u.User != nil { 133 u2.User = new(url.Userinfo) 134 *u2.User = *u.User 135 } 136 return u2 137 }