Skip to content

Commit

Permalink
[8.x] [Cloud Security] Fix vulnerability detection rule creation logic (
Browse files Browse the repository at this point in the history
#195291) (#195596)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Cloud Security] Fix vulnerability detection rule creation logic
(#195291)](#195291)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT
[{"author":{"name":"Jordan","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-09T13:18:33Z","message":"[Cloud
Security] Fix vulnerability detection rule creation logic
(#195291)","sha":"fbf3f8b8b24575bd9fdc10e05ed0e5032a1a4340","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Cloud
Security","backport:prev-minor"],"title":"[Cloud Security] Fix
vulnerability detection rule creation
logic","number":195291,"url":"https://github.com/elastic/kibana/pull/195291","mergeCommit":{"message":"[Cloud
Security] Fix vulnerability detection rule creation logic
(#195291)","sha":"fbf3f8b8b24575bd9fdc10e05ed0e5032a1a4340"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/195291","number":195291,"mergeCommit":{"message":"[Cloud
Security] Fix vulnerability detection rule creation logic
(#195291)","sha":"fbf3f8b8b24575bd9fdc10e05ed0e5032a1a4340"}}]}]
BACKPORT-->

Co-authored-by: Jordan <[email protected]>
  • Loading branch information
kibanamachine and JordanSh authored Oct 9, 2024
1 parent 4de542f commit 0556cfc
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 44 deletions.
5 changes: 4 additions & 1 deletion x-pack/packages/kbn-cloud-security-posture-common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export type {
CspSetupStatus,
} from './types/status';
export type { CspFinding, CspFindingResult } from './types/findings';
export type { CspVulnerabilityFinding } from './schema/vulnerabilities/csp_vulnerability_finding';
export type {
CspVulnerabilityFinding,
Vulnerability,
} from './schema/vulnerabilities/csp_vulnerability_finding';
export type { BenchmarksCisId } from './types/benchmark';
export type { VulnSeverity } from './types/vulnerabilities';
export * from './constants';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ export const LatestVulnerabilitiesTable = ({
});

const createVulnerabilityRuleFn = (rowIndex: number) => {
const finding = getCspVulnerabilityFinding(rows[rowIndex].raw._source);
if (!finding) return;
const vulnerabilityFinding = getCspVulnerabilityFinding(rows[rowIndex].raw._source);
if (!vulnerabilityFinding) return;

return async (http: HttpSetup) =>
createDetectionRuleFromVulnerabilityFinding(http, finding.vulnerability);
createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityFinding);
};

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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 {
getVulnerabilityTags,
getVulnerabilityRuleName,
generateVulnerabilitiesRuleQuery,
} from './create_detection_rule_from_vulnerability';
import { CspVulnerabilityFinding, Vulnerability } from '@kbn/cloud-security-posture-common';
import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding';

// Mocking the isNativeCspFinding function
jest.mock('../../../common/utils/is_native_csp_finding', () => ({
isNativeCspFinding: jest.fn(),
}));

describe('CreateDetectionRuleFromVulnerability', () => {
describe('getVulnerabilityTags', () => {
it('should return tags with CSP_RULE_TAG and vulnerability id', () => {
const mockVulnerability = {
vulnerability: { id: 'CVE-2024-00001' },
observer: undefined,
data_stream: undefined,
} as unknown as CspVulnerabilityFinding;

(isNativeCspFinding as jest.Mock).mockReturnValue(false);

const tags = getVulnerabilityTags(mockVulnerability);
expect(tags).toEqual(['Cloud Security', 'CVE-2024-00001']);
});

it('should include vendor tag if available', () => {
const mockVulnerability = {
vulnerability: { id: 'CVE-2024-00002' },
observer: { vendor: 'Wiz' },
data_stream: undefined,
} as unknown as CspVulnerabilityFinding;

(isNativeCspFinding as jest.Mock).mockReturnValue(false);

const tags = getVulnerabilityTags(mockVulnerability);
expect(tags).toEqual(['Cloud Security', 'CVE-2024-00002', 'Wiz']);
});

it('should include CNVM tags for native findings', () => {
const mockVulnerability = {
vulnerability: { id: 'CVE-2024-00003' },
observer: undefined,
data_stream: undefined,
} as unknown as CspVulnerabilityFinding;

(isNativeCspFinding as jest.Mock).mockReturnValue(true);

const tags = getVulnerabilityTags(mockVulnerability);
expect(tags).toEqual([
'Cloud Security',
'CNVM',
'Data Source: Cloud Native Vulnerability Management',
'Use Case: Vulnerability',
'OS: Linux',
'CVE-2024-00003',
]);
});
});

describe('getVulnerabilityRuleName', () => {
it('should return correct rule name for a vulnerability', () => {
const mockVulnerability = {
id: 'CVE-2024-00004',
description: '',
reference: '',
} as Vulnerability;

const ruleName = getVulnerabilityRuleName(mockVulnerability);
expect(ruleName).toEqual('Vulnerability: CVE-2024-00004');
});
});

describe('generateVulnerabilitiesRuleQuery', () => {
it('should generate correct query for a vulnerability', () => {
const mockVulnerability = {
id: 'CVE-2024-00005',
description: '',
reference: '',
} as Vulnerability;
const currentTimestamp = new Date().toISOString();

const query = generateVulnerabilitiesRuleQuery(mockVulnerability);
expect(query).toEqual(
`vulnerability.id: "CVE-2024-00005" AND event.ingested >= "${currentTimestamp}"`
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import { HttpSetup } from '@kbn/core/public';
import { i18n } from '@kbn/i18n';
import {
CspVulnerabilityFinding,
LATEST_VULNERABILITIES_RETENTION_POLICY,
VULNERABILITIES_SEVERITY,
} from '@kbn/cloud-security-posture-common';
import type { Vulnerability } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding';
import { VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants';
import { createDetectionRule } from '../../../common/api/create_detection_rule';

Expand Down Expand Up @@ -42,15 +44,7 @@ enum AlertSuppressionMissingFieldsStrategy {
Suppress = 'suppress',
}

const CSP_RULE_TAG = 'Cloud Security';

const STATIC_RULE_TAGS = [CSP_RULE_TAG];

const generateVulnerabilitiesTags = (tags?: string[]) => {
return [...STATIC_RULE_TAGS, ...(!!tags?.length ? tags : [])];
};

const getVulnerabilityRuleName = (vulnerability: Vulnerability) => {
export const getVulnerabilityRuleName = (vulnerability: Vulnerability) => {
return i18n.translate('xpack.csp.vulnerabilities.detectionRuleNamePrefix', {
defaultMessage: 'Vulnerability: {vulnerabilityId}',
values: {
Expand All @@ -59,20 +53,42 @@ const getVulnerabilityRuleName = (vulnerability: Vulnerability) => {
});
};

const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => {
export const generateVulnerabilitiesRuleQuery = (vulnerability: Vulnerability) => {
const currentTimestamp = new Date().toISOString();

return `vulnerability.id: "${vulnerability.id}" AND event.ingested >= "${currentTimestamp}"`;
};

const CSP_RULE_TAG = 'Cloud Security';
const CNVM_TAG = 'CNVM';
const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management';
const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability';
const CNVM_RULE_TAG_OS = 'OS: Linux';

export const getVulnerabilityTags = (vulnerabilityFinding: CspVulnerabilityFinding) => {
let tags = [vulnerabilityFinding.vulnerability.id];
const vendor =
vulnerabilityFinding.observer?.vendor || vulnerabilityFinding?.data_stream?.dataset;

if (isNativeCspFinding(vulnerabilityFinding)) {
tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags];
} else if (!!vendor) {
tags.push(vendor);
}

return [CSP_RULE_TAG, ...tags];
};

/*
* Creates a detection rule from a Vulnerability
*/
export const createDetectionRuleFromVulnerabilityFinding = async (
http: HttpSetup,
vulnerability: Vulnerability,
tags?: string[]
vulnerabilityFinding: CspVulnerabilityFinding
) => {
const tags = getVulnerabilityTags(vulnerabilityFinding);
const vulnerability = vulnerabilityFinding.vulnerability;

return await createDetectionRule({
http,
rule: {
Expand Down Expand Up @@ -135,7 +151,7 @@ export const createDetectionRuleFromVulnerabilityFinding = async (
references: vulnerability.reference ? [vulnerability.reference] : [],
name: getVulnerabilityRuleName(vulnerability),
description: vulnerability.description,
tags: generateVulnerabilitiesTags(tags),
tags,
investigation_fields: DEFAULT_INVESTIGATION_FIELDS,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,21 @@
import React from 'react';
import type { HttpSetup } from '@kbn/core/public';
import type { CspVulnerabilityFinding } from '@kbn/cloud-security-posture-common/schema/vulnerabilities/latest';
import { isNativeCspFinding } from '../../../common/utils/is_native_csp_finding';
import { DetectionRuleCounter } from '../../../components/detection_rule_counter';
import { createDetectionRuleFromVulnerabilityFinding } from '../utils/create_detection_rule_from_vulnerability';

const CNVM_TAG = 'CNVM';
const CNVM_RULE_TAG_DATA_SOURCE = 'Data Source: Cloud Native Vulnerability Management';
const CNVM_RULE_TAG_USE_CASE = 'Use Case: Vulnerability';
const CNVM_RULE_TAG_OS = 'OS: Linux';

const getTags = (vulnerabilityRecord: CspVulnerabilityFinding) => {
let tags = [vulnerabilityRecord.vulnerability.id];
const vendor = vulnerabilityRecord.observer?.vendor || vulnerabilityRecord?.data_stream?.dataset;

if (isNativeCspFinding(vulnerabilityRecord)) {
tags = [CNVM_TAG, CNVM_RULE_TAG_DATA_SOURCE, CNVM_RULE_TAG_USE_CASE, CNVM_RULE_TAG_OS, ...tags];
} else if (!!vendor) {
tags.push(vendor);
}

return tags;
};
import {
createDetectionRuleFromVulnerabilityFinding,
getVulnerabilityTags,
} from '../utils/create_detection_rule_from_vulnerability';

export const VulnerabilityDetectionRuleCounter = ({
vulnerabilityRecord,
}: {
vulnerabilityRecord: CspVulnerabilityFinding;
}) => {
const tags = getTags(vulnerabilityRecord);
const tags = getVulnerabilityTags(vulnerabilityRecord);

const createVulnerabilityRuleFn = async (http: HttpSetup) =>
await createDetectionRuleFromVulnerabilityFinding(
http,
vulnerabilityRecord.vulnerability,
tags
);
await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord);

return <DetectionRuleCounter tags={tags} createRuleFn={createVulnerabilityRuleFn} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const VulnerabilityFindingFlyout = ({
const vulnerabilityReference = vulnerability?.reference;

const createVulnerabilityRuleFn = async (http: HttpSetup) =>
await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord.vulnerability);
await createDetectionRuleFromVulnerabilityFinding(http, vulnerabilityRecord);

return (
<EuiFlyout onClose={closeFlyout}>
Expand Down

0 comments on commit 0556cfc

Please sign in to comment.