-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[core.logging] Add RewriteAppender for filtering LogMeta. #91492
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
Conversation
68e0019 to
4372efa
Compare
4372efa to
0d7b5c9
Compare
0d7b5c9 to
ae5facc
Compare
|
Pinging @elastic/kibana-core (Team:Core) |
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.
Currently all sensitive headers are filtered in the http response logging, and the filters cannot be disabled.
In this PR, I removed the filtering code from http, and here have "wrapped" our default console appender in a rewrite appender that performs the same logic.
However, there is one main caveat: While this ensures nothing sensitive is logged with a default configuration, the protection is gone as soon as you customize your config to use something other than the console appender. I tried to think of another way to enforce this more widely while also making it configurable, and I didn't come up with any great solutions that didn't involve creating another standalone config option. Open to suggestions though!
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.
While this ensures nothing sensitive is logged with a default configuration, the protection is gone as soon as you customize your config to use something other than the console appender. I tried to think of another way to enforce this more widely while also making it configurable, and I didn't come up with any great solutions that didn't involve creating another standalone config option.
That might be a reason not to use RewriteAppender internally to filter out sensitive data (but provide it as public API). We can either implement a custom filtering logic always applicable to http.request / http.response contexts. Or filter out sensitive properties when creating meta object https://github.com/elastic/kibana/blob/master/src/core/server/http/logging/get_response_log.ts
How it works now in the Legacy platform? Does it always censor the sensitive content?
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.
Or filter out sensitive properties when creating meta object
@restrry Yeah, that's the approach we take now, the only issue is that it can't be disabled, and IIRC this was one of the reasons we wanted a rewrite appender to begin with, for the case where we have a reason to allow sensitive headers through for support/debugging purposes.
That's why the only alternative that comes to mind is a new config option to disable filters, which would then be used inside the http response logger getResponseLog. But in the spirit of having One Way Of Doing Things (TM), it'd be nice to use the existing config if we can.
Actually, as I think about it, this is an issue that would possibly be solved by our discussion around having logger-specific default appender configurations.
How it works now in the Legacy platform? Does it always censor the sensitive content?
It filters them out by default (just authorization and cookie), but you can disable that using the (undocumented) logging.filter settings - e.g. logging.filter.cookie=none to remove filter from that header in hapi/good.
kibana/packages/kbn-legacy-logging/src/get_logging_config.ts
Lines 53 to 60 in 72670eb
| // I'm adding the default here because if you add another filter | |
| // using the commandline it will remove authorization. I want users | |
| // to have to explicitly set --logging.filter.authorization=none or | |
| // --logging.filter.cookie=none to have it show up in the logs. | |
| filter: _.defaults(config.filter, { | |
| authorization: 'remove', | |
| cookie: 'remove', | |
| }), |
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.
Yeah, that's the approach we take now, the only issue is that it can't be disabled, and IIRC this was one of the reasons we wanted a rewrite appender to begin with, for the case where we have a reason to allow sensitive headers through for support/debugging purposes.
I'd say it's nice to have. It is better to not add such a feature than to add it but with the possibility of sensitive data leakage due to incorrect configuration:
While this ensures nothing sensitive is logged with a default configuration,
the protection is gone as soon as you customize your config to use something other than the console appender.
Actually, as I think about it, this is an issue that would possibly be solved by our discussion around having logger-specific default appender configurations.
Are you implying that we can hide the Meta object from the logs? The pattern does not apply to json layout.
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.
I'd say it's nice to have. It is better to not add such a feature than to add it but with the possibility of sensitive data leakage due to incorrect configuration
Fair point, so do you think we should:
- Keep the hardcoded filtering of sensitive header fields, meaning we can't turn those off for debugging purposes
- Go with option 1 but also introduce a new config flag to disable this for debugging purposes (e.g.
logging.filterSensitiveHttpHeadersor whatever). The flag would default totruebut could be disabled if someone wanted to use a custom rewrite appender. - Some other option I'm not thinking of?
Ideally I'd like to not introduce another config flag, but I'm also unsure of how we could otherwise make it possible to disable the filtering.
Are you implying that we can hide the Meta object from the logs?
No, sorry that was a bit vague. I meant if we went the route of having predefined default appender configurations on a per-logger basis (similar to the ES config file), then this would be another use case for those and would solve this problem. But if we go the simpler route of removing the meta from the pattern by default, that won't help us in this case.
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.
Keep the hardcoded filtering of sensitive header fields, meaning we can't turn those off for debugging purposes
As for me, it's an acceptable trade-off. Any other opinions? @joshdover @pgayvallet @TinaHeiligers
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.
Yeah the more I think about it, the hardcoded approach feels like the safest option for the time being. And then if we were to consider an enhancement in 8.x to support logger-specific appender defaults as discussed in #90457, it would allow us to move these settings there anyway.
docs/development/core/server/kibana-plugin-core-server.savedobjectsfindresult.sort.md
Outdated
Show resolved
Hide resolved
src/core/server/logging/appenders/rewrite/policies/meta/meta_policy.ts
Outdated
Show resolved
Hide resolved
While I understand that the initial implementation is pretty much a MVP, IMHO, I must disagree with not documenting the The fact the filtering in the LP isn't documented shouldn't hold us back from doing the right thing, at least at the dev level. |
|
@TinaHeiligers I'm perfectly comfortable documenting this for devs -- I think the only reason we previously decided to make this internal was because the legacy filtering is also undocumented and we wanted to reserve the right to make changes in the future (or decide whether we want to support this functionality long-term at all). Since we don't yet have proper docs on the new logging system, I will just add a mention to the |
|
|
||
| export const createRewritePolicy = (config: RewritePolicyConfig): RewritePolicy => { | ||
| switch (config.type) { | ||
| case 'meta': |
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.
I can't find MetaRewritePolicy in log4j http://logging.apache.org/log4j/2.x/manual/appenders.html#RewritePolicy
Do we call so because we apply a policy to Meta object only?
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.
I think MetaRewritePolicy is a combined modification of log4j's MapRewritePolicy and PropertiesRewritePolicy where we're using the type field and the properties field rather than the keyValuePair in MetaRewritePolicy and we're allowing fields to be added too ( what PropertiesRewritePolicy does). And, yes, the policy is applied to the meta property. It's hard to tell though because our implementation isn't a 1-to-1 with log4j.
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.
Do we call so because we apply a policy to Meta object only?
Yeah exactly, they have a map and properties rewrite policy, so I called this meta as it is only scoped to the LogMeta. With this pattern, in the future we could have something like a message or level policy that will rewrite those items specifically.
src/core/server/logging/appenders/rewrite/policies/meta/meta_policy.test.ts
Outdated
Show resolved
Hide resolved
src/core/server/logging/appenders/rewrite/policies/meta/meta_policy.ts
Outdated
Show resolved
Hide resolved
src/core/server/logging/appenders/rewrite/policies/meta/meta_policy.ts
Outdated
Show resolved
Hide resolved
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.
While this ensures nothing sensitive is logged with a default configuration, the protection is gone as soon as you customize your config to use something other than the console appender. I tried to think of another way to enforce this more widely while also making it configurable, and I didn't come up with any great solutions that didn't involve creating another standalone config option.
That might be a reason not to use RewriteAppender internally to filter out sensitive data (but provide it as public API). We can either implement a custom filtering logic always applicable to http.request / http.response contexts. Or filter out sensitive properties when creating meta object https://github.com/elastic/kibana/blob/master/src/core/server/http/logging/get_response_log.ts
How it works now in the Legacy platform? Does it always censor the sensitive content?
TinaHeiligers
left a comment
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.
I went through the initial implementation and it seems to make sense. I tried to pull the code and run it locally but keep hitting a config error on start up (probably local).
I'd really like to see something in the README on the final implementation though.
|
|
||
| export const createRewritePolicy = (config: RewritePolicyConfig): RewritePolicy => { | ||
| switch (config.type) { | ||
| case 'meta': |
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.
I think MetaRewritePolicy is a combined modification of log4j's MapRewritePolicy and PropertiesRewritePolicy where we're using the type field and the properties field rather than the keyValuePair in MetaRewritePolicy and we're allowing fields to be added too ( what PropertiesRewritePolicy does). And, yes, the policy is applied to the meta property. It's hard to tell though because our implementation isn't a 1-to-1 with log4j.
I'll update the README, but the example config I gave in the PR description should be working without an error if you want to play around with it. |
A direct copy-paste throws the following: Changing Removing the file appender solves that. What am I missing in the config? |
|
Ah sorry @TinaHeiligers, I added that example before #90764 was merged and some of the properties were renamed. I've updated now, let me know if you hit any issues. |
pgayvallet
left a comment
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.
Few NITS, overall looking great
src/core/server/logging/appenders/rewrite/policies/meta/meta_policy.ts
Outdated
Show resolved
Hide resolved
| result[key] = FORBIDDEN_HEADERS.includes(key) ? REDACTED_HEADER_TEXT : headers[key]; | ||
| result[key] = redactSensitiveHeaders( | ||
| key, | ||
| Array.isArray(headers[key]) ? [...headers[key]] : headers[key] |
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.
optional: It's good we enforce immutability, but we pay the extra cost when cloning the array. IMO we can assume that no-one mutates the array.
|
@elasticmachine merge upstream |
|
@elasticmachine merge upstream |
TinaHeiligers
left a comment
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.
This is a great addition to our new logging system and even though we're not using the implementation in the default config right now, it's going to be super useful when we get around to #92082.
LGTM!
💚 Build SucceededMetrics [docs]
History
To update your PR or re-run it, just comment with: cc @lukeelmers |
* master: (38 commits) Fixes Cypress flake by adding pipe, click, and should (elastic#92762) [Discover] Fix filtering selected sidebar fields (elastic#91828) [ML] Fixes positions of calendar arrow buttons in start datafeed modal (elastic#92625) [dev/build_ts_refs] check that commit in outDirs matches mergeBase (elastic#92513) add dep on `@kbn/config` so it is built first [Expressions] [Lens] Add id and copyMetaFrom arg to mapColumn fn + add configurable onError argument to math fn (elastic#90481) [Lens] Fix Workspace hidden when using Safari (elastic#92616) [Lens] Fixes vertical alignment validation messages (elastic#91878) forbid x-elastic-product-origin header in elasticsearch configuration (elastic#92359) [Security Solution][Detections] Set default indicator path to reduce friction with new filebeat modules (elastic#92081) [ILM][Accessibility] Added A11y test for ILM new policy form. (elastic#92570) [Security Solution][Exceptions] - Fixes exceptions builder UI where invalid values can cause overwrites of other values (elastic#90634) Automatically generated Api documentation (elastic#86232) Increase index pattern select limit to 1000 (elastic#92093) [core.logging] Add RewriteAppender for filtering LogMeta. (elastic#91492) [Security Solution][Detection Rules] Update prebuilt rule threats to match schema (elastic#92281) [Security Solutions][Detection Engine] Fixes bug with not being able to duplicate indicator matches (elastic#92565) [Dashboard] Export appropriate references from byValue panels (elastic#91567) [Upgrade Assistant] Align code between branches (elastic#91862) [Security Solution][Case] Fix alerts push (elastic#91638) ...
Closes #57547
Summary
Implements a
RewriteAppenderfor the purposes of filtering / manipulating aLogRecord, as described in the original issue. The approach here is based on log4j2's RewriteAppender.Each rewrite appender uses a designated
policywhich describes what part of theLogRecordto manipulate. This PR starts with a singlemetapolicy for modifyingLogMeta. The policy has amodewhich can either beremoveorupdate, and takes in a list of paths in theLogMetaobject which are to be modified.For the time being we are intentionally keeping this undocumented in the public docs in case we choose to make future changes, as the legacy filtering behavior was also undocumented.
Usage
Here's a full example configuration which logs both to the console and a log file, censoring the
cookierequest header from the http response logs:The
removemode does not take a value as it simply deletes the provided path: