-
Notifications
You must be signed in to change notification settings - Fork 440
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
appsec/graphql: add support for Threat Monitoring #2309
Conversation
Adds a new in-app WAF integration for GraphQL to `dyngo`. Also adds a new contrib for `github.com/grapgql-go/graphql` to ensure the integration is not unnecessarily middleware-dependent. The `graphql.server.all_resolvers` address can currently only be sent to the WAF after all resolvers have executed, as doing otherwise would require re-parsing the query and matching fields to variables, which is unnecessarily expensive. Blocking capabilities will require further work (possibly dynamic instrumentation) as the tracing hooks provided by both supported middleware fail to allow altering the response flow (e.g: returning an error instead of invoking the field resolvers).
BenchmarksBenchmark execution time: 2023-12-19 10:16:39 Comparing candidate commit e0bb880 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 40 metrics, 1 unstable metrics. |
ed9ae81
to
2f0d043
Compare
…hql/APPSEC-11164 # Conflicts: # go.mod # go.sum # internal/appsec/dyngo/instrumentation/common.go # internal/appsec/remoteconfig_test.go # internal/appsec/waf.go # internal/appsec/waf_unit_test.go
Move dyngo listeners into per-protocol packages to make them easier to maintain and to improve overall separation of concerns within dyngo listener settings. This is an initial step in preparing for the addition of GraphQL support, and to make listener activation be contrib-driven instead of being unconditional.
…graphql/APPSEC-11164 # Conflicts: # internal/appsec/waf.go
} | ||
} | ||
|
||
// TraceField traces a GraphQL field access. | ||
func (t *Tracer) TraceField(ctx context.Context, _ string, typeName string, fieldName string, trivial bool, _ map[string]interface{}) (context.Context, trace.TraceFieldFinishFunc) { | ||
func (t *Tracer) TraceField(ctx context.Context, label string, typeName string, fieldName string, trivial bool, arguments map[string]interface{}) (context.Context, trace.FieldFinishFunc) { |
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.
🚫 [golangci] reported by reviewdog 🐶
unused-parameter: parameter 'label' seems to be unused, consider removing or renaming it as _ (revive)
…ctor-dyngo # Conflicts: # internal/appsec/listener/util/util_test.go # internal/appsec/waf.go
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.
First pass done - I reviewed everything on the dyngo side of things. I have all the contribs left to review.
if span == nil { | ||
// The span may be nil (e.g: in case of GraphQL subscriptions with certian contribs) | ||
span = trace.BlackHoleTagSetter{} | ||
} |
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.
What about skipping them if in the end we don't have any data transport available?
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.
Also, in Q1, we will start relying on the GLS so this case shouldn't happen anymore.
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.
GLS standing for Goroutine Local Storage? I don't think that'll change anything in this posture... The problem this works around is that the tracer INTENTIONALLY does not create a span for GraphQL Subscriptions because they may be open forever (preventing anything from being emitted).
…hql/APPSEC-11164 # Conflicts: # contrib/google.golang.org/grpc/stats_client.go # internal/appsec/trace/tagsholder.go # internal/appsec/waf.go
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.
First round of review, mainly focused on the non-appsec code.
Does it make sense to add an integration test for the new contrib? Let's also add an example_test.go
file for it.
I didn't add comments for style but please read the style guidelines of the repo. There are multiple places where the Stay compact
rule wasn't respected.
Ah - you got me there... I guess I am aware of the style guide but the whole Stay Compact aspect I have a pretty strong disagreement with at this stage (and sadly, the style guide provides no motivation for this guideline, so I can't even say if I agree with the general principles of why it's there)... Nevertheless, my strong opinions aren't a justification to simply ignore guidelines (and this is also not the place to debate on said guidelines), so I'll go around and remove excessive blank lines 🫣 |
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.
Looks good for tracing. If @rarguelloF or @zarirhamza could review on behalf of the FI team that would be great!
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.
Contrib looks good too, glad to see better graphQL instrumentation
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.
Congrats - very amazing work and super happy to see such a good level of testing.
I left side notes only for the record, nothing to address immediately.
"gopkg.in/DataDog/dd-trace-go.v1/internal/appsec" | ||
) | ||
|
||
func TestAppSec(t *testing.T) { |
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.
amazing test 👏
// returns a function to restore the previous environment state. | ||
func enableAppSec(t *testing.T) func() { | ||
const rules = `{ | ||
"version": "2.2", |
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.
Note: there's a helper function template somewhere in internal/appsec that you could leverage too.
The reason is that the rule format changed a few times so we created constructors instead at some point.
err = os.WriteFile(rulesFile, []byte(rules), 0644) | ||
require.NoError(t, err) | ||
t.Setenv("DD_APPSEC_ENABLED", "1") | ||
t.Setenv("DD_APPSEC_RULES", rulesFile) |
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.
Would we useful to accept inlined rules in the string value - worth adding this idea in the backlog:
Pull Request is not mergeable
What does this PR do?
Adds a new in-app WAF integration for GraphQL to
dyngo
. Also adds a new contrib forgithub.com/grapgql-go/graphql
to ensure the integration is not unnecessarily middleware-dependent.The
graphql.server.all_resolvers
address can currently only be sent to the WAF after all resolvers have executed, as doing otherwise would require re-parsing the query and matching fields to variables, which is unnecessarily expensive.Blocking capabilities will require further work (possibly dynamic instrumentation) as the tracing hooks provided by both supported middleware fail to allow altering the response flow (e.g: returning an error instead of invoking the field resolvers).
Motivation
This provides in-app WAF support for GraphQL operations.
Reviewer's Checklist
For Datadog employees:
@DataDog/security-design-and-guidance
.Unsure? Have a question? Request a review!