-
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
[alerting] Adds whitelisting configuration for the builtin webhooks action #44242
Conversation
💔 Build Failed |
…Kiabana configs making them an action specific concern
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 was imagining something much simpler - single config whitelist property, and some library function an action can call to check to see if a particular hostname/url/whatever-we-whitelist-on is "valid", probably returning a response object {status, message} that the action can just return (single translated message in the lib function).
Not sure if we really need per-action whitelists; maybe I missed a discussion on that.
@@ -8,6 +8,7 @@ jest.mock('./lib/send_email', () => ({ | |||
sendEmail: jest.fn(), | |||
})); | |||
|
|||
import { none } from 'fp-ts/lib/Option'; |
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.
Just happened to think; email takes either a host/port or "service name", where a service name is a nodemailer alias for a well-known host/port, eg, 'gmail'.
I believe we could probably check the ultimate host/port if a service name is provided (get it from nodemailer), so we could add a whitelisting check here. Understand if you don't want to tackle that in this PR, and if not, create a project card to do it later.
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.
Likewise, pagerduty and slack have default but overridable http scheme/host/port values we should be able to whitelist.
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, I was definitely focusing on Webhooks here.
I definitely think we need to take into account what email/slack need when designing the solution, but the implementation should probably be a follow up PR.
It's a good point that in webhooks you might want to "whitelist hostnames and paths", while in email "hostnames and nodemailer aliases", this feels like an argument for separate whitelists, as the needs are different.
No? 🤔
x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts
Outdated
Show resolved
Hide resolved
return configObject => { | ||
const { url }: ActionTypeConfigType = configObject; | ||
|
||
const anyUrlAllowed = kibanaConfig |
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 looks like the config takes a list of urls (things parseable as a Url), but only checks the hostname. If that's the case, I think the whitelist should just contain the hostname, otherwise it's a bit confusing; it looks like you could whitelist https://bob.com
, and then hope that http://bob.com
wouldn't pass whitelist validation, but it would.
We also have one non-http action - email - so using an url for that would be slightly odd.
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, I was wondering about that and figured I'd just push it a a draft and then have a conversation.
The question I had in the back of my ind was - might we want to whitelist a specific path and not a whole hostname?
@@ -59,6 +59,10 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) | |||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'alerts')}`, | |||
`--plugin-path=${path.join(__dirname, 'fixtures', 'plugins', 'actions')}`, | |||
`--server.xsrf.whitelist=${JSON.stringify(getAllExternalServiceSimulatorPaths())}`, | |||
`--xpack.actions.webhook.whitelistedEndpoints=${JSON.stringify([ |
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'm not sure that we really need or want action-specific config values here; I was imagining a single list used across all actions. That wouldn't allow you to allow a url for one action, and not for another, but I'm not sure there's a real use case there. Seems like it could simplify the code.
If we do have action-specific whitelists, should we check if they specify a config for an action that doesn't exist, like ... they mispelled it? "warning: action whitelist config specified for non-existant action foo-bob"
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.
Added comments on this here: https://github.com/elastic/kibana-team/issues/136
Felt like the conversation was being split too much between Slack/PR/Issue :)
url: schema.string(), | ||
method: schema.oneOf([schema.literal(WebhookMethods.POST), schema.literal(WebhookMethods.PUT)], { | ||
defaultValue: WebhookMethods.POST, | ||
}), | ||
headers: nullableType(HeadersSchema), | ||
}; | ||
export type ActionTypeConfigType = TypeOf<typeof UnvalidatedConfigSchema>; |
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.
there's something about not having these type and schema's name "match" that feels not right :-)
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.
Hmm fair.
The reason for "ActionTypeConfigType" is to align with the other actions.
The UnvalidatedConfigSchema is because... it doesn't have validation attached, the reason being that we can't yet attach validation because we don't have the configuration at the time of parsing the module yet.
I was hoping to find a way to "attach" validation to a Schema and so we wouldn't need two versions but it doesn't look possible.
I'll rename it so it aligns, because I know what you mean... but... it also feel wrong to not be explicit about it not having the expected validation... :/
@@ -4,31 +4,103 @@ | |||
* you may not use this file except in compliance with the Elastic License. | |||
*/ | |||
import { i18n } from '@kbn/i18n'; | |||
import { URL } from 'url'; | |||
import Boom from 'boom'; |
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.
just checked and we currently aren't using Boom in the other actions, so this is maybe a smell. Basically, actions never throw errors :-) . I think in the Boom usage below, you can just return a {status, message}
object instead of throwing.
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 thought we do when a schema is validated:
throw Boom.badRequest(`error validating ${name}: ${err.message}`); |
I used Boom for that reason - to align with the other validations.
@@ -4,6 +4,7 @@ | |||
* you may not use this file except in compliance with the Elastic License. | |||
*/ | |||
|
|||
import { Option } from 'fp-ts/lib/Option'; |
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 Option<T>
is just T | undefined
- oh, looking at it, it's ... a thing!
Not sure we want to expose this in an API that a customer may have to code against - they'll need to pull in fp-ts
as well in their action code?
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.
Well, the point of an Option is as a guard against null and undefined.
Ideally you don't want developers to have to think about null/undefined and anything that has the possibility of not being there is exposed as an Option. Once you get used to an Option based code base, it's hard to go back to the numerous null checks that usually fill JS codebases 🤷♂️
I was a little worried that I might be jumping into the deep end with this as people who aren't used to it will find it weird, but having completely moved away from nulls (and null pointer exceptions) over the past few years... it's very attractive to use Optionals to step up our use of the typesystem and null safety.
I guess this is a debate we need to have about whether we'd like to try and provide a "null safe" approach to interacting with our code using Optionals, or leave that to developers.
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 issue of "customer may have to code against... fp-ts" mioght be an issue, I'm just not familiar with how we expect these customers to add their own code.
Will that be within Kibana or as external code?
Pinging @elastic/kibana-stack-services |
💚 Build Succeeded |
💚 Build Succeeded |
💚 Build Succeeded |
…cluded protocols breaking the tests
💔 Build Failed |
💚 Build Succeeded |
Closing as a new PR will include a deeper refactoring that'll allow this to be done better. |
Summary
Adds whitelisting configuration for the builtin webhooks action.
Refers to: https://github.com/elastic/kibana-team/issues/136
Checklist
Use
strikethroughsto remove checklist items you don't feel are applicable to this PR.For maintainers