diff --git a/x-pack/platform/plugins/private/telemetry_collection_xpack/schema/xpack_security.json b/x-pack/platform/plugins/private/telemetry_collection_xpack/schema/xpack_security.json index 1ff881bca3e20..fead301fbf74f 100644 --- a/x-pack/platform/plugins/private/telemetry_collection_xpack/schema/xpack_security.json +++ b/x-pack/platform/plugins/private/telemetry_collection_xpack/schema/xpack_security.json @@ -569,6 +569,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled query rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled query rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within query rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within query rules" + } + } + } + } + } } } }, @@ -689,6 +721,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled threshold rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled threshold rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within threshold rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within threshold rules" + } + } + } + } + } } } }, @@ -809,6 +873,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled eql rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled eql rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within eql rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within eql rules" + } + } + } + } + } } } }, @@ -929,6 +1025,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled machine_learning rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled machine_learning rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within machine_learning rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within machine_learning rules" + } + } + } + } + } } } }, @@ -1049,6 +1177,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled threat_match rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled threat_match rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within threat_match rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within threat_match rules" + } + } + } + } + } } } }, @@ -1169,6 +1329,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled new_term rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled new_term rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within new_term rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within new_term rules" + } + } + } + } + } } } }, @@ -1289,6 +1481,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled esql rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled esql rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within esql rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within esql rules" + } + } + } + } + } } } }, @@ -1409,6 +1633,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled elastic rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled elastic rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within elastic rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within elastic rules" + } + } + } + } + } } } }, @@ -1529,6 +1785,38 @@ } } } + }, + "response_actions": { + "properties": { + "enabled": { + "type": "long", + "_meta": { + "description": "Number of enabled custom rules configured with response actions" + } + }, + "disabled": { + "type": "long", + "_meta": { + "description": "Number of disabled custom rules configured with response actions" + } + }, + "response_actions": { + "properties": { + "endpoint": { + "type": "long", + "_meta": { + "description": "Number of endpoint response actions within custom rules" + } + }, + "osquery": { + "type": "long", + "_meta": { + "description": "Number of osquery response actions within custom rules" + } + } + } + } + } } } } diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/collector.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/collector.ts index 9e2ce4b4608dd..fad08ea435448 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/collector.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/collector.ts @@ -154,6 +154,32 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: 'Number of enabled query rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: 'Number of disabled query rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within query rules', + }, + }, + osquery: { + type: 'long', + _meta: { description: 'Number of osquery response actions within query rules' }, + }, + }, + }, }, threshold: { enabled: { @@ -262,6 +288,36 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: + 'Number of enabled threshold rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: + 'Number of disabled threshold rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within threshold rules', + }, + }, + osquery: { + type: 'long', + _meta: { + description: 'Number of osquery response actions within threshold rules', + }, + }, + }, + }, }, eql: { enabled: { type: 'long', _meta: { description: 'Number of eql rules enabled' } }, @@ -358,6 +414,32 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: 'Number of enabled eql rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: 'Number of disabled eql rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within eql rules', + }, + }, + osquery: { + type: 'long', + _meta: { description: 'Number of osquery response actions within eql rules' }, + }, + }, + }, }, machine_learning: { enabled: { @@ -468,6 +550,38 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: + 'Number of enabled machine_learning rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: + 'Number of disabled machine_learning rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: + 'Number of endpoint response actions within machine_learning rules', + }, + }, + osquery: { + type: 'long', + _meta: { + description: + 'Number of osquery response actions within machine_learning rules', + }, + }, + }, + }, }, threat_match: { enabled: { @@ -577,6 +691,36 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: + 'Number of enabled threat_match rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: + 'Number of disabled threat_match rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within threat_match rules', + }, + }, + osquery: { + type: 'long', + _meta: { + description: 'Number of osquery response actions within threat_match rules', + }, + }, + }, + }, }, new_terms: { enabled: { @@ -685,6 +829,36 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: + 'Number of enabled new_term rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: + 'Number of disabled new_term rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within new_term rules', + }, + }, + osquery: { + type: 'long', + _meta: { + description: 'Number of osquery response actions within new_term rules', + }, + }, + }, + }, }, esql: { enabled: { @@ -789,6 +963,32 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: 'Number of enabled esql rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: 'Number of disabled esql rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within esql rules', + }, + }, + osquery: { + type: 'long', + _meta: { description: 'Number of osquery response actions within esql rules' }, + }, + }, + }, }, elastic_total: { enabled: { type: 'long', _meta: { description: 'Number of elastic rules enabled' } }, @@ -890,6 +1090,35 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: 'Number of enabled elastic rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: + 'Number of disabled elastic rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within elastic rules', + }, + }, + osquery: { + type: 'long', + _meta: { + description: 'Number of osquery response actions within elastic rules', + }, + }, + }, + }, }, custom_total: { enabled: { type: 'long', _meta: { description: 'Number of custom rules enabled' } }, @@ -987,6 +1216,34 @@ export const registerCollector: RegisterCollector = ({ }, }, }, + response_actions: { + enabled: { + type: 'long', + _meta: { + description: 'Number of enabled custom rules configured with response actions', + }, + }, + disabled: { + type: 'long', + _meta: { + description: 'Number of disabled custom rules configured with response actions', + }, + }, + response_actions: { + endpoint: { + type: 'long', + _meta: { + description: 'Number of endpoint response actions within custom rules', + }, + }, + osquery: { + type: 'long', + _meta: { + description: 'Number of osquery response actions within custom rules', + }, + }, + }, + }, }, }, detection_rule_detail: { diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/get_metrics.test.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/get_metrics.test.ts index 7705d618bf78a..8db31c97707db 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/get_metrics.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/get_metrics.test.ts @@ -34,7 +34,11 @@ import { } from './rules/get_metrics.mocks'; import { getInitialDetectionMetrics } from './get_initial_usage'; import { getDetectionsMetrics } from './get_metrics'; -import { getInitialRulesUsage, initialAlertSuppression } from './rules/get_initial_usage'; +import { + getInitialRulesUsage, + initialAlertSuppression, + initialResponseActionsUsage, +} from './rules/get_initial_usage'; describe('Detections Usage and Metrics', () => { let esClient: ReturnType; @@ -110,6 +114,9 @@ describe('Detections Usage and Metrics', () => { has_alert_suppression_per_rule_execution: false, has_alert_suppression_per_time_period: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }, ], detection_rule_usage: { @@ -125,6 +132,7 @@ describe('Detections Usage and Metrics', () => { notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, elastic_total: { alerts: 3400, @@ -137,6 +145,7 @@ describe('Detections Usage and Metrics', () => { notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, }, }, @@ -185,6 +194,7 @@ describe('Detections Usage and Metrics', () => { notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, query: { alerts: 800, @@ -197,6 +207,7 @@ describe('Detections Usage and Metrics', () => { notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, }, }, @@ -251,6 +262,9 @@ describe('Detections Usage and Metrics', () => { has_alert_suppression_missing_fields_strategy_do_not_suppress: false, has_alert_suppression_per_rule_execution: false, has_alert_suppression_per_time_period: false, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }, ], detection_rule_usage: { @@ -266,6 +280,7 @@ describe('Detections Usage and Metrics', () => { notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, query: { alerts: 0, @@ -278,6 +293,7 @@ describe('Detections Usage and Metrics', () => { notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, }, }, diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/get_initial_usage.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/get_initial_usage.ts index fdc7bb7d43788..4cca150171f6b 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/get_initial_usage.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/get_initial_usage.ts @@ -13,6 +13,7 @@ import type { SingleEventMetric, AlertSuppressionUsage, SpacesUsage, + ResponseActionsUsage, } from './types'; export const initialAlertSuppression: AlertSuppressionUsage = { @@ -29,6 +30,15 @@ export const initialAlertSuppression: AlertSuppressionUsage = { does_not_suppress_missing_fields: 0, }; +export const initialResponseActionsUsage: ResponseActionsUsage = { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, +}; + export const getInitialSpacesUsage = (): SpacesUsage => ({ total: 0, rules_in_spaces: [], @@ -49,6 +59,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, threshold: { enabled: 0, @@ -61,6 +72,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, eql: { enabled: 0, @@ -73,6 +85,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, machine_learning: { enabled: 0, @@ -85,6 +98,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, threat_match: { enabled: 0, @@ -97,6 +111,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, new_terms: { enabled: 0, @@ -109,6 +124,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, esql: { enabled: 0, @@ -121,6 +137,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, elastic_total: { enabled: 0, @@ -133,6 +150,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, custom_total: { enabled: 0, @@ -145,6 +163,7 @@ export const getInitialRulesUsage = (): RulesTypeUsage => ({ notifications_disabled: 0, legacy_investigation_fields: 0, alert_suppression: initialAlertSuppression, + response_actions: initialResponseActionsUsage, }, }); diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_object_correlations.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_object_correlations.ts index 7e3dc6ee18169..530bf2fd1f160 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_object_correlations.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/transform_utils/get_rule_object_correlations.ts @@ -9,6 +9,7 @@ import type { SavedObjectsFindResult } from '@kbn/core/server'; import type { RuleMetric } from '../types'; import type { RuleSearchResult } from '../../../types'; import { getAlertSuppressionUsage } from '../usage_utils/get_alert_suppression_usage'; +import { getResponseActionsUsage } from '../usage_utils/get_response_actions_usage'; export interface RuleObjectCorrelationsOptions { ruleResults: Array>; @@ -49,6 +50,9 @@ export const getRuleObjectCorrelations = ({ alertSuppressionFieldsCount, } = getAlertSuppressionUsage(attributes); + const { hasResponseActions, hasResponseActionsEndpoint, hasResponseActionsOsquery } = + getResponseActionsUsage(attributes); + return { rule_name: attributes.name, rule_id: attributes.params.ruleId, @@ -69,6 +73,9 @@ export const getRuleObjectCorrelations = ({ has_alert_suppression_missing_fields_strategy_do_not_suppress: hasAlertSuppressionMissingFieldsStrategyDoNotSuppress, alert_suppression_fields_count: alertSuppressionFieldsCount, + has_response_actions: hasResponseActions, + has_response_actions_endpoint: hasResponseActionsEndpoint, + has_response_actions_osquery: hasResponseActionsOsquery, }; }); }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/types.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/types.ts index b5d7c133d5940..f944b5b9df64f 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/types.ts @@ -19,6 +19,15 @@ export interface AlertSuppressionUsage { does_not_suppress_missing_fields: number; } +export interface ResponseActionsUsage { + enabled: number; + disabled: number; + response_actions: { + endpoint: number; + osquery: number; + }; +} + export interface FeatureTypeUsage { enabled: number; disabled: number; @@ -30,6 +39,7 @@ export interface FeatureTypeUsage { notifications_disabled: number; legacy_investigation_fields: number; alert_suppression: AlertSuppressionUsage; + response_actions: ResponseActionsUsage; } export interface RulesTypeUsage { @@ -74,6 +84,9 @@ export interface RuleMetric { has_alert_suppression_per_time_period: boolean; has_alert_suppression_missing_fields_strategy_do_not_suppress: boolean; alert_suppression_fields_count: number; + has_response_actions: boolean; + has_response_actions_endpoint: boolean; + has_response_actions_osquery: boolean; } /** diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/update_usage.test.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/update_usage.test.ts index b6884222ff2c7..f2e075d0150f8 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/update_usage.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/update_usage.test.ts @@ -22,6 +22,9 @@ interface StubRuleOptions { hasAlertSuppressionPerRuleExecution: boolean; hasAlertSuppressionPerTimePeriod: boolean; alertSuppressionFieldsCount: number; + hasResponseActions: boolean; + hasResponseActionsEndpoint: boolean; + hasResponseActionsOsquery: boolean; } const createStubRule = ({ @@ -37,6 +40,9 @@ const createStubRule = ({ hasAlertSuppressionPerRuleExecution, hasAlertSuppressionPerTimePeriod, alertSuppressionFieldsCount, + hasResponseActions, + hasResponseActionsEndpoint, + hasResponseActionsOsquery, }: StubRuleOptions): RuleMetric => ({ rule_name: 'rule-name', rule_id: 'id-123', @@ -56,6 +62,9 @@ const createStubRule = ({ has_alert_suppression_per_rule_execution: hasAlertSuppressionPerRuleExecution, has_alert_suppression_per_time_period: hasAlertSuppressionPerTimePeriod, alert_suppression_fields_count: alertSuppressionFieldsCount, + has_response_actions: hasResponseActions, + has_response_actions_endpoint: hasResponseActionsEndpoint, + has_response_actions_osquery: hasResponseActionsOsquery, }); describe('Detections Usage and Metrics', () => { @@ -74,6 +83,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: true, hasAlertSuppressionPerTimePeriod: false, alertSuppressionFieldsCount: 3, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const usage = updateRuleUsage(stubRule, getInitialRulesUsage()); @@ -102,6 +114,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 0, suppresses_missing_fields: 1, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, eql: { alerts: 1, @@ -126,6 +146,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 0, suppresses_missing_fields: 1, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, }); }); @@ -144,6 +172,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: false, hasAlertSuppressionPerTimePeriod: false, alertSuppressionFieldsCount: 0, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const stubQueryRuleOne = createStubRule({ ruleType: 'query', @@ -158,6 +189,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: false, hasAlertSuppressionPerTimePeriod: false, alertSuppressionFieldsCount: 0, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const stubQueryRuleTwo = createStubRule({ ruleType: 'query', @@ -172,6 +206,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: false, hasAlertSuppressionPerTimePeriod: true, alertSuppressionFieldsCount: 2, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const stubMachineLearningOne = createStubRule({ ruleType: 'machine_learning', @@ -186,6 +223,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: false, hasAlertSuppressionPerTimePeriod: true, alertSuppressionFieldsCount: 2, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const stubMachineLearningTwo = createStubRule({ ruleType: 'machine_learning', @@ -200,6 +240,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: false, hasAlertSuppressionPerTimePeriod: false, alertSuppressionFieldsCount: 0, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); let usage = updateRuleUsage(stubEqlRule, getInitialRulesUsage()); @@ -233,6 +276,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 2, suppresses_missing_fields: 0, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, elastic_total: { alerts: 28, @@ -257,6 +308,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 0, suppresses_missing_fields: 0, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, eql: { alerts: 1, @@ -281,6 +340,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 0, suppresses_missing_fields: 0, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, machine_learning: { alerts: 22, @@ -305,6 +372,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 1, suppresses_missing_fields: 0, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, query: { alerts: 10, @@ -329,6 +404,14 @@ describe('Detections Usage and Metrics', () => { suppressed_per_time_period: 1, suppresses_missing_fields: 0, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }, }); }); @@ -411,6 +494,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: true, hasAlertSuppressionPerTimePeriod: false, alertSuppressionFieldsCount: 3, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const usage = updateRuleUsage(rule1, getInitialRulesUsage()) as ReturnType< typeof updateRuleUsage @@ -439,6 +525,9 @@ describe('Detections Usage and Metrics', () => { hasAlertSuppressionPerRuleExecution: true, hasAlertSuppressionPerTimePeriod: false, alertSuppressionFieldsCount: 3, + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, }); const usageAddedByOne = updateRuleUsage(rule2, usage) as ReturnType< typeof updateRuleUsage diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/get_response_actions_usage.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/get_response_actions_usage.ts new file mode 100644 index 0000000000000..93f349b236979 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/get_response_actions_usage.ts @@ -0,0 +1,53 @@ +/* + * 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 { RuleSearchResult } from '../../../types'; + +export const getResponseActionsUsage = ( + ruleAttributes: RuleSearchResult +): { + hasResponseActions: boolean; + hasResponseActionsEndpoint: boolean; + hasResponseActionsOsquery: boolean; +} => { + if ( + ruleAttributes.params.responseActions == null || + ruleAttributes.params.responseActions.length === 0 + ) { + return { + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, + }; + } + + switch (ruleAttributes.params.type) { + case 'threshold': + case 'query': + case 'saved_query': + case 'new_terms': + case 'threat_match': + case 'machine_learning': + case 'esql': + case 'eql': + return { + hasResponseActions: !!ruleAttributes.params.responseActions, + hasResponseActionsEndpoint: !!ruleAttributes.params.responseActions?.some( + (action) => action.actionTypeId === '.endpoint' + ), + hasResponseActionsOsquery: !!ruleAttributes.params.responseActions?.some( + (action) => action.actionTypeId === '.osquery' + ), + }; + default: + return { + hasResponseActions: false, + hasResponseActionsEndpoint: false, + hasResponseActionsOsquery: false, + }; + } +}; diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_query_usage.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_query_usage.ts index 5245d2c9abeeb..e88823bce8bba 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_query_usage.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_query_usage.ts @@ -8,6 +8,7 @@ import type { RulesTypeUsage, RuleMetric, FeatureTypeUsage } from '../types'; import { getNotificationsEnabledDisabled } from './get_notifications_enabled_disabled'; import { updateAlertSuppressionUsage } from './update_alert_suppression_usage'; +import { updateResponseActionsUsage } from './update_response_actions_usage'; export interface UpdateQueryUsageOptions { ruleType: keyof RulesTypeUsage; @@ -49,5 +50,9 @@ export const updateQueryUsage = ({ ? usage[ruleType].legacy_investigation_fields + 1 : usage[ruleType].legacy_investigation_fields, alert_suppression: updateAlertSuppressionUsage({ usage: usage[ruleType], detectionRuleMetric }), + response_actions: updateResponseActionsUsage({ + usage: usage[ruleType], + detectionRuleMetric, + }), }; }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_response_actions_usage.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_response_actions_usage.ts new file mode 100644 index 0000000000000..6c78456879c2c --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_response_actions_usage.ts @@ -0,0 +1,43 @@ +/* + * 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 { ResponseActionsUsage, RuleMetric, FeatureTypeUsage } from '../types'; + +export interface UpdateResponseActionsUsage { + detectionRuleMetric: RuleMetric; + usage: FeatureTypeUsage; +} + +export const updateResponseActionsUsage = ({ + detectionRuleMetric, + usage, +}: UpdateResponseActionsUsage): ResponseActionsUsage => { + const areResponseActionsConfigured = detectionRuleMetric.has_response_actions; + + // if rule does not have response actions configured + // returned unchanged + if (!areResponseActionsConfigured) { + return usage.response_actions; + } + + return { + enabled: detectionRuleMetric.enabled + ? usage.response_actions.enabled + 1 + : usage.response_actions.enabled, + disabled: !detectionRuleMetric.enabled + ? usage.response_actions.disabled + 1 + : usage.response_actions.disabled, + response_actions: { + endpoint: detectionRuleMetric.has_response_actions_endpoint + ? usage.response_actions.response_actions.endpoint + 1 + : usage.response_actions.response_actions.endpoint, + osquery: detectionRuleMetric.has_response_actions_osquery + ? usage.response_actions.response_actions.osquery + 1 + : usage.response_actions.response_actions.osquery, + }, + }; +}; diff --git a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_total_usage.ts b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_total_usage.ts index c7ce17f8ab0e3..2e5a8203e3364 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_total_usage.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/usage/detections/rules/usage_utils/update_total_usage.ts @@ -8,6 +8,7 @@ import type { RulesTypeUsage, RuleMetric, FeatureTypeUsage } from '../types'; import { getNotificationsEnabledDisabled } from './get_notifications_enabled_disabled'; import { updateAlertSuppressionUsage } from './update_alert_suppression_usage'; +import { updateResponseActionsUsage } from './update_response_actions_usage'; export interface UpdateTotalUsageOptions { detectionRuleMetric: RuleMetric; @@ -55,5 +56,9 @@ export const updateTotalUsage = ({ usage: updatedUsage[totalType], detectionRuleMetric, }), + response_actions: updateResponseActionsUsage({ + usage: updatedUsage[totalType], + detectionRuleMetric, + }), }; }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules.ts index c43d08a805ca8..44952256dd286 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules.ts @@ -1098,6 +1098,14 @@ export default ({ getService }: FtrProviderContext) => { suppresses_missing_fields: 0, does_not_suppress_missing_fields: 0, }, + response_actions: { + enabled: 0, + disabled: 0, + response_actions: { + endpoint: 0, + osquery: 0, + }, + }, }); }); }); @@ -1133,6 +1141,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); }); }); @@ -1175,6 +1186,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); expect( stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled @@ -1232,6 +1246,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); expect( stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled @@ -1289,6 +1306,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); expect( stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled @@ -1349,6 +1369,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); expect( stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules_legacy_action.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules_legacy_action.ts index f85f317e2da07..b54847d0c4b47 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules_legacy_action.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/telemetry/trial_license_complete_tier/usage_collector/detection_rules_legacy_action.ts @@ -442,6 +442,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); expect( stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled @@ -502,6 +505,9 @@ export default ({ getService }: FtrProviderContext) => { has_alert_suppression_per_time_period: false, has_alert_suppression_missing_fields_strategy_do_not_suppress: false, alert_suppression_fields_count: 0, + has_response_actions: false, + has_response_actions_endpoint: false, + has_response_actions_osquery: false, }); expect( stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled