[8.11] [Cloud Security][Telemetry] Create a unified cloud accounts collector (#167203) (#168050)

# Backport

This will backport the following commits from `main` to `8.11`:
- [[Cloud Security][Telemetry] Create a unified cloud accounts collector
(#167203)](https://github.com/elastic/kibana/pull/167203)

<!--- Backport version: 8.9.7 -->

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

<!--BACKPORT
[{"author":{"name":"Lola","email":"omolola.akinleye@elastic.co"},"sourceCommit":{"committedDate":"2023-10-04T22:26:49Z","message":"[Cloud
Security][Telemetry] Create a unified cloud accounts collector
(#167203)\n\n## Summary\r\n\r\nSummarize your PR. If it involves visual
changes include a screenshot or\r\ngif.\r\n\r\nAdds Cloud Security
Telemetry to track all cloud accounts from products\r\n`CSPM`,`KSPM`,
and`CNVM`\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"fc434d185dfbdac8061aa2c344fb03013f462c9d","branchLabelMapping":{"^v8.12.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Cloud
Security","v8.11.0","v8.12.0"],"number":167203,"url":"https://github.com/elastic/kibana/pull/167203","mergeCommit":{"message":"[Cloud
Security][Telemetry] Create a unified cloud accounts collector
(#167203)\n\n## Summary\r\n\r\nSummarize your PR. If it involves visual
changes include a screenshot or\r\ngif.\r\n\r\nAdds Cloud Security
Telemetry to track all cloud accounts from products\r\n`CSPM`,`KSPM`,
and`CNVM`\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"fc434d185dfbdac8061aa2c344fb03013f462c9d"}},"sourceBranch":"main","suggestedTargetBranches":["8.11"],"targetPullRequestStates":[{"branch":"8.11","label":"v8.11.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.12.0","labelRegex":"^v8.12.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/167203","number":167203,"mergeCommit":{"message":"[Cloud
Security][Telemetry] Create a unified cloud accounts collector
(#167203)\n\n## Summary\r\n\r\nSummarize your PR. If it involves visual
changes include a screenshot or\r\ngif.\r\n\r\nAdds Cloud Security
Telemetry to track all cloud accounts from products\r\n`CSPM`,`KSPM`,
and`CNVM`\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"fc434d185dfbdac8061aa2c344fb03013f462c9d"}}]}]
BACKPORT-->

Co-authored-by: Lola <omolola.akinleye@elastic.co>
This commit is contained in:
Kibana Machine 2023-10-05 12:37:18 -04:00 committed by GitHub
parent 379cbdaea1
commit 6a19c59fbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 699 additions and 5 deletions

View file

@ -20,7 +20,6 @@ export const getIdentifierRuntimeMapping = (): MappingRuntimeFields => ({
!doc["rule.benchmark.posture_type"].empty;
def orchestratorIdAvailable = doc.containsKey("orchestrator.cluster.id") &&
!doc["orchestrator.cluster.id"].empty;
if (!postureTypeAvailable) {
def identifier = orchestratorIdAvailable ?
doc["orchestrator.cluster.id"].value : doc["cluster_id"].value;

View file

@ -0,0 +1,23 @@
/*
* 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 { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
export const getPackagePolicyIdRuntimeMapping = (): MappingRuntimeFields => ({
package_policy_identifier: {
type: 'keyword',
script: {
source: `
def packagePolicyIdAvailable = doc.containsKey("cloud_security_posture.package_policy.id") &&
!doc["cloud_security_posture.package_policy.id"].empty;
if (packagePolicyIdAvailable) {
emit(doc["cloud_security_posture.package_policy.id"].value);
}
`,
},
},
});

View file

@ -20,7 +20,7 @@ export const getSafeKspmClusterIdRuntimeMapping = (): MappingRuntimeFields => ({
!doc["orchestrator.cluster.id"].empty;
def clusterIdAvailable = doc.containsKey("cluster_id") &&
!doc["cluster_id"].empty;
if (orchestratorIdAvailable) {
emit(doc["orchestrator.cluster.id"].value);
} else if (clusterIdAvailable) {

View file

@ -0,0 +1,411 @@
/*
* 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 { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import type { Logger } from '@kbn/core/server';
import type { SearchRequest } from '@elastic/elasticsearch/lib/api/types';
import { getPackagePolicyIdRuntimeMapping } from '../../../../common/runtime_mappings/get_package_policy_id_mapping';
import { getIdentifierRuntimeMapping } from '../../../../common/runtime_mappings/get_identifier_runtime_mapping';
import { calculatePostureScore } from '../../../../common/utils/helpers';
import type {
AccountEntity,
AccountsStats,
CloudProviderKey,
CloudSecurityAccountsStats,
} from './types';
import {
CSPM_POLICY_TEMPLATE,
KSPM_POLICY_TEMPLATE,
LATEST_FINDINGS_INDEX_DEFAULT_NS,
LATEST_VULNERABILITIES_INDEX_DEFAULT_NS,
VULN_MGMT_POLICY_TEMPLATE,
} from '../../../../common/constants';
export const getPostureAccountsStatsQuery = (index: string): SearchRequest => ({
index,
runtime_mappings: { ...getIdentifierRuntimeMapping(), ...getPackagePolicyIdRuntimeMapping() },
query: {
match_all: {},
},
aggs: {
accounts: {
terms: {
field: 'asset_identifier',
order: {
_count: 'desc',
},
size: 100,
},
aggs: {
cloud_provider: {
top_metrics: {
metrics: {
field: 'cloud.provider',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
latest_doc_updated_timestamp: {
top_metrics: {
metrics: {
field: '@timestamp',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
benchmark_id: {
top_metrics: {
metrics: {
field: 'rule.benchmark.id',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
benchmark_version: {
top_metrics: {
metrics: {
field: 'rule.benchmark.version',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
benchmark_name: {
top_metrics: {
metrics: {
field: 'rule.benchmark.name',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
passed_findings_count: {
filter: {
bool: {
filter: [
{
bool: {
should: [
{
term: {
'result.evaluation': 'passed',
},
},
],
minimum_should_match: 1,
},
},
],
},
},
},
failed_findings_count: {
filter: {
bool: {
filter: [
{
bool: {
should: [
{
term: {
'result.evaluation': 'failed',
},
},
],
minimum_should_match: 1,
},
},
],
},
},
},
// KSPM QUERY FIELDS
kubernetes_version: {
top_metrics: {
metrics: {
field: 'cloudbeat.kubernetes.version',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
resources: {
filter: {
bool: {
filter: [
{
bool: {
should: [
{
term: {
'resource.sub_type': 'Pod',
},
},
],
minimum_should_match: 1,
},
},
],
},
},
aggs: {
pods_count: {
cardinality: {
field: 'resource.id',
},
},
},
},
nodes_count: {
cardinality: {
field: 'host.name',
},
},
agents_count: {
cardinality: {
field: 'agent.id',
},
},
package_policy_id: {
terms: {
field: 'package_policy_identifier',
order: {
_count: 'desc',
},
size: 100,
},
},
},
},
},
size: 0,
_source: false,
});
export const getVulnMgmtAccountsStatsQuery = (index: string): SearchRequest => ({
index,
runtime_mappings: getPackagePolicyIdRuntimeMapping(),
query: {
match_all: {},
},
aggs: {
accounts: {
terms: {
field: 'cloud.account.id',
order: {
_count: 'desc',
},
size: 100,
},
aggs: {
latest_doc_updated_timestamp: {
top_metrics: {
metrics: {
field: '@timestamp',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
cloud_provider: {
top_metrics: {
metrics: {
field: 'cloud.provider',
},
size: 1,
sort: {
'@timestamp': 'desc',
},
},
},
package_policy_id: {
terms: {
field: 'package_policy_identifier',
order: {
_count: 'desc',
},
size: 100,
},
},
},
},
},
size: 0,
_source: false,
});
const cloudBaseStats = (account: AccountEntity) => ({
account_id: account.key,
latest_doc_count: account.doc_count,
latest_doc_updated_timestamp: account.latest_doc_updated_timestamp.top[0].metrics['@timestamp'],
cloud_provider: account.cloud_provider.top[0].metrics['cloud.provider'],
package_policy_id: account.package_policy_id?.buckets[0]?.key ?? null,
});
const getPostureManagementStats = (account: AccountEntity) => ({
posture_management_stats: {
posture_score: calculatePostureScore(
account.passed_findings_count.doc_count,
account.failed_findings_count.doc_count
),
passed_findings_count: account.passed_findings_count.doc_count,
failed_findings_count: account.failed_findings_count.doc_count,
benchmark_name: account.benchmark_name.top[0].metrics['rule.benchmark.name'],
benchmark_version: account.benchmark_version.top[0].metrics['rule.benchmark.version'],
},
});
const getKspmStats = (account: AccountEntity) => ({
kspm_stats: {
kubernetes_version: account.kubernetes_version.top[0].metrics['cloudbeat.kubernetes.version'],
agents_count: account.agents_count.value,
nodes_count: account.nodes_count.value,
pods_count: account.resources.pods_count.value,
},
});
const kspmCloudProviders: Record<CloudProviderKey, string | null> = {
cis_eks: 'aws',
cis_gke: 'gcp',
cis_k8s: null,
cis_ake: 'azure',
};
const cspmBenchmarkIds = ['cis_aws', 'cis_azure', 'cis_gcp'];
const kspmBenchmarkIds = ['cis_eks', 'cis_ake', 'cis_gke', 'cis_k8s'];
const getCloudProvider = (ruleBenchmarkId: CloudProviderKey) => {
return kspmCloudProviders[ruleBenchmarkId];
};
const getPostureType = (ruleBenchmarkId: string) => {
if (cspmBenchmarkIds.includes(ruleBenchmarkId)) {
return CSPM_POLICY_TEMPLATE;
} else if (kspmBenchmarkIds.includes(ruleBenchmarkId)) {
return KSPM_POLICY_TEMPLATE;
}
return undefined;
};
export const getCloudAccountsStats = (
aggregatedResourcesStats: AccountsStats,
logger: Logger
): CloudSecurityAccountsStats[] => {
const accounts = aggregatedResourcesStats.accounts.buckets;
const cloudAccountsStats = accounts.map((account) => {
const cloudAccount = cloudBaseStats(account);
const postureType = getPostureType(
account.benchmark_id?.top?.[0]?.metrics['rule.benchmark.id']
);
if (!postureType) {
return {
...cloudAccount,
product: VULN_MGMT_POLICY_TEMPLATE,
};
}
if (postureType === CSPM_POLICY_TEMPLATE) {
return {
...cloudAccount,
product: CSPM_POLICY_TEMPLATE,
...getPostureManagementStats(account),
};
}
return {
...cloudAccount,
product: KSPM_POLICY_TEMPLATE,
...getPostureManagementStats(account),
...getKspmStats(account),
cloud_provider: getCloudProvider(
account.benchmark_id.top[0].metrics['rule.benchmark.id'] as CloudProviderKey
),
};
});
logger.info('Cloud Account Stats telemetry: accounts stats was sent');
return cloudAccountsStats;
};
export const getIndexAccountStats = async (
esClient: ElasticsearchClient,
logger: Logger,
index: string,
getAccountQuery: (index: string) => SearchRequest
) => {
const accountsStatsResponse = await esClient.search<unknown, AccountsStats>(
getAccountQuery(index)
);
return accountsStatsResponse.aggregations
? getCloudAccountsStats(accountsStatsResponse.aggregations, logger)
: [];
};
export const getAllCloudAccountsStats = async (
esClient: ElasticsearchClient,
logger: Logger
): Promise<CloudSecurityAccountsStats[]> => {
try {
const indices = [LATEST_FINDINGS_INDEX_DEFAULT_NS, LATEST_VULNERABILITIES_INDEX_DEFAULT_NS];
const [findingIndex, vulnerabilitiesIndex] = await Promise.all(
indices.map(async (index) => ({
exists: await esClient.indices.exists({
index,
}),
name: index,
}))
);
let postureIndexAccountStats: CloudSecurityAccountsStats[] = [];
let vulnerabilityIndexAccountStats: CloudSecurityAccountsStats[] = [];
if (!findingIndex.exists && !vulnerabilitiesIndex.exists) return [];
if (findingIndex.exists) {
postureIndexAccountStats = await getIndexAccountStats(
esClient,
logger,
findingIndex.name,
getPostureAccountsStatsQuery
);
}
if (vulnerabilitiesIndex.exists) {
vulnerabilityIndexAccountStats = await getIndexAccountStats(
esClient,
logger,
vulnerabilitiesIndex.name,
getVulnMgmtAccountsStatsQuery
);
}
return [...postureIndexAccountStats, ...vulnerabilityIndexAccountStats];
} catch (e) {
logger.error(`Failed to get cloud account stats v2 ${e}`);
logger.error(`Failed to get cloud account stats v2 ${e.stack}`);
return [];
}
};

View file

@ -13,15 +13,69 @@ import {
SO_SEARCH_LIMIT,
} from '@kbn/fleet-plugin/common';
import { agentPolicyService } from '@kbn/fleet-plugin/server/services';
import type { CloudSecurityInstallationStats } from './types';
import type {
CloudbeatConfigKeyType,
CloudSecurityInstallationStats,
SetupAccessOption,
} from './types';
import type { CspServerPluginStart, CspServerPluginStartDeps } from '../../../types';
import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../../../../common/constants';
interface CredentialMappings {
'gcp.credentials.file': 'credentials file';
'gcp.credentials.json': 'credentials json';
shared_credential_file: 'credentials file';
role_arn: 'role';
}
const getEnabledInputStreamVars = (packagePolicy: PackagePolicy) => {
const enabledInput = packagePolicy.inputs.find((input) => input.enabled);
return enabledInput?.streams[0].vars;
};
const getEnabledIsSetupAutomatic = (packagePolicy: PackagePolicy) => {
const cloudbeatConfig: Record<CloudbeatConfigKeyType, string> = {
'cloudbeat/cis_aws': 'cloud_formation_template_url',
'cloudbeat/vuln_mgmt_aws': 'cloud_formation_template_url',
'cloudbeat/cis_gcp': 'cloud_shell_url',
'cloudbeat/cis_azure': 'arm_template_url',
};
const enabledInput = packagePolicy.inputs.find((input) => input.enabled);
if (!enabledInput) return false;
const configKey = cloudbeatConfig[enabledInput.type as CloudbeatConfigKeyType];
return !!configKey && !!enabledInput.config?.[configKey]?.value;
};
const getSetupAccessOption = (
packagePolicy: PackagePolicy
): CloudSecurityInstallationStats['setup_access_option'] => {
const inputStreamVars = getEnabledInputStreamVars(packagePolicy);
if (!inputStreamVars) return null;
const credentialMappings: Record<string, SetupAccessOption> = {
'gcp.credentials.file': 'credentials file',
'gcp.credentials.json': 'credentials json',
shared_credential_file: 'credentials file',
role_arn: 'role',
};
for (const [key, config] of Object.entries(inputStreamVars)) {
if (config?.value && credentialMappings[key as keyof CredentialMappings]) {
return credentialMappings[key as keyof CredentialMappings];
}
}
if (inputStreamVars.session_token) return 'temporary access';
if (inputStreamVars.access_key && inputStreamVars.secret_access_key) return 'direct access';
return null;
};
const getAccountTypeField = (
packagePolicy: PackagePolicy
): CloudSecurityInstallationStats['account_type'] => {
@ -47,6 +101,7 @@ const getInstalledPackagePolicies = (
const agentCounts =
agentPolicies?.find((agentPolicy) => agentPolicy?.id === packagePolicy.policy_id)?.agents ??
0;
const isSetupAutomatic = getEnabledIsSetupAutomatic(packagePolicy);
return {
package_policy_id: packagePolicy.id,
@ -57,6 +112,8 @@ const getInstalledPackagePolicies = (
agent_policy_id: packagePolicy.policy_id,
agent_count: agentCounts,
account_type: getAccountTypeField(packagePolicy),
is_setup_automatic: isSetupAutomatic,
setup_access_option: isSetupAutomatic ? null : getSetupAccessOption(packagePolicy),
};
}
);

View file

@ -16,6 +16,7 @@ import { getAccountsStats } from './accounts_stats_collector';
import { getRulesStats } from './rules_stats_collector';
import { getInstallationStats } from './installation_stats_collector';
import { getAlertsStats } from './alert_stats_collector';
import { getAllCloudAccountsStats } from './cloud_accounts_stats_collector';
export function registerCspmUsageCollector(
logger: Logger,
@ -58,6 +59,7 @@ export function registerCspmUsageCollector(
rulesStats,
installationStats,
alertsStats,
cloudAccountStats,
] = await Promise.all([
awaitPromiseSafe('Indices', getIndicesStats(esClient, soClient, coreServices, logger)),
awaitPromiseSafe('Accounts', getAccountsStats(esClient, logger)),
@ -68,6 +70,7 @@ export function registerCspmUsageCollector(
getInstallationStats(esClient, soClient, coreServices, logger)
),
awaitPromiseSafe('Alerts', getAlertsStats(esClient, logger)),
awaitPromiseSafe('Cloud Accounts', getAllCloudAccountsStats(esClient, logger)),
]);
return {
indices: indicesStats,
@ -76,6 +79,7 @@ export function registerCspmUsageCollector(
rules_stats: rulesStats,
installation_stats: installationStats,
alerts_stats: alertsStats,
cloud_account_stats: cloudAccountStats,
};
},
schema: cspmUsageSchema,

View file

@ -154,6 +154,8 @@ export const cspmUsageSchema: MakeSchemaFrom<CspmUsage> = {
created_at: { type: 'date' },
agent_count: { type: 'long' },
account_type: { type: 'keyword' },
is_setup_automatic: { type: 'boolean' },
setup_access_option: { type: 'keyword' },
},
},
alerts_stats: {
@ -167,4 +169,28 @@ export const cspmUsageSchema: MakeSchemaFrom<CspmUsage> = {
alerts_acknowledged_count: { type: 'long' },
},
},
cloud_account_stats: {
type: 'array',
items: {
account_id: { type: 'keyword' },
cloud_provider: { type: 'keyword' },
product: { type: 'keyword' },
package_policy_id: { type: 'keyword' },
latest_doc_count: { type: 'long' },
latest_doc_updated_timestamp: { type: 'date' },
posture_management_stats: {
posture_score: { type: 'long' },
benchmark_name: { type: 'keyword' },
benchmark_version: { type: 'keyword' },
passed_findings_count: { type: 'long' },
failed_findings_count: { type: 'long' },
},
kspm_stats: {
kubernetes_version: { type: 'keyword' },
agents_count: { type: 'short' },
nodes_count: { type: 'short' },
pods_count: { type: 'short' },
},
},
},
};

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { AggregationsMultiBucketBase } from '@elastic/elasticsearch/lib/api/types';
import { CspStatusCode } from '../../../../common/types';
export type CloudSecurityUsageCollectorType =
@ -13,7 +14,15 @@ export type CloudSecurityUsageCollectorType =
| 'Resources'
| 'Rules'
| 'Installation'
| 'Alerts';
| 'Alerts'
| 'Cloud Accounts';
export type CloudProviderKey = 'cis_eks' | 'cis_gke' | 'cis_k8s' | 'cis_ake';
export type CloudbeatConfigKeyType =
| 'cloudbeat/cis_aws'
| 'cloudbeat/vuln_mgmt_aws'
| 'cloudbeat/cis_gcp'
| 'cloudbeat/cis_azure';
export interface CspmUsage {
indices: CspmIndicesStats;
@ -22,6 +31,7 @@ export interface CspmUsage {
rules_stats: CspmRulesStats[];
installation_stats: CloudSecurityInstallationStats[];
alerts_stats: CloudSecurityAlertsStats[];
cloud_account_stats: CloudSecurityAccountsStats[];
}
export interface PackageSetupStatus {
@ -58,6 +68,32 @@ export interface CspmResourcesStats {
passed_findings_count: number;
failed_findings_count: number;
}
export interface CloudSecurityAccountsStats {
account_id: string;
product: string;
cloud_provider: string | null;
package_policy_id: string | null;
posture_management_stats?: CloudPostureAccountsStats;
kspm_stats?: KSPMAccountsStats;
latest_doc_count: number;
latest_doc_updated_timestamp: string;
}
export interface CloudPostureAccountsStats {
posture_score: number;
benchmark_name: string;
benchmark_version: string;
passed_findings_count: number;
failed_findings_count: number;
}
export interface KSPMAccountsStats {
kubernetes_version: string | null;
agents_count: number;
nodes_count: number;
pods_count: number;
}
export interface CspmAccountsStats {
account_id: string;
posture_score: number;
@ -65,9 +101,9 @@ export interface CspmAccountsStats {
benchmark_id: string;
benchmark_name: string;
benchmark_version: string;
kubernetes_version: string | null;
passed_findings_count: number;
failed_findings_count: number;
kubernetes_version: string | null;
agents_count: number;
nodes_count: number;
pods_count: number;
@ -87,6 +123,13 @@ export interface CspmRulesStats {
failed_findings_count: number;
}
export type SetupAccessOption =
| 'temporary access'
| 'direct access'
| 'role'
| 'credentials file'
| 'credentials json'
| null;
export interface CloudSecurityInstallationStats {
package_policy_id: string;
feature: string;
@ -95,7 +138,9 @@ export interface CloudSecurityInstallationStats {
deployment_mode: string;
created_at: string;
agent_count: number;
is_setup_automatic: boolean;
account_type?: 'single-account' | 'organization-account';
setup_access_option: SetupAccessOption;
}
export interface CloudSecurityAlertsStats {
@ -106,3 +151,66 @@ export interface CloudSecurityAlertsStats {
alerts_closed_count: number;
alerts_acknowledged_count: number;
}
export interface Value {
value: number;
}
export interface BenchmarkName {
metrics: { 'rule.benchmark.name': string };
}
export interface BenchmarkVersion {
metrics: { 'rule.benchmark.version': string };
}
export interface BenchmarkId {
metrics: { 'rule.benchmark.id': string };
}
export interface CloudProvider {
metrics: { 'cloud.provider': string };
}
export interface KubernetesVersion {
metrics: { 'cloudbeat.kubernetes.version': string };
}
export interface PackagePolicyId {
metrics: { 'cloud_security_posture.package_policy.id': string };
}
export interface LatestDocTimestamp {
metrics: { '@timestamp': string };
}
export interface AccountsStats {
accounts: {
buckets: AccountEntity[];
};
}
export interface AccountEntity {
key: string; // account_id
doc_count: number; // latest findings doc count
passed_findings_count: AggregationsMultiBucketBase;
failed_findings_count: AggregationsMultiBucketBase;
package_policy_id: {
doc_count_error_upper_bound: number;
sum_other_doc_count: number;
buckets: Array<{
key: string; // package_policy_id
doc_count: number;
}>;
};
cloud_provider: { top: CloudProvider[] };
latest_doc_updated_timestamp: { top: LatestDocTimestamp[] };
benchmark_id: { top: BenchmarkId[] };
benchmark_name: { top: BenchmarkName[] };
benchmark_version: { top: BenchmarkVersion[] };
kubernetes_version: { top: KubernetesVersion[] };
agents_count: Value;
nodes_count: Value;
pods_count: Value;
resources: {
pods_count: Value;
};
}

View file

@ -7604,6 +7604,12 @@
},
"account_type": {
"type": "keyword"
},
"is_setup_automatic": {
"type": "boolean"
},
"setup_access_option": {
"type": "keyword"
}
}
}
@ -7632,6 +7638,66 @@
}
}
}
},
"cloud_account_stats": {
"type": "array",
"items": {
"properties": {
"account_id": {
"type": "keyword"
},
"cloud_provider": {
"type": "keyword"
},
"product": {
"type": "keyword"
},
"package_policy_id": {
"type": "keyword"
},
"latest_doc_count": {
"type": "long"
},
"latest_doc_updated_timestamp": {
"type": "date"
},
"posture_management_stats": {
"properties": {
"posture_score": {
"type": "long"
},
"benchmark_name": {
"type": "keyword"
},
"benchmark_version": {
"type": "keyword"
},
"passed_findings_count": {
"type": "long"
},
"failed_findings_count": {
"type": "long"
}
}
},
"kspm_stats": {
"properties": {
"kubernetes_version": {
"type": "keyword"
},
"agents_count": {
"type": "short"
},
"nodes_count": {
"type": "short"
},
"pods_count": {
"type": "short"
}
}
}
}
}
}
}
},