mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[9.0] [Security Solution][Detection Engine] adds spaces telemetry for detection rules (#215393) (#216586)
# Backport This will backport the following commits from `main` to `9.0`: - [[Security Solution][Detection Engine] adds spaces telemetry for detection rules (#215393)](https://github.com/elastic/kibana/pull/215393) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Vitalii Dmyterko","email":"92328789+vitaliidm@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-04-01T08:07:08Z","message":"[Security Solution][Detection Engine] adds spaces telemetry for detection rules (#215393)\n\n## Summary\n\n - addresses https://github.com/elastic/security-team/issues/12000\n - adds telemetry for rules in spaces: \n - number of spaces, detection rules added\n - number of rules in each space\n\n---------\n\nCo-authored-by: Dan Dillinger <ddillinger@users.noreply.github.com>\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b3d750bc49816de62de75bd550e7aab0066c7b7f","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Detections and Resp","Team: SecuritySolution","Team:Detection Engine","backport:version","v9.1.0","v8.19.0"],"title":"[Security Solution][Detection Engine] adds spaces telemetry for detection rules","number":215393,"url":"https://github.com/elastic/kibana/pull/215393","mergeCommit":{"message":"[Security Solution][Detection Engine] adds spaces telemetry for detection rules (#215393)\n\n## Summary\n\n - addresses https://github.com/elastic/security-team/issues/12000\n - adds telemetry for rules in spaces: \n - number of spaces, detection rules added\n - number of rules in each space\n\n---------\n\nCo-authored-by: Dan Dillinger <ddillinger@users.noreply.github.com>\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b3d750bc49816de62de75bd550e7aab0066c7b7f"}},"sourceBranch":"main","suggestedTargetBranches":["9.0","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/215393","number":215393,"mergeCommit":{"message":"[Security Solution][Detection Engine] adds spaces telemetry for detection rules (#215393)\n\n## Summary\n\n - addresses https://github.com/elastic/security-team/issues/12000\n - adds telemetry for rules in spaces: \n - number of spaces, detection rules added\n - number of rules in each space\n\n---------\n\nCo-authored-by: Dan Dillinger <ddillinger@users.noreply.github.com>\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b3d750bc49816de62de75bd550e7aab0066c7b7f"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com>
This commit is contained in:
parent
471ef15a70
commit
3c0fe5e9d3
9 changed files with 118 additions and 3 deletions
|
@ -431,6 +431,25 @@
|
|||
"properties": {
|
||||
"detection_rules": {
|
||||
"properties": {
|
||||
"spaces_usage": {
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Total number of spaces where detection rules added"
|
||||
}
|
||||
},
|
||||
"rules_in_spaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Number of rules is each space"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"detection_rule_usage": {
|
||||
"properties": {
|
||||
"query": {
|
||||
|
|
|
@ -44,6 +44,19 @@ export const registerCollector: RegisterCollector = ({
|
|||
schema: {
|
||||
detectionMetrics: {
|
||||
detection_rules: {
|
||||
spaces_usage: {
|
||||
total: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Total number of spaces where detection rules added' },
|
||||
},
|
||||
rules_in_spaces: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'long',
|
||||
_meta: { description: 'Number of rules is each space' },
|
||||
},
|
||||
},
|
||||
},
|
||||
detection_rule_usage: {
|
||||
query: {
|
||||
enabled: { type: 'long', _meta: { description: 'Number of query rules enabled' } },
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
import type { DetectionMetrics } from './types';
|
||||
|
||||
import { getInitialMlJobUsage } from './ml_jobs/get_initial_usage';
|
||||
import { getInitialEventLogUsage, getInitialRulesUsage } from './rules/get_initial_usage';
|
||||
import {
|
||||
getInitialEventLogUsage,
|
||||
getInitialRulesUsage,
|
||||
getInitialSpacesUsage,
|
||||
} from './rules/get_initial_usage';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { getInitialLegacySiemSignalsUsage } from './legacy_siem_signals/get_initial_usage';
|
||||
|
||||
|
@ -24,6 +28,7 @@ export const getInitialDetectionMetrics = (): DetectionMetrics => ({
|
|||
detection_rule_detail: [],
|
||||
detection_rule_usage: getInitialRulesUsage(),
|
||||
detection_rule_status: getInitialEventLogUsage(),
|
||||
spaces_usage: getInitialSpacesUsage(),
|
||||
},
|
||||
legacy_siem_signals: getInitialLegacySiemSignalsUsage(),
|
||||
});
|
||||
|
|
|
@ -86,6 +86,10 @@ describe('Detections Usage and Metrics', () => {
|
|||
expect(result).toEqual<DetectionMetrics>({
|
||||
...getInitialDetectionMetrics(),
|
||||
detection_rules: {
|
||||
spaces_usage: {
|
||||
rules_in_spaces: [1],
|
||||
total: 1,
|
||||
},
|
||||
detection_rule_status: getAllEventLogTransform(),
|
||||
detection_rule_detail: [
|
||||
{
|
||||
|
@ -162,6 +166,10 @@ describe('Detections Usage and Metrics', () => {
|
|||
expect(result).toEqual<DetectionMetrics>({
|
||||
...getInitialDetectionMetrics(),
|
||||
detection_rules: {
|
||||
spaces_usage: {
|
||||
rules_in_spaces: [1],
|
||||
total: 1,
|
||||
},
|
||||
detection_rule_status: getAllEventLogTransform(),
|
||||
detection_rule_detail: [], // *should not* contain custom detection rule details
|
||||
detection_rule_usage: {
|
||||
|
@ -219,6 +227,10 @@ describe('Detections Usage and Metrics', () => {
|
|||
expect(result).toEqual<DetectionMetrics>({
|
||||
...getInitialDetectionMetrics(),
|
||||
detection_rules: {
|
||||
spaces_usage: {
|
||||
rules_in_spaces: [1],
|
||||
total: 1,
|
||||
},
|
||||
detection_rule_status: getAllEventLogTransform(),
|
||||
detection_rule_detail: [
|
||||
{
|
||||
|
|
|
@ -11,7 +11,11 @@ import type { DetectionMetrics } from './types';
|
|||
|
||||
import { getMlJobMetrics } from './ml_jobs/get_metrics';
|
||||
import { getRuleMetrics } from './rules/get_metrics';
|
||||
import { getInitialEventLogUsage, getInitialRulesUsage } from './rules/get_initial_usage';
|
||||
import {
|
||||
getInitialEventLogUsage,
|
||||
getInitialRulesUsage,
|
||||
getInitialSpacesUsage,
|
||||
} from './rules/get_initial_usage';
|
||||
import { getInitialMlJobUsage } from './ml_jobs/get_initial_usage';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { getInitialLegacySiemSignalsUsage } from './legacy_siem_signals/get_initial_usage';
|
||||
|
@ -55,6 +59,7 @@ export const getDetectionsMetrics = async ({
|
|||
detection_rule_detail: [],
|
||||
detection_rule_usage: getInitialRulesUsage(),
|
||||
detection_rule_status: getInitialEventLogUsage(),
|
||||
spaces_usage: getInitialSpacesUsage(),
|
||||
},
|
||||
legacy_siem_signals:
|
||||
legacySiemSignalsUsage.status === 'fulfilled'
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
SingleEventLogStatusMetric,
|
||||
SingleEventMetric,
|
||||
AlertSuppressionUsage,
|
||||
SpacesUsage,
|
||||
} from './types';
|
||||
|
||||
export const initialAlertSuppression: AlertSuppressionUsage = {
|
||||
|
@ -28,6 +29,11 @@ export const initialAlertSuppression: AlertSuppressionUsage = {
|
|||
does_not_suppress_missing_fields: 0,
|
||||
};
|
||||
|
||||
export const getInitialSpacesUsage = (): SpacesUsage => ({
|
||||
total: 0,
|
||||
rules_in_spaces: [],
|
||||
});
|
||||
|
||||
/**
|
||||
* Default detection rule usage count, split by type + elastic/custom
|
||||
*/
|
||||
|
|
|
@ -12,11 +12,16 @@ import { updateRuleUsage } from './update_usage';
|
|||
import { getDetectionRules } from '../../queries/get_detection_rules';
|
||||
import { getAlerts } from '../../queries/get_alerts';
|
||||
import { MAX_PER_PAGE, MAX_RESULTS_WINDOW } from '../../constants';
|
||||
import { getInitialEventLogUsage, getInitialRulesUsage } from './get_initial_usage';
|
||||
import {
|
||||
getInitialEventLogUsage,
|
||||
getInitialRulesUsage,
|
||||
getInitialSpacesUsage,
|
||||
} from './get_initial_usage';
|
||||
import { getCaseComments } from '../../queries/get_case_comments';
|
||||
import { getRuleIdToCasesMap } from './transform_utils/get_rule_id_to_cases_map';
|
||||
import { getAlertIdToCountMap } from './transform_utils/get_alert_id_to_count_map';
|
||||
import { getRuleIdToEnabledMap } from './transform_utils/get_rule_id_to_enabled_map';
|
||||
import { getSpacesUsage } from './transform_utils/get_spaces_usage';
|
||||
import { getRuleObjectCorrelations } from './transform_utils/get_rule_object_correlations';
|
||||
import { getEventLogByTypeAndStatus } from '../../queries/get_event_log_by_type_and_status';
|
||||
|
||||
|
@ -53,6 +58,7 @@ export const getRuleMetrics = async ({
|
|||
detection_rule_detail: [],
|
||||
detection_rule_usage: getInitialRulesUsage(),
|
||||
detection_rule_status: getInitialEventLogUsage(),
|
||||
spaces_usage: getInitialSpacesUsage(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -123,6 +129,7 @@ export const getRuleMetrics = async ({
|
|||
detection_rule_detail: elasticRuleObjects,
|
||||
detection_rule_usage: rulesUsage,
|
||||
detection_rule_status: eventLogMetricsTypeStatus,
|
||||
spaces_usage: getSpacesUsage(ruleResults),
|
||||
};
|
||||
} catch (e) {
|
||||
// ignore failure, usage will be zeroed. We use debug mode to not unnecessarily worry users as this will not effect them.
|
||||
|
@ -133,6 +140,7 @@ export const getRuleMetrics = async ({
|
|||
detection_rule_detail: [],
|
||||
detection_rule_usage: getInitialRulesUsage(),
|
||||
detection_rule_status: getInitialEventLogUsage(),
|
||||
spaces_usage: getInitialSpacesUsage(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 type { SavedObjectsFindResult } from '@kbn/core/server';
|
||||
import type { RuleSearchResult } from '../../../types';
|
||||
import type { SpacesUsage } from '../types';
|
||||
|
||||
/**
|
||||
* Calculates the usage of spaces based on the provided rule results.
|
||||
*
|
||||
* @param {Array<SavedObjectsFindResult<RuleSearchResult>>} ruleResults - An array of saved object results containing rule search results.
|
||||
*
|
||||
* @returns {SpacesUsage}
|
||||
* - `total`: The total number spaces rules belong to.
|
||||
* - `rules_in_spaces`: An array where each value represents the number of rules in a specific space.
|
||||
*/
|
||||
export const getSpacesUsage = (
|
||||
ruleResults: Array<SavedObjectsFindResult<RuleSearchResult>>
|
||||
): SpacesUsage => {
|
||||
const spacesUsageMap = new Map<string, number>();
|
||||
|
||||
// for loop is faster
|
||||
for (let i = 0; i < ruleResults.length; i++) {
|
||||
const rule = ruleResults[i];
|
||||
|
||||
const space = rule.namespaces?.[0];
|
||||
|
||||
if (space) {
|
||||
spacesUsageMap.set(space, (spacesUsageMap.get(space) ?? 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
total: spacesUsageMap.size,
|
||||
rules_in_spaces: Array.from(spacesUsageMap.values()),
|
||||
};
|
||||
};
|
|
@ -44,10 +44,16 @@ export interface RulesTypeUsage {
|
|||
esql: FeatureTypeUsage;
|
||||
}
|
||||
|
||||
export interface SpacesUsage {
|
||||
total: number;
|
||||
rules_in_spaces: number[];
|
||||
}
|
||||
|
||||
export interface RuleAdoption {
|
||||
detection_rule_detail: RuleMetric[];
|
||||
detection_rule_usage: RulesTypeUsage;
|
||||
detection_rule_status: EventLogStatusMetric;
|
||||
spaces_usage: SpacesUsage;
|
||||
}
|
||||
|
||||
export interface RuleMetric {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue