-
Notifications
You must be signed in to change notification settings - Fork 324
Ensure all restHeaders from ActionPlugin.getRestHeaders are carried to threadContext for tracing #5396
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?
Conversation
…o threadContext for tracing Signed-off-by: Craig Perkins <cwperx@amazon.com>
requestHeadersToCopy, | ||
getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_REQUEST_HEADERS).split(",") | ||
); | ||
requestHeadersToCopy.remove(Task.X_OPAQUE_ID); // Special case where this header is preserved during stashContext. |
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.
The changes in this file are necessary because currently only X_OPAQUE_ID
is not lost when stashing here: https://github.com/opensearch-project/OpenSearch/blob/main/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java#L157-L163
Ideally, this is solved another way through the core. Either:
- Change X_OPAQUE_ID to a persistent header and remove the logic in
stashContext
. persistentHeaders are a special category of headers that are not stashable. - Update the logic in ThreadContext to not stash any of the headers from https://github.com/opensearch-project/OpenSearch/blob/main/server/src/main/java/org/opensearch/action/ActionModule.java#L581-L586
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.
IMO, option 1 is better.
@sgup432 This PR would need additional tests, but this is what the general changes could look like if just done within the confines of the security plugin. |
Signed-off-by: Craig Perkins <cwperx@amazon.com>
Signed-off-by: Craig Perkins <cwperx@amazon.com>
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #5396 +/- ##
=======================================
Coverage 72.76% 72.77%
=======================================
Files 397 397
Lines 24591 24606 +15
Branches 3741 3747 +6
=======================================
+ Hits 17894 17906 +12
- Misses 4867 4872 +5
+ Partials 1830 1828 -2
🚀 New features to boost your workflow:
|
@@ -130,7 +131,8 @@ public void testShouldAllowAtRestAndBlockAtTransport() { | |||
// granted at Rest layer | |||
auditLogsRule.assertExactlyOne(privilegePredicateRESTLayer(GRANTED_PRIVILEGES, REST_ONLY, GET, "/" + PROTECTED_API)); | |||
// missing at Transport layer | |||
auditLogsRule.assertExactlyOne( | |||
auditLogsRule.assertExactlyScanAll( |
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.
It was tricky fixing the tests in this file. The reason these started to fail is because of the logic here to separate REST-Layer audit logs from Transport-Layer audit logs. We should find a more robust way to handle this and aim to have robust assertions in the tests.
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.
Why scan all to only evaluate 1?
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.
All of these assertions need to be revisited after this bugfix.
From what I've gathered, the test audit log tries to split messages into 2 distinct categories:
- REST-Layer messages
- Transport-Layer messages
The previous logic to sort these was not working properly and relied on the present of audit_transport_headers
to determine if the message was from the transport-layer.
I'm using this method here because it was the only appropriate one I found, but I think the right fix is either not to separate the messages into each category or to make sure the logic to separate the messages is correct.
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.
okay, would you mind opening an issue (good-first issue?) to address this in future.
if (xOpaqueId != null) { | ||
threadContext.putHeader(Task.X_OPAQUE_ID, xOpaqueId); | ||
for (Map.Entry<String, String> header : tmpHeaders.entrySet()) { | ||
threadContext.putHeader(header.getKey(), header.getValue()); |
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.
qq, will values be null for any header?
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.
no, null is not possible. There could be empty
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.
does this need specific headers or all headers? Copying/populating all headers might be costly?
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.
+1 Could this cause perf regression?
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.
See the linked issue: #4799
There is a bug with ActionPlugin.getRestHeaders() where the headers are getting dropped because the security plugin is not carrying them from rest -> transport and then also propagating them internally in the transport layer.
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.
Don't think this would have a high performance penalty.
requestHeadersToCopy, | ||
getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_REQUEST_HEADERS).split(",") | ||
); | ||
requestHeadersToCopy.remove(Task.X_OPAQUE_ID); // Special case where this header is preserved during stashContext. |
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.
IMO, option 1 is better.
@@ -130,7 +131,8 @@ public void testShouldAllowAtRestAndBlockAtTransport() { | |||
// granted at Rest layer | |||
auditLogsRule.assertExactlyOne(privilegePredicateRESTLayer(GRANTED_PRIVILEGES, REST_ONLY, GET, "/" + PROTECTED_API)); | |||
// missing at Transport layer | |||
auditLogsRule.assertExactlyOne( | |||
auditLogsRule.assertExactlyScanAll( |
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.
Why scan all to only evaluate 1?
src/main/java/org/opensearch/security/support/ConfigConstants.java
Outdated
Show resolved
Hide resolved
if (xOpaqueId != null) { | ||
threadContext.putHeader(Task.X_OPAQUE_ID, xOpaqueId); | ||
for (Map.Entry<String, String> header : tmpHeaders.entrySet()) { | ||
threadContext.putHeader(header.getKey(), header.getValue()); |
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.
+1 Could this cause perf regression?
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | |||
- Create a mechanism for plugins to explicitly declare actions they need to perform with their assigned PluginSubject ([#5341](https://github.com/opensearch-project/security/pull/5341)) | |||
|
|||
### Changed | |||
- Ensure all restHeaders from ActionPlugin.getRestHeaders are carried to threadContext for tracing ([#5396](https://github.com/opensearch-project/security/pull/5396)) |
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 is the motivation for this change? Without this how hard is it be debug?
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.
See the issue as described here: #4799
WLM (workload management) found this issue bc they have logic to tag queries and assign them to groups. It was noticed that after overridding ActionPlugin.getRestHeaders()
the the headers they expected to trace around with the entire request handling process (i.e. from rest down to transport and carried node-to-node) were getting dropped bc of logic in the security repo to control what headers are sent internally. Not all HTTP Headers should be copied to the threadcontext and carried around, but the one's explicitly allowed via ActionPlugin.getRestHeaders()
should be.
Signed-off-by: Craig Perkins <cwperx@amazon.com>
Signed-off-by: Craig Perkins <cwperx@amazon.com>
Signed-off-by: Craig Perkins <cwperx@amazon.com>
Description
This PR ensures that allowlisted headers from ActionPlugin.getRestHeaders() are carried from HTTP Headers -> ThreadContext headers in order to trace a request end-to-end through the cluster.
Bug fix
Issues Resolved
Resolves #4799
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.