mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.8] [Cloud Security][Bug Fix] Empty EKS Dashboard / Wrong number of Healthy agents shown fix (#156601) (#156919)
# Backport This will backport the following commits from `main` to `8.8`: - [[Cloud Security][Bug Fix] Empty EKS Dashboard / Wrong number of Healthy agents shown fix (#156601)](https://github.com/elastic/kibana/pull/156601) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Rickyanto Ang","email":"rickyangwyn@gmail.com"},"sourceCommit":{"committedDate":"2023-05-05T20:44:05Z","message":"[Cloud Security][Bug Fix] Empty EKS Dashboard / Wrong number of Healthy agents shown fix (#156601)\n\n## Summary\r\n\r\nThis Fix is to address issue where Healthy agents remains zero even when\r\nwe have Healthy agents and EKS Dashboard is empty even though we have\r\nfindings for that integration flowing in\r\n\r\nAlso added new API test for Benchmark\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b5fc7c4054a1bb97e4f522ee61c19a62054cace9","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Cloud Security","v8.8.0","v8.9.0"],"number":156601,"url":"https://github.com/elastic/kibana/pull/156601","mergeCommit":{"message":"[Cloud Security][Bug Fix] Empty EKS Dashboard / Wrong number of Healthy agents shown fix (#156601)\n\n## Summary\r\n\r\nThis Fix is to address issue where Healthy agents remains zero even when\r\nwe have Healthy agents and EKS Dashboard is empty even though we have\r\nfindings for that integration flowing in\r\n\r\nAlso added new API test for Benchmark\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b5fc7c4054a1bb97e4f522ee61c19a62054cace9"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/156601","number":156601,"mergeCommit":{"message":"[Cloud Security][Bug Fix] Empty EKS Dashboard / Wrong number of Healthy agents shown fix (#156601)\n\n## Summary\r\n\r\nThis Fix is to address issue where Healthy agents remains zero even when\r\nwe have Healthy agents and EKS Dashboard is empty even though we have\r\nfindings for that integration flowing in\r\n\r\nAlso added new API test for Benchmark\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"b5fc7c4054a1bb97e4f522ee61c19a62054cace9"}}]}] BACKPORT--> Co-authored-by: Rickyanto Ang <rickyangwyn@gmail.com>
This commit is contained in:
parent
75f8f72127
commit
2a20412fd0
6 changed files with 242 additions and 141 deletions
|
@ -107,3 +107,10 @@ export type BenchmarkName = CspRuleTemplateMetadata['benchmark']['name'];
|
|||
export type PostureInput = typeof SUPPORTED_CLOUDBEAT_INPUTS[number];
|
||||
export type CloudSecurityPolicyTemplate = typeof SUPPORTED_POLICY_TEMPLATES[number];
|
||||
export type PosturePolicyTemplate = Extract<CloudSecurityPolicyTemplate, 'kspm' | 'cspm'>;
|
||||
|
||||
export interface BenchmarkResponse {
|
||||
items: Benchmark[];
|
||||
total: number;
|
||||
page: number;
|
||||
perPage: number;
|
||||
}
|
||||
|
|
|
@ -19,11 +19,15 @@ import type {
|
|||
} from '@kbn/fleet-plugin/common';
|
||||
import { errors } from '@elastic/elasticsearch';
|
||||
import { CloudSecurityPolicyTemplate, PostureTypes } from '../../common/types';
|
||||
import { SUPPORTED_POLICY_TEMPLATES } from '../../common/constants';
|
||||
import {
|
||||
SUPPORTED_POLICY_TEMPLATES,
|
||||
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
|
||||
} from '../../common/constants';
|
||||
import { CSP_FLEET_PACKAGE_KUERY } from '../../common/utils/helpers';
|
||||
import {
|
||||
BENCHMARK_PACKAGE_POLICY_PREFIX,
|
||||
BenchmarksQueryParams,
|
||||
DEFAULT_BENCHMARKS_PER_PAGE,
|
||||
} from '../../common/schemas/benchmark';
|
||||
|
||||
export const PACKAGE_POLICY_SAVED_OBJECT_TYPE = 'ingest-package-policies';
|
||||
|
@ -34,25 +38,8 @@ const isFleetMissingAgentHttpError = (error: unknown) =>
|
|||
const isPolicyTemplate = (input: any): input is CloudSecurityPolicyTemplate =>
|
||||
SUPPORTED_POLICY_TEMPLATES.includes(input);
|
||||
|
||||
const getPackageNameQuery = (
|
||||
// ADD 3rd case both cspm and kspm, for findings posture type empty => kspm
|
||||
postureType: string,
|
||||
packageName: string,
|
||||
benchmarkFilter?: string
|
||||
): string => {
|
||||
const integrationNameQuery = `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${packageName}`;
|
||||
const integrationPostureType = `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.vars.posture.value:${postureType}`;
|
||||
if (postureType === 'all') {
|
||||
const kquery = benchmarkFilter
|
||||
? `${integrationNameQuery} AND ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name: *${benchmarkFilter}*`
|
||||
: `${integrationNameQuery}`;
|
||||
return kquery;
|
||||
} else {
|
||||
const kquery = benchmarkFilter
|
||||
? `${integrationNameQuery} AND ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name: *${benchmarkFilter}* AND ${integrationPostureType}`
|
||||
: `${integrationNameQuery} AND ${integrationPostureType}`;
|
||||
return kquery;
|
||||
}
|
||||
const getPackageNameQuery = (): string => {
|
||||
return `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:"${CLOUD_SECURITY_POSTURE_PACKAGE_NAME}"`;
|
||||
};
|
||||
|
||||
export type AgentStatusByAgentPolicyMap = Record<string, GetAgentStatusResponse['results']>;
|
||||
|
@ -94,7 +81,7 @@ export const getCspAgentPolicies = async (
|
|||
ignoreMissing: true,
|
||||
});
|
||||
|
||||
export const getCspPackagePolicies = (
|
||||
export const getCspPackagePolicies = async (
|
||||
soClient: SavedObjectsClientContract,
|
||||
packagePolicyService: PackagePolicyClient,
|
||||
packageName: string,
|
||||
|
@ -103,13 +90,37 @@ export const getCspPackagePolicies = (
|
|||
): Promise<ListResult<PackagePolicy>> => {
|
||||
const sortField = queryParams.sort_field?.replaceAll(BENCHMARK_PACKAGE_POLICY_PREFIX, '');
|
||||
|
||||
return packagePolicyService.list(soClient, {
|
||||
kuery: getPackageNameQuery(postureType, packageName, queryParams.benchmark_name),
|
||||
page: queryParams.page,
|
||||
perPage: queryParams.per_page,
|
||||
const allCSPPackages = await packagePolicyService.list(soClient, {
|
||||
kuery: getPackageNameQuery(),
|
||||
page: 1,
|
||||
perPage: 10000,
|
||||
sortField,
|
||||
sortOrder: queryParams.sort_order,
|
||||
});
|
||||
|
||||
const filteredItems = allCSPPackages.items.filter(
|
||||
(pkg) =>
|
||||
pkg.inputs.filter((input) =>
|
||||
postureType === 'all'
|
||||
? input.enabled
|
||||
: input.enabled && input.policy_template === postureType
|
||||
).length > 0 &&
|
||||
(!queryParams.benchmark_name ||
|
||||
pkg.name.toLowerCase().includes(queryParams.benchmark_name.toLowerCase()))
|
||||
);
|
||||
|
||||
const page = queryParams?.page ?? 1;
|
||||
const perPage = queryParams?.per_page ?? DEFAULT_BENCHMARKS_PER_PAGE;
|
||||
|
||||
return {
|
||||
items: filteredItems.slice(
|
||||
(page - 1) * perPage,
|
||||
Math.min(filteredItems.length, page * perPage)
|
||||
),
|
||||
total: filteredItems.length,
|
||||
page,
|
||||
perPage,
|
||||
};
|
||||
};
|
||||
|
||||
export const getInstalledPolicyTemplates = async (
|
||||
|
|
|
@ -9,19 +9,11 @@ import {
|
|||
benchmarksQueryParamsSchema,
|
||||
DEFAULT_BENCHMARKS_PER_PAGE,
|
||||
} from '../../../common/schemas/benchmark';
|
||||
import {
|
||||
PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
getCspPackagePolicies,
|
||||
getCspAgentPolicies,
|
||||
} from '../../lib/fleet_util';
|
||||
import { POSTURE_TYPE_ALL } from '../../../common/constants';
|
||||
import { getCspAgentPolicies } from '../../lib/fleet_util';
|
||||
import { defineGetBenchmarksRoute, getRulesCountForPolicy } from './benchmarks';
|
||||
|
||||
import { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server';
|
||||
import {
|
||||
createMockAgentPolicyService,
|
||||
createPackagePolicyServiceMock,
|
||||
} from '@kbn/fleet-plugin/server/mocks';
|
||||
import { createMockAgentPolicyService } from '@kbn/fleet-plugin/server/mocks';
|
||||
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { createCspRequestHandlerContextMock } from '../../mocks';
|
||||
|
||||
|
@ -154,111 +146,6 @@ describe('benchmarks API', () => {
|
|||
mockSoClient = savedObjectsClientMock.create();
|
||||
});
|
||||
|
||||
describe('test getPackagePolicies', () => {
|
||||
it('should format request by package name', async () => {
|
||||
const mockPackagePolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getCspPackagePolicies(
|
||||
mockSoClient,
|
||||
mockPackagePolicyService,
|
||||
'myPackage',
|
||||
{
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_order: 'desc',
|
||||
},
|
||||
POSTURE_TYPE_ALL
|
||||
);
|
||||
|
||||
expect(mockPackagePolicyService.list.mock.calls[0][1]).toMatchObject(
|
||||
expect.objectContaining({
|
||||
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:myPackage`,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should build sort request by `sort_field` and default `sort_order`', async () => {
|
||||
const mockAgentPolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getCspPackagePolicies(
|
||||
mockSoClient,
|
||||
mockAgentPolicyService,
|
||||
'myPackage',
|
||||
{
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_field: 'package_policy.name',
|
||||
sort_order: 'desc',
|
||||
},
|
||||
POSTURE_TYPE_ALL
|
||||
);
|
||||
|
||||
expect(mockAgentPolicyService.list.mock.calls[0][1]).toMatchObject(
|
||||
expect.objectContaining({
|
||||
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:myPackage`,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
sortField: 'name',
|
||||
sortOrder: 'desc',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should build sort request by `sort_field` and asc `sort_order`', async () => {
|
||||
const mockAgentPolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getCspPackagePolicies(
|
||||
mockSoClient,
|
||||
mockAgentPolicyService,
|
||||
'myPackage',
|
||||
{
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_field: 'package_policy.name',
|
||||
sort_order: 'asc',
|
||||
},
|
||||
POSTURE_TYPE_ALL
|
||||
);
|
||||
|
||||
expect(mockAgentPolicyService.list.mock.calls[0][1]).toMatchObject(
|
||||
expect.objectContaining({
|
||||
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:myPackage`,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
sortField: 'name',
|
||||
sortOrder: 'asc',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should format request by benchmark_name', async () => {
|
||||
const mockAgentPolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getCspPackagePolicies(
|
||||
mockSoClient,
|
||||
mockAgentPolicyService,
|
||||
'myPackage',
|
||||
{
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_order: 'desc',
|
||||
benchmark_name: 'my_cis_benchmark',
|
||||
},
|
||||
POSTURE_TYPE_ALL
|
||||
);
|
||||
|
||||
expect(mockAgentPolicyService.list.mock.calls[0][1]).toMatchObject(
|
||||
expect.objectContaining({
|
||||
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:myPackage AND ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.name: *my_cis_benchmark*`,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('test getAgentPolicies', () => {
|
||||
it('should return one agent policy id when there is duplication', async () => {
|
||||
const agentPolicyService = createMockAgentPolicyService();
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import type { BenchmarkResponse } from '@kbn/cloud-security-posture-plugin/common/types';
|
||||
import type { SuperTest, Test } from 'supertest';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
// import { createPackagePolicy } from './status';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
describe('GET /internal/cloud_security_posture/benchmark', () => {
|
||||
let agentPolicyId: string;
|
||||
let agentPolicyId2: string;
|
||||
let agentPolicyId3: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
|
||||
|
||||
const { body: agentPolicyResponse } = await supertest
|
||||
.post(`/api/fleet/agent_policies`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({
|
||||
name: 'Test policy',
|
||||
namespace: 'default',
|
||||
});
|
||||
|
||||
agentPolicyId = agentPolicyResponse.item.id;
|
||||
|
||||
const { body: agentPolicyResponse2 } = await supertest
|
||||
.post(`/api/fleet/agent_policies`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({
|
||||
name: 'Test policy 2',
|
||||
namespace: 'default',
|
||||
});
|
||||
|
||||
agentPolicyId2 = agentPolicyResponse2.item.id;
|
||||
|
||||
const { body: agentPolicyResponse3 } = await supertest
|
||||
.post(`/api/fleet/agent_policies`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({
|
||||
name: 'Test policy 3',
|
||||
namespace: 'default',
|
||||
});
|
||||
|
||||
agentPolicyId3 = agentPolicyResponse3.item.id;
|
||||
|
||||
await createPackagePolicy(
|
||||
supertest,
|
||||
agentPolicyId,
|
||||
'cspm',
|
||||
'cloudbeat/cis_aws',
|
||||
'aws',
|
||||
'cspm',
|
||||
'CSPM-1'
|
||||
);
|
||||
|
||||
await createPackagePolicy(
|
||||
supertest,
|
||||
agentPolicyId2,
|
||||
'kspm',
|
||||
'cloudbeat/cis_k8s',
|
||||
'vanilla',
|
||||
'kspm',
|
||||
'KSPM-1'
|
||||
);
|
||||
|
||||
await createPackagePolicy(
|
||||
supertest,
|
||||
agentPolicyId3,
|
||||
'vuln_mgmt',
|
||||
'cloudbeat/vuln_mgmt_aws',
|
||||
'aws',
|
||||
'vuln_mgmt',
|
||||
'CNVM-1'
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
it(`Should return non-empty array filled with Rules if user has CSP integrations`, async () => {
|
||||
const { body: res }: { body: BenchmarkResponse } = await supertest
|
||||
.get(`/internal/cloud_security_posture/benchmarks`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.expect(200);
|
||||
|
||||
expect(res.items.length).equal(3);
|
||||
expect(res.total).equal(3);
|
||||
});
|
||||
|
||||
it(`Should return array size 2 when we set per page to be only 2 (total element is still 3)`, async () => {
|
||||
const { body: res }: { body: BenchmarkResponse } = await supertest
|
||||
.get(`/internal/cloud_security_posture/benchmarks?per_page=2`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.expect(200);
|
||||
|
||||
expect(res.items.length).equal(2);
|
||||
expect(res.total).equal(3);
|
||||
});
|
||||
|
||||
it(`Should return array size 2 when we set per page to be only 2 (total element is still 3)`, async () => {
|
||||
const { body: res }: { body: BenchmarkResponse } = await supertest
|
||||
.get(`/internal/cloud_security_posture/benchmarks?per_page=2&page=2`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.expect(200);
|
||||
|
||||
expect(res.items.length).equal(1);
|
||||
expect(res.total).equal(3);
|
||||
});
|
||||
|
||||
it(`Should return empty array when we set page to be above the last page number`, async () => {
|
||||
const { body: res }: { body: BenchmarkResponse } = await supertest
|
||||
.get(`/internal/cloud_security_posture/benchmarks?per_page=2&page=3`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.expect(200);
|
||||
|
||||
expect(res.items.length).equal(0);
|
||||
expect(res.total).equal(3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function createPackagePolicy(
|
||||
supertest: SuperTest<Test>,
|
||||
agentPolicyId: string,
|
||||
policyTemplate: string,
|
||||
input: string,
|
||||
deployment: string,
|
||||
posture: string,
|
||||
packageName: string
|
||||
) {
|
||||
const version = posture === 'kspm' || posture === 'cspm' ? '1.2.8' : '1.3.0-preview2';
|
||||
const title = 'Security Posture Management';
|
||||
const streams = [
|
||||
{
|
||||
enabled: false,
|
||||
data_stream: {
|
||||
type: 'logs',
|
||||
dataset: 'cloud_security_posture.vulnerabilities',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const inputTemplate = {
|
||||
enabled: true,
|
||||
type: input,
|
||||
policy_template: policyTemplate,
|
||||
};
|
||||
|
||||
const inputs = posture === 'vuln_mgmt' ? { ...inputTemplate, streams } : { ...inputTemplate };
|
||||
|
||||
const { body: postPackageResponse } = await supertest
|
||||
.post(`/api/fleet/package_policies`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({
|
||||
force: true,
|
||||
name: packageName,
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
policy_id: agentPolicyId,
|
||||
enabled: true,
|
||||
inputs: [inputs],
|
||||
package: {
|
||||
name: 'cloud_security_posture',
|
||||
title,
|
||||
version,
|
||||
},
|
||||
vars: {
|
||||
deployment: {
|
||||
value: deployment,
|
||||
type: 'text',
|
||||
},
|
||||
posture: {
|
||||
value: posture,
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
return postPackageResponse.item;
|
||||
}
|
|
@ -11,6 +11,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
describe('cloud_security_posture', function () {
|
||||
this.tags(['cloud_security_posture']);
|
||||
loadTestFile(require.resolve('./status'));
|
||||
loadTestFile(require.resolve('./benchmark'));
|
||||
|
||||
// Place your tests files under this directory and add the following here:
|
||||
// loadTestFile(require.resolve('./your test name'));
|
||||
|
|
|
@ -28,6 +28,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
name: 'Test policy',
|
||||
namespace: 'default',
|
||||
});
|
||||
|
||||
agentPolicyId = agentPolicyResponse.item.id;
|
||||
});
|
||||
|
||||
|
@ -103,7 +104,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
}
|
||||
|
||||
async function createPackagePolicy(
|
||||
export async function createPackagePolicy(
|
||||
supertest: SuperTest<Test>,
|
||||
agentPolicyId: string,
|
||||
policyTemplate: string,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue