-
Notifications
You must be signed in to change notification settings - Fork 8
draft: adding filter eval for client spans #250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,9 +4,12 @@ | |
"bytes" | ||
"io" | ||
"net/http" | ||
"strings" | ||
|
||
config "github.com/hypertrace/agent-config/gen/go/v1" | ||
"github.com/hypertrace/goagent/sdk" | ||
codes "github.com/hypertrace/goagent/sdk" | ||
"github.com/hypertrace/goagent/sdk/filter" | ||
internalconfig "github.com/hypertrace/goagent/sdk/internal/config" | ||
"github.com/hypertrace/goagent/sdk/internal/container" | ||
) | ||
|
@@ -18,6 +21,7 @@ | |
defaultAttributes map[string]string | ||
spanFromContextRetriever sdk.SpanFromContext | ||
dataCaptureConfig *config.DataCapture | ||
filter filter.Filter | ||
} | ||
|
||
func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||
|
@@ -58,6 +62,29 @@ | |
req.Body = io.NopCloser(bytes.NewBuffer(body)) | ||
} | ||
|
||
filterResult := rt.filter.Evaluate(span) | ||
if filterResult.Block { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this for blocking client requests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, since we are anyways calling libtraceable, thought we can add blocking support as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I guess I'm wondering on use case, I understand that because we want to add sampling, we could add blocking support. This seems like it introduces ambiguity in our blocking feature as a whole. Up to this point, blocking has specifically been about preventing bad requests from making it into the system. Since we don't currently propagate string taint from the original request to downstream client spans, it's unclear what would drive the decision to block here. The only scenarios I can think of are: 1.) The app loads something from a DB or config and decides to block the outbound request - which is totally unrelated to the original inbound request. If we allow blocking here, we're essentially saying: "some internal logic or app state, something not tied to the inbound request caused us to block an outbound call." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. But we also have DLP based blocking which is basically to prevent data leaks and was made for client spans only, but at that time none of our agents did blocking eval on client spans and hence user said they'll put all of their egress under a proxy and instrument our agent there so that DLP based blocking will work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But if you think even having the capability makes our feature ambiguous, then definitely removing this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, okay, but don't remove just because I don't think worth it - i think worth identifying what we are trying to do..(I see you also did header injections) so is the purpose of these tickets to add sampling support, or add sampling support, header injections & blocking. I'd think this is a product question, if we see value in blocking client spans then sure.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, lets start a thread with protection team/pm involved as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sampling makes sense for client spans. Blocking I am not so sure. Let's get clarity from PM. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have started a thread here: https://harness.slack.com/archives/C08SEG313E3/p1751005003984389 We kind of discussed it back when rolling dlp out, but since its a huge lift, never prioritised it. I am unsure if we should prioritise it now as well, but I thought I can add it here since its not a lot of extra changes from adding sampling support to get it supported in goagent. |
||
span.SetStatus(codes.StatusCodeError, "Access Denied") | ||
span.SetAttribute("http.status_code", filterResult.ResponseStatusCode) | ||
return &http.Response{ | ||
Status: "Access Denied", | ||
StatusCode: int(filterResult.ResponseStatusCode), | ||
Proto: "HTTP/1.1", | ||
ProtoMajor: 1, | ||
ProtoMinor: 1, | ||
Request: req, | ||
Header: map[string][]string{ | ||
"Content-Type": {"text/plain"}, | ||
}, | ||
Body: io.NopCloser(strings.NewReader(filterResult.ResponseMessage)), | ||
}, nil | ||
} else if filterResult.Decorations != nil { | ||
for _, header := range filterResult.Decorations.RequestHeaderInjections { | ||
req.Header.Add(header.Key, header.Value) | ||
span.SetAttribute("http.request.header."+header.Key, header.Value) | ||
} | ||
} | ||
|
||
res, err := rt.delegate.RoundTrip(req) | ||
if err != nil { | ||
return res, err | ||
|
@@ -90,7 +117,7 @@ | |
|
||
// WrapTransport returns a new http.RoundTripper that should be wrapped | ||
// by an instrumented http.RoundTripper | ||
func WrapTransport(delegate http.RoundTripper, spanFromContextRetriever sdk.SpanFromContext, spanAttributes map[string]string) http.RoundTripper { | ||
func WrapTransport(delegate http.RoundTripper, spanFromContextRetriever sdk.SpanFromContext, options *Options, spanAttributes map[string]string) http.RoundTripper { | ||
defaultAttributes := make(map[string]string) | ||
for k, v := range spanAttributes { | ||
defaultAttributes[k] = v | ||
|
@@ -99,5 +126,15 @@ | |
defaultAttributes["container_id"] = containerID | ||
} | ||
|
||
return &roundTripper{delegate, defaultAttributes, spanFromContextRetriever, internalconfig.GetConfig().GetDataCapture()} | ||
var filter filter.Filter = &filter.NoopFilter{} | ||
if options != nil && options.Filter != nil { | ||
filter = options.Filter | ||
} | ||
return &roundTripper{ | ||
delegate: delegate, | ||
defaultAttributes: defaultAttributes, | ||
spanFromContextRetriever: spanFromContextRetriever, | ||
dataCaptureConfig: internalconfig.GetConfig().GetDataCapture(), | ||
filter: filter, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the filter be an interface type instead of just using the NoopFilter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its an interface type. I am initialising the variable in this way because the interface variable can be assigned from 2 different interface implementations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I see we are reading it from the options below too.