[Cloud Security] [Telemetry] Add Alerts Telemetry (#163907)

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Paulo Henrique 2023-08-16 03:17:36 -07:00 committed by GitHub
parent cfe7cabf86
commit ff2e7a8c8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 285 additions and 18 deletions

View file

@ -136,3 +136,5 @@ export const AWS_CREDENTIALS_TYPE_TO_FIELDS_MAP: AwsCredentialsTypeFieldMap = {
export const SETUP_ACCESS_CLOUD_SHELL = 'google_cloud_shell';
export const SETUP_ACCESS_MANUAL = 'manual';
export const DETECTION_ENGINE_ALERTS_INDEX_DEFAULT = '.alerts-security.alerts-default';

View file

@ -0,0 +1,210 @@
/*
* 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 { Logger } from '@kbn/core/server';
import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import type { CloudSecurityAlertsStats } from './types';
import { DETECTION_ENGINE_ALERTS_INDEX_DEFAULT } from '../../../../common/constants';
interface AlertsStats {
aggregations: {
cspm: {
rules_count: {
value: number;
};
alerts_open: {
doc_count: number;
};
alerts_acknowledged: {
doc_count: number;
};
alerts_closed: {
doc_count: number;
};
};
kspm: {
rules_count: {
value: number;
};
alerts_open: {
doc_count: number;
};
alerts_acknowledged: {
doc_count: number;
};
alerts_closed: {
doc_count: number;
};
};
vuln_mgmt: {
rules_count: {
value: number;
};
alerts_open: {
doc_count: number;
};
alerts_acknowledged: {
doc_count: number;
};
alerts_closed: {
doc_count: number;
};
};
};
}
const getAlertsStatsQuery = (index: string) => ({
size: 0,
query: {
bool: {
filter: [{ term: { 'kibana.alert.rule.tags': 'Cloud Security' } }],
},
},
sort: '@timestamp:desc',
index,
aggs: {
cspm: {
filter: {
term: {
'kibana.alert.rule.tags': 'CSPM',
},
},
aggs: {
rules_count: {
cardinality: {
field: 'kibana.alert.rule.uuid',
},
},
alerts_open: {
filter: {
term: {
'kibana.alert.workflow_status': 'open',
},
},
},
alerts_acknowledged: {
filter: {
term: {
'kibana.alert.workflow_status': 'acknowledged',
},
},
},
alerts_closed: {
filter: {
term: {
'kibana.alert.workflow_status': 'closed',
},
},
},
},
},
kspm: {
filter: {
term: {
'kibana.alert.rule.tags': 'KSPM',
},
},
aggs: {
rules_count: {
cardinality: {
field: 'kibana.alert.rule.uuid',
},
},
alerts_open: {
filter: {
term: {
'kibana.alert.workflow_status': 'open',
},
},
},
alerts_acknowledged: {
filter: {
term: {
'kibana.alert.workflow_status': 'acknowledged',
},
},
},
alerts_closed: {
filter: {
term: {
'kibana.alert.workflow_status': 'closed',
},
},
},
},
},
vuln_mgmt: {
filter: {
term: {
'kibana.alert.rule.tags': 'CNVM',
},
},
aggs: {
rules_count: {
cardinality: {
field: 'kibana.alert.rule.uuid',
},
},
alerts_open: {
filter: {
term: {
'kibana.alert.workflow_status': 'open',
},
},
},
alerts_acknowledged: {
filter: {
term: {
'kibana.alert.workflow_status': 'acknowledged',
},
},
},
alerts_closed: {
filter: {
term: {
'kibana.alert.workflow_status': 'closed',
},
},
},
},
},
},
});
export const getAlertsStats = async (
esClient: ElasticsearchClient,
logger: Logger
): Promise<CloudSecurityAlertsStats[]> => {
const index = DETECTION_ENGINE_ALERTS_INDEX_DEFAULT;
try {
const isIndexExists = await esClient.indices.exists({
index,
});
if (isIndexExists) {
const alertsStats = await esClient.search<unknown, AlertsStats>(getAlertsStatsQuery(index));
const postureTypes = ['cspm', 'kspm', 'vuln_mgmt'] as const;
return postureTypes.map((postureType) => ({
posture_type: postureType,
rules_count: alertsStats.aggregations?.aggregations[postureType].rules_count.value,
alerts_count: alertsStats.aggregations?.aggregations[postureType].alerts_open.doc_count,
alerts_open_count:
alertsStats.aggregations?.aggregations[postureType].alerts_open.doc_count,
alerts_acknowledged_count:
alertsStats.aggregations?.aggregations[postureType].alerts_acknowledged.doc_count,
alerts_closed_count:
alertsStats.aggregations?.aggregations[postureType].alerts_closed.doc_count,
})) as CloudSecurityAlertsStats[];
}
return [];
} catch (e) {
logger.error(`Failed to get index stats for ${index}: ${e}`);
return [];
}
};

View file

@ -15,6 +15,7 @@ import { CspmUsage } from './types';
import { getAccountsStats } from './accounts_stats_collector';
import { getRulesStats } from './rules_stats_collector';
import { getInstallationStats } from './installation_stats_collector';
import { getAlertsStats } from './alert_stats_collector';
export function registerCspmUsageCollector(
logger: Logger,
@ -34,24 +35,31 @@ export function registerCspmUsageCollector(
return true;
},
fetch: async (collectorFetchContext: CollectorFetchContext) => {
const [indicesStats, accountsStats, resourcesStats, rulesStats, installationStats] =
await Promise.all([
getIndicesStats(
collectorFetchContext.esClient,
collectorFetchContext.soClient,
coreServices,
logger
),
getAccountsStats(collectorFetchContext.esClient, logger),
getResourcesStats(collectorFetchContext.esClient, logger),
getRulesStats(collectorFetchContext.esClient, logger),
getInstallationStats(
collectorFetchContext.esClient,
collectorFetchContext.soClient,
coreServices,
logger
),
]);
const [
indicesStats,
accountsStats,
resourcesStats,
rulesStats,
installationStats,
alertsStats,
] = await Promise.all([
getIndicesStats(
collectorFetchContext.esClient,
collectorFetchContext.soClient,
coreServices,
logger
),
getAccountsStats(collectorFetchContext.esClient, logger),
getResourcesStats(collectorFetchContext.esClient, logger),
getRulesStats(collectorFetchContext.esClient, logger),
getInstallationStats(
collectorFetchContext.esClient,
collectorFetchContext.soClient,
coreServices,
logger
),
getAlertsStats(collectorFetchContext.esClient, logger),
]);
return {
indices: indicesStats,
@ -59,6 +67,7 @@ export function registerCspmUsageCollector(
resources_stats: resourcesStats,
rules_stats: rulesStats,
installation_stats: installationStats,
alerts_stats: alertsStats,
};
},
schema: cspmUsageSchema,

View file

@ -156,4 +156,15 @@ export const cspmUsageSchema: MakeSchemaFrom<CspmUsage> = {
account_type: { type: 'keyword' },
},
},
alerts_stats: {
type: 'array',
items: {
posture_type: { type: 'keyword' },
rules_count: { type: 'long' },
alerts_count: { type: 'long' },
alerts_open_count: { type: 'long' },
alerts_closed_count: { type: 'long' },
alerts_acknowledged_count: { type: 'long' },
},
},
};

View file

@ -13,6 +13,7 @@ export interface CspmUsage {
accounts_stats: CspmAccountsStats[];
rules_stats: CspmRulesStats[];
installation_stats: CloudSecurityInstallationStats[];
alerts_stats: CloudSecurityAlertsStats[];
}
export interface PackageSetupStatus {
@ -88,3 +89,12 @@ export interface CloudSecurityInstallationStats {
agent_count: number;
account_type?: 'single-account' | 'organization-account';
}
export interface CloudSecurityAlertsStats {
posture_type: string;
rules_count: number;
alerts_count: number;
alerts_open_count: number;
alerts_closed_count: number;
alerts_acknowledged_count: number;
}

View file

@ -6613,6 +6613,31 @@
}
}
}
},
"alerts_stats": {
"type": "array",
"items": {
"properties": {
"posture_type": {
"type": "keyword"
},
"rules_count": {
"type": "long"
},
"alerts_count": {
"type": "long"
},
"alerts_open_count": {
"type": "long"
},
"alerts_closed_count": {
"type": "long"
},
"alerts_acknowledged_count": {
"type": "long"
}
}
}
}
}
},