-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[core.logging] Add RewriteAppender for filtering LogMeta. #91492
Conversation
68e0019
to
4372efa
Compare
4372efa
to
0d7b5c9
Compare
0d7b5c9
to
ae5facc
Compare
Pinging @elastic/kibana-core (Team:Core) |
// By default, we transparently rewrite `LogMeta` sent to the | ||
// console appender to remove potentially sensitive keys. | ||
// This can be overridden in a logger's configuration. | ||
'console', | ||
{ | ||
type: 'rewrite', | ||
appenders: ['stdout'], | ||
policy: { | ||
type: 'meta', | ||
mode: 'update', | ||
properties: SENSITIVE_META_PATHS.map((path) => ({ path, value: REDACTED_META_TEXT })), | ||
}, | ||
} as AppenderConfigType, |
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.filterSensitiveHttpHeaders
or whatever). The flag would default totrue
but 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
// By default, we transparently rewrite `LogMeta` sent to the | ||
// console appender to remove potentially sensitive keys. | ||
// This can be overridden in a logger's configuration. | ||
'console', | ||
{ | ||
type: 'rewrite', | ||
appenders: ['stdout'], | ||
policy: { | ||
type: 'meta', | ||
mode: 'update', | ||
properties: SENSITIVE_META_PATHS.map((path) => ({ path, value: REDACTED_META_TEXT })), | ||
}, | ||
} as AppenderConfigType, |
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.
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. |
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 |
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
RewriteAppender
for 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
policy
which describes what part of theLogRecord
to manipulate. This PR starts with a singlemeta
policy for modifyingLogMeta
. The policy has amode
which can either beremove
orupdate
, and takes in a list of paths in theLogMeta
object 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
cookie
request header from the http response logs:The
remove
mode does not take a value as it simply deletes the provided path: