Skip to content

Commit

Permalink
Common data store for the rules (opensearch-project#474)
Browse files Browse the repository at this point in the history
* [FEATURE] Common data store for the rules opensearch-project#473

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Common data store for the rules opensearch-project#473

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Common data store for the rules opensearch-project#473

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Common data store for the rules opensearch-project#473
Fix cypress create rules flaky tests opensearch-project#426

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Common data store for the rules opensearch-project#473
Fix cypress create rules flaky tests opensearch-project#426

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Common data store for the rules opensearch-project#473

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* [FEATURE] Common data store for the rules opensearch-project#473

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>

---------

Signed-off-by: Jovan Cvetkovic <jovanca.cvetkovic@gmail.com>
  • Loading branch information
jovancacvetkovic committed Mar 14, 2023
1 parent 326fdbc commit 7fcfb5a
Show file tree
Hide file tree
Showing 41 changed files with 647 additions and 772 deletions.
117 changes: 117 additions & 0 deletions cypress/fixtures/sample_rule.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{
"ok": true,
"response": {
"hits": {
"hits": [
{
"_index": ".opensearch-sap-pre-packaged-rules-config",
"_id": "503fe26e-b5f2-4944-a126-eab405cc06e51",
"_version": 1,
"_seq_no": 1885,
"_primary_term": 1,
"_score": 1,
"_source": {
"category": "network",
"title": "Kerberos Network Traffic RC4 Ticket Encryption",
"log_source": "",
"description": "Detects kerberos TGS request using RC4 encryption which may be indicative of kerberoasting",
"references": [
{
"value": "https://adsecurity.org/?p=3458"
}
],
"tags": [
{
"value": "attack.credential_access"
},
{
"value": "attack.t1558.003"
}
],
"level": "medium",
"false_positives": [
{
"value": "Normal enterprise SPN requests activity"
}
],
"author": "sigma",
"status": "test",
"last_update_time": "2020-02-11T23:00:00.000Z",
"queries": [
{
"value": "((zeek-kerberos-request_type: \"TGS\") AND (zeek-kerberos-cipher: \"rc4\\-hmac\")) AND ((NOT service: $*))"
}
],
"query_field_names": [
{
"value": "zeek-kerberos-cipher"
},
{
"value": "service"
},
{
"value": "zeek-kerberos-request_type"
}
],
"aggregationQueries": [],
"rule": "title: Kerberos Network Traffic RC4 Ticket Encryption\nid: 503fe26e-b5f2-4944-a126-eab405cc06e5\nstatus: test\ndescription: Detects kerberos TGS request using RC4 encryption which may be indicative of kerberoasting\nauthor: sigma\nreferences:\n - https://adsecurity.org/?p=3458\ndate: 2020/02/12\nmodified: 2021/11/27\nlogsource:\n product: zeek\n service: kerberos\ndetection:\n selection:\n request_type: 'TGS'\n cipher: 'rc4-hmac'\n computer_acct:\n service|startswith: '$'\n condition: selection and not computer_acct\nfalsepositives:\n - Normal enterprise SPN requests activity\nlevel: medium\ntags:\n - attack.credential_access\n - attack.t1558.003\n"
}
},
{
"_index": ".opensearch-sap-pre-packaged-rules-config",
"_id": "503fe26e-b5f2-4944-a126-eab405cc06e5",
"_version": 1,
"_seq_no": 1885,
"_primary_term": 1,
"_score": 1,
"_source": {
"category": "network",
"title": "Kerberos Network Traffic RC4 Ticket Encryption",
"log_source": "",
"description": "Detects kerberos TGS request using RC4 encryption which may be indicative of kerberoasting",
"references": [
{
"value": "https://adsecurity.org/?p=3458"
}
],
"tags": [
{
"value": "attack.credential_access"
},
{
"value": "attack.t1558.003"
}
],
"level": "medium",
"false_positives": [
{
"value": "Normal enterprise SPN requests activity"
}
],
"author": "sigma",
"status": "test",
"last_update_time": "2020-02-11T23:00:00.000Z",
"queries": [
{
"value": "((zeek-kerberos-request_type: \"TGS\") AND (zeek-kerberos-cipher: \"rc4\\-hmac\")) AND ((NOT service: $*))"
}
],
"query_field_names": [
{
"value": "zeek-kerberos-cipher"
},
{
"value": "service"
},
{
"value": "zeek-kerberos-request_type"
}
],
"aggregationQueries": [],
"rule": "title: Kerberos Network Traffic RC4 Ticket Encryption\nid: 503fe26e-b5f2-4944-a126-eab405cc06e5\nstatus: test\ndescription: Detects kerberos TGS request using RC4 encryption which may be indicative of kerberoasting\nauthor: sigma\nreferences:\n - https://adsecurity.org/?p=3458\ndate: 2020/02/12\nmodified: 2021/11/27\nlogsource:\n product: zeek\n service: kerberos\ndetection:\n selection:\n request_type: 'TGS'\n cipher: 'rc4-hmac'\n computer_acct:\n service|startswith: '$'\n condition: selection and not computer_acct\nfalsepositives:\n - Normal enterprise SPN requests activity\nlevel: medium\ntags:\n - attack.credential_access\n - attack.t1558.003\n"
}
}
]
}
}
}
30 changes: 23 additions & 7 deletions cypress/integration/2_rules.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ describe('Rules', () => {
force: true,
});

// Enter the log type
cy.get('[data-test-subj="rule_status_dropdown"]').type(SAMPLE_RULE.status);

// Enter the name
cy.get('[data-test-subj="rule_name_field"]').type(SAMPLE_RULE.name);

Expand All @@ -162,23 +165,24 @@ describe('Rules', () => {

// Enter the tags
SAMPLE_RULE.tags.forEach((tag) =>
cy.get('[data-test-subj="rule_tags_dropdown"]').type(`${tag}{enter}{esc}`)
cy.get('[data-test-subj="rule_tags_dropdown"]').type(`${tag}{enter}`)
);

// Enter the reference
cy.get('[data-test-subj="rule_references_field_0"]').type(SAMPLE_RULE.references);

// Enter the false positive cases
cy.get('[data-test-subj="rule_false_positives_field_0"]').type(SAMPLE_RULE.falsePositive);
cy.get('[data-test-subj="rule_false_positives_field_0"]').type(
`${SAMPLE_RULE.falsePositive}{enter}`
);

// Enter the author
cy.get('[data-test-subj="rule_author_field"]').type(SAMPLE_RULE.author);

// Enter the log type
cy.get('[data-test-subj="rule_status_dropdown"]').type(SAMPLE_RULE.status);
cy.get('[data-test-subj="rule_author_field"]').type(`${SAMPLE_RULE.author}{enter}`);

// Enter the detection
cy.get('[data-test-subj="rule_detection_field"]').type(SAMPLE_RULE.detection);
cy.get('[data-test-subj="rule_detection_field"] textarea').type(SAMPLE_RULE.detection, {
force: true,
});

// Switch to YAML editor
cy.get('[data-test-subj="change-editor-type"] label:nth-child(2)').click({
Expand Down Expand Up @@ -270,6 +274,15 @@ describe('Rules', () => {
url: '/rules',
}).as('deleteRule');

cy.intercept('POST', 'rules/_search?prePackaged=true', {
delay: 5000,
}).as('getPrePackagedRules');

cy.intercept('POST', 'rules/_search?prePackaged=false', {
delay: 5000,
}).as('getCustomRules');

cy.wait('@rulesSearch');
cy.get(`input[placeholder="Search rules"]`).ospSearch(SAMPLE_RULE.name);

// Click the rule link to open the details flyout
Expand All @@ -288,8 +301,11 @@ describe('Rules', () => {
.then(() => cy.get('.euiModalFooter > .euiButton').contains('Delete').click());

cy.wait('@deleteRule');
cy.wait('@getCustomRules');
cy.wait('@getPrePackagedRules');

// Search for sample_detector, presumably deleted
cy.wait(3000);
cy.get(`input[placeholder="Search rules"]`).ospSearch(SAMPLE_RULE.name);
// Click the rule link to open the details flyout
cy.get('tbody').contains(SAMPLE_RULE.name).should('not.exist');
Expand Down
13 changes: 4 additions & 9 deletions public/pages/Alerts/components/AlertFlyout/AlertFlyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,18 @@ import {
formatRuleType,
renderTime,
} from '../../../../utils/helpers';
import { FindingsService, RuleService, OpenSearchService } from '../../../../services';
import { FindingsService, OpenSearchService } from '../../../../services';
import FindingDetailsFlyout from '../../../Findings/components/FindingDetailsFlyout';
import { Detector } from '../../../../../models/interfaces';
import { parseAlertSeverityToOption } from '../../../CreateDetector/components/ConfigureAlerts/utils/helpers';
import { Finding } from '../../../Findings/models/interfaces';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { RulesViewModelActor } from '../../../Rules/models/RulesViewModelActor';
import { DataStore } from '../../../../store/DataStore';

export interface AlertFlyoutProps {
alertItem: AlertItem;
detector: Detector;
findingsService: FindingsService;
ruleService: RuleService;
notifications: NotificationsStart;
opensearchService: OpenSearchService;
onClose: () => void;
Expand All @@ -56,13 +55,9 @@ export interface AlertFlyoutState {
}

export class AlertFlyout extends React.Component<AlertFlyoutProps, AlertFlyoutState> {
private rulesViewModelActor: RulesViewModelActor;

constructor(props: AlertFlyoutProps) {
super(props);

this.rulesViewModelActor = new RulesViewModelActor(props.ruleService);

this.state = {
acknowledged: props.alertItem.state === ALERT_STATE.ACKNOWLEDGED,
findingItems: [],
Expand Down Expand Up @@ -113,12 +108,12 @@ export class AlertFlyout extends React.Component<AlertFlyoutProps, AlertFlyoutSt
});

if (ruleIds.length > 0) {
const rulesResponse = await this.rulesViewModelActor.fetchRules({
const rules = await DataStore.rules.getAllRules({
_id: ruleIds,
});

const allRules: { [id: string]: RuleSource } = {};
rulesResponse.forEach((hit) => (allRules[hit._id] = hit._source));
rules.forEach((hit) => (allRules[hit._id] = hit._source));

this.setState({ rules: allRules });
}
Expand Down
5 changes: 1 addition & 4 deletions public/pages/Alerts/containers/Alerts/Alerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import AlertsService from '../../../../services/AlertsService';
import DetectorService from '../../../../services/DetectorService';
import { AlertItem } from '../../../../../server/models/interfaces';
import { AlertFlyout } from '../../components/AlertFlyout/AlertFlyout';
import { FindingsService, RuleService, OpenSearchService } from '../../../../services';
import { FindingsService, OpenSearchService } from '../../../../services';
import { Detector } from '../../../../../models/interfaces';
import { parseAlertSeverityToOption } from '../../../CreateDetector/components/ConfigureAlerts/utils/helpers';
import { DISABLE_ACKNOWLEDGED_ALERT_HELP_TEXT } from '../../utils/constants';
Expand All @@ -62,7 +62,6 @@ export interface AlertsProps extends RouteComponentProps {
alertService: AlertsService;
detectorService: DetectorService;
findingService: FindingsService;
ruleService: RuleService;
opensearchService: OpenSearchService;
notifications: NotificationsStart;
match: match;
Expand Down Expand Up @@ -406,7 +405,6 @@ export class Alerts extends Component<AlertsProps, AlertsState> {
};

render() {
const { ruleService } = this.props;
const {
alerts,
alertsFiltered,
Expand Down Expand Up @@ -485,7 +483,6 @@ export class Alerts extends Component<AlertsProps, AlertsState> {
onClose={this.onFlyoutClose}
onAcknowledge={this.onAcknowledge}
findingsService={this.props.findingService}
ruleService={ruleService}
/>
)}
<EuiFlexGroup direction="column">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ export const DetectionRules: React.FC<DetectionRulesProps> = ({
hideFlyout={() => setFlyoutData(() => null)}
history={null as any}
ruleTableItem={flyoutData}
ruleService={null as any}
/>
) : null}
<EuiAccordion
Expand Down
11 changes: 4 additions & 7 deletions public/pages/CreateDetector/containers/CreateDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
getPlugins,
successNotificationToast,
} from '../../../utils/helpers';
import { RulesViewModelActor } from '../../Rules/models/RulesViewModelActor';
import { DataStore } from '../../../store/DataStore';

interface CreateDetectorProps extends RouteComponentProps {
isEdit: boolean;
Expand All @@ -58,11 +58,9 @@ interface CreateDetectorState {

export default class CreateDetector extends Component<CreateDetectorProps, CreateDetectorState> {
static contextType = CoreServicesContext;
private rulesViewModelActor: RulesViewModelActor;

constructor(props: CreateDetectorProps) {
super(props);
this.rulesViewModelActor = new RulesViewModelActor(props.services.ruleService);
this.state = {
currentStep: DetectorCreationStep.DEFINE_DETECTOR,
detector: EMPTY_DEFAULT_DETECTOR,
Expand Down Expand Up @@ -215,10 +213,9 @@ export default class CreateDetector extends Component<CreateDetectorProps, Creat
this.setState({
loadingRules: true,
});
const allRules = await this.rulesViewModelActor.fetchRules(undefined, {
bool: {
must: [{ match: { 'rule.category': `${detector_type}` } }],
},

const allRules = await DataStore.rules.getAllRules({
'rule.category': [detector_type],
});

const prePackagedRules = allRules.filter((rule) => rule.prePackaged);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { ContentPanel } from '../../../../components/ContentPanel';
import React, { useContext, useEffect, useState, useMemo } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import { EuiAccordion, EuiButton, EuiSpacer, EuiText } from '@elastic/eui';
import { RuleItem } from '../../../CreateDetector/components/DefineDetector/components/DetectionRules/types/interfaces';
import { ServicesContext } from '../../../../services';
Expand All @@ -15,7 +15,7 @@ import { NotificationsStart } from 'opensearch-dashboards/public';
import { RulesTable } from '../../../Rules/components/RulesTable/RulesTable';
import { RuleTableItem } from '../../../Rules/utils/helpers';
import { RuleViewerFlyout } from '../../../Rules/components/RuleViewerFlyout/RuleViewerFlyout';
import { RulesViewModelActor } from '../../../Rules/models/RulesViewModelActor';
import { DataStore } from '../../../../store/DataStore';

export interface DetectorRulesViewProps {
detector: Detector;
Expand Down Expand Up @@ -59,11 +59,6 @@ export const DetectorRulesView: React.FC<DetectorRulesViewProps> = (props) => {
];
const services = useContext(ServicesContext);

const rulesViewModelActor = useMemo(
() => (services ? new RulesViewModelActor(services.ruleService) : null),
[services]
);

useEffect(() => {
const updateRulesState = async () => {
setLoading(true);
Expand All @@ -74,10 +69,8 @@ export const DetectorRulesView: React.FC<DetectorRulesViewProps> = (props) => {
props.detector.inputs[0].detector_input.custom_rules.map((ruleInfo) => ruleInfo.id)
);

const allRules = await rulesViewModelActor?.fetchRules(undefined, {
bool: {
must: [{ match: { 'rule.category': `${props.detector.detector_type.toLowerCase()}` } }],
},
const allRules = await DataStore.rules.getAllRules({
'rule.category': [props.detector.detector_type.toLowerCase()],
});

const prePackagedRules = allRules?.filter((rule) => rule.prePackaged);
Expand Down Expand Up @@ -127,7 +120,6 @@ export const DetectorRulesView: React.FC<DetectorRulesViewProps> = (props) => {
hideFlyout={() => setFlyoutData(() => null)}
history={null as any}
ruleTableItem={flyoutData}
ruleService={null as any}
notifications={props.notifications}
/>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ exports[`<DetectorRulesView /> spec renders the component 1`] = `
},
"_version": 1,
"id": "rule_id_1",
"prePackaged": true,
},
],
"description": "detectorDescription",
Expand All @@ -49,6 +50,7 @@ exports[`<DetectorRulesView /> spec renders the component 1`] = `
},
"_version": 1,
"id": "rule_id_1",
"prePackaged": true,
},
],
},
Expand Down
Loading

0 comments on commit 7fcfb5a

Please sign in to comment.