-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Cloud Security] [Findings] [Misconfigurations] [Alerts] - Create det…
…ection rule (#162750) Co-authored-by: kibanamachine <[email protected]>
- Loading branch information
1 parent
c04f566
commit c0fe4ac
Showing
6 changed files
with
302 additions
and
3 deletions.
There are no files selected for viewing
59 changes: 59 additions & 0 deletions
59
x-pack/plugins/cloud_security_posture/public/common/api/create_detection_rule.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
import { HttpSetup } from '@kbn/core/public'; | ||
|
||
const DETECTION_ENGINE_URL = '/api/detection_engine' as const; | ||
const DETECTION_ENGINE_RULES_URL = `${DETECTION_ENGINE_URL}/rules` as const; | ||
|
||
interface RuleCreateProps { | ||
type: string; | ||
language: string; | ||
license: string; | ||
author: string[]; | ||
filters: any[]; | ||
false_positives: any[]; | ||
risk_score: number; | ||
risk_score_mapping: any[]; | ||
severity: string; | ||
severity_mapping: any[]; | ||
threat: any[]; | ||
interval: string; | ||
from: string; | ||
to: string; | ||
timestamp_override: string; | ||
timestamp_override_fallback_disabled: boolean; | ||
actions: any[]; | ||
enabled: boolean; | ||
alert_suppression: { | ||
group_by: string[]; | ||
missing_fields_strategy: string; | ||
}; | ||
index: string[]; | ||
query: string; | ||
references: string[]; | ||
name: string; | ||
description: string; | ||
tags: string[]; | ||
} | ||
|
||
export interface RuleResponse extends RuleCreateProps { | ||
id: string; | ||
} | ||
|
||
export const createDetectionRule = async ({ | ||
http, | ||
rule, | ||
}: { | ||
http: HttpSetup; | ||
rule: RuleCreateProps; | ||
}): Promise<RuleResponse> => { | ||
const res = await http.post<RuleCreateProps>(DETECTION_ENGINE_RULES_URL, { | ||
body: JSON.stringify(rule), | ||
}); | ||
|
||
return res as RuleResponse; | ||
}; |
129 changes: 129 additions & 0 deletions
129
x-pack/plugins/cloud_security_posture/public/components/take_action.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React, { useState } from 'react'; | ||
import { | ||
EuiButton, | ||
EuiContextMenuItem, | ||
EuiContextMenuPanel, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiPopover, | ||
EuiText, | ||
useGeneratedHtmlId, | ||
} from '@elastic/eui'; | ||
import { toMountPoint } from '@kbn/kibana-react-plugin/public'; | ||
import type { HttpSetup } from '@kbn/core/public'; | ||
import { FormattedMessage } from '@kbn/i18n-react'; | ||
import { CREATE_RULE_ACTION_SUBJ, TAKE_ACTION_SUBJ } from './test_subjects'; | ||
import { useKibana } from '../common/hooks/use_kibana'; | ||
import type { RuleResponse } from '../common/api/create_detection_rule'; | ||
|
||
const RULE_PAGE_PATH = '/app/security/rules/id/'; | ||
|
||
interface TakeActionProps { | ||
createRuleFn: (http: HttpSetup) => Promise<RuleResponse>; | ||
} | ||
/* | ||
* This component is used to create a detection rule from Flyout. | ||
* It accepts a createRuleFn parameter which is used to create a rule in a generic way. | ||
*/ | ||
export const TakeAction = ({ createRuleFn }: TakeActionProps) => { | ||
const [isPopoverOpen, setPopoverOpen] = useState(false); | ||
const [isLoading, setIsLoading] = useState(false); | ||
const closePopover = () => { | ||
setPopoverOpen(false); | ||
}; | ||
|
||
const smallContextMenuPopoverId = useGeneratedHtmlId({ | ||
prefix: 'smallContextMenuPopover', | ||
}); | ||
|
||
const { http, notifications } = useKibana().services; | ||
|
||
const showSuccessToast = (ruleResponse: RuleResponse) => { | ||
return notifications.toasts.addSuccess({ | ||
toastLifeTimeMs: 10000, | ||
color: 'success', | ||
iconType: '', | ||
text: toMountPoint( | ||
<div> | ||
<EuiText size="m"> | ||
<strong>{ruleResponse.name}</strong> | ||
{` `} | ||
<FormattedMessage | ||
id="xpack.csp.flyout.ruleCreatedToastTitle" | ||
defaultMessage="detection rule was created." | ||
/> | ||
</EuiText> | ||
<EuiText size="s"> | ||
<FormattedMessage | ||
id="xpack.csp.flyout.ruleCreatedToast" | ||
defaultMessage="Add rule actions to get notified when alerts are generated." | ||
/> | ||
</EuiText> | ||
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButton size="s" href={http.basePath.prepend(RULE_PAGE_PATH + ruleResponse.id)}> | ||
<FormattedMessage | ||
id="xpack.csp.flyout.ruleCreatedToastViewRuleButton" | ||
defaultMessage="View rule" | ||
/> | ||
</EuiButton> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</div> | ||
), | ||
}); | ||
}; | ||
|
||
const button = ( | ||
<EuiButton | ||
isLoading={isLoading} | ||
fill | ||
iconType="arrowDown" | ||
iconSide="right" | ||
onClick={() => setPopoverOpen(!isPopoverOpen)} | ||
> | ||
<FormattedMessage id="xpack.csp.flyout.takeActionButton" defaultMessage="Take action" /> | ||
</EuiButton> | ||
); | ||
|
||
return ( | ||
<EuiPopover | ||
id={smallContextMenuPopoverId} | ||
button={button} | ||
isOpen={isPopoverOpen} | ||
closePopover={closePopover} | ||
panelPaddingSize="none" | ||
anchorPosition="downLeft" | ||
data-test-subj={TAKE_ACTION_SUBJ} | ||
> | ||
<EuiContextMenuPanel | ||
size="s" | ||
items={[ | ||
<EuiContextMenuItem | ||
key="createRule" | ||
onClick={async () => { | ||
closePopover(); | ||
setIsLoading(true); | ||
const ruleResponse = await createRuleFn(http); | ||
setIsLoading(false); | ||
showSuccessToast(ruleResponse); | ||
}} | ||
data-test-subj={CREATE_RULE_ACTION_SUBJ} | ||
> | ||
<FormattedMessage | ||
defaultMessage="Create a detection rule" | ||
id="xpack.csp.createDetectionRuleButton" | ||
/> | ||
</EuiContextMenuItem>, | ||
]} | ||
/> | ||
</EuiPopover> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
..._security_posture/public/pages/configurations/utils/create_detection_rule_from_finding.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { HttpSetup } from '@kbn/core/public'; | ||
import type { CspFinding } from '../../../../common/schemas/csp_finding'; | ||
import { LATEST_FINDINGS_INDEX_DEFAULT_NS } from '../../../../common/constants'; | ||
import { createDetectionRule } from '../../../common/api/create_detection_rule'; | ||
|
||
const DEFAULT_RULE_RISK_SCORE = 0; | ||
const DEFAULT_RULE_SEVERITY = 'low'; | ||
const DEFAULT_RULE_ENABLED = true; | ||
const DEFAULT_RULE_AUTHOR = 'Elastic'; | ||
const DEFAULT_RULE_LICENSE = 'Elastic License v2'; | ||
const ALERT_SUPPRESSION_FIELD = 'resource.id'; | ||
const ALERT_TIMESTAMP_FIELD = 'event.ingested'; | ||
|
||
enum AlertSuppressionMissingFieldsStrategy { | ||
// per each document a separate alert will be created | ||
DoNotSuppress = 'doNotSuppress', | ||
// only one alert will be created per suppress by bucket | ||
Suppress = 'suppress', | ||
} | ||
|
||
const convertReferencesLinksToArray = (input: string | undefined) => { | ||
if (!input) { | ||
return []; | ||
} | ||
// Match all URLs in the input string using a regular expression | ||
const matches = input.match(/(https?:\/\/\S+)/g); | ||
|
||
if (!matches) { | ||
return []; | ||
} | ||
|
||
// Remove the numbers and new lines | ||
return matches.map((link) => link.replace(/^\d+\. /, '').replace(/\n/g, '')); | ||
}; | ||
|
||
const STATIC_RULE_TAGS = ['Elastic', 'Cloud Security']; | ||
|
||
const generateMisconfigurationsTags = (finding: CspFinding) => { | ||
return [STATIC_RULE_TAGS] | ||
.concat(finding.rule.tags) | ||
.concat( | ||
finding.rule.benchmark.posture_type ? [finding.rule.benchmark.posture_type.toUpperCase()] : [] | ||
) | ||
.flat(); | ||
}; | ||
|
||
const generateMisconfigurationsRuleQuery = (finding: CspFinding) => { | ||
return ` | ||
rule.benchmark.rule_number: "${finding.rule.benchmark.rule_number}" | ||
AND rule.benchmark.id: "${finding.rule.benchmark.id}" | ||
AND result.evaluation: "failed" | ||
`; | ||
}; | ||
|
||
/* | ||
* Creates a detection rule from a CspFinding | ||
*/ | ||
export const createDetectionRuleFromFinding = async (http: HttpSetup, finding: CspFinding) => { | ||
return await createDetectionRule({ | ||
http, | ||
rule: { | ||
type: 'query', | ||
language: 'kuery', | ||
license: DEFAULT_RULE_LICENSE, | ||
author: [DEFAULT_RULE_AUTHOR], | ||
filters: [], | ||
false_positives: [], | ||
risk_score: DEFAULT_RULE_RISK_SCORE, | ||
risk_score_mapping: [], | ||
severity: DEFAULT_RULE_SEVERITY, | ||
severity_mapping: [], | ||
threat: [], | ||
interval: '1h', | ||
from: 'now-7200s', | ||
to: 'now', | ||
timestamp_override: ALERT_TIMESTAMP_FIELD, | ||
timestamp_override_fallback_disabled: false, | ||
actions: [], | ||
enabled: DEFAULT_RULE_ENABLED, | ||
alert_suppression: { | ||
group_by: [ALERT_SUPPRESSION_FIELD], | ||
missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.Suppress, | ||
}, | ||
index: [LATEST_FINDINGS_INDEX_DEFAULT_NS], | ||
query: generateMisconfigurationsRuleQuery(finding), | ||
references: convertReferencesLinksToArray(finding.rule.references), | ||
name: finding.rule.name, | ||
description: finding.rule.rationale, | ||
tags: generateMisconfigurationsTags(finding), | ||
}, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters