mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Cloud Security] add rules status to benchmark API
This commit is contained in:
parent
71a1f04703
commit
876d65c479
6 changed files with 149 additions and 36 deletions
|
@ -47,6 +47,12 @@ export interface ComplianceDashboardData {
|
|||
trend: PostureTrend[];
|
||||
}
|
||||
|
||||
export interface CspRulesStatus {
|
||||
all: number;
|
||||
enabled: number;
|
||||
disabled: number;
|
||||
}
|
||||
|
||||
export interface Benchmark {
|
||||
package_policy: Pick<
|
||||
PackagePolicy,
|
||||
|
@ -61,4 +67,5 @@ export interface Benchmark {
|
|||
| 'created_by'
|
||||
>;
|
||||
agent_policy: Pick<GetAgentPoliciesResponseItem, 'id' | 'name' | 'agents'>;
|
||||
rules: CspRulesStatus;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,13 @@ export const createCspBenchmarkIntegrationFixture = ({
|
|||
name: chance.sentence(),
|
||||
agents: chance.integer({ min: 0 }),
|
||||
},
|
||||
rules = {
|
||||
all: chance.integer(),
|
||||
enabled: chance.integer(),
|
||||
disabled: chance.integer(),
|
||||
},
|
||||
}: CreateCspBenchmarkIntegrationFixtureInput = {}): Benchmark => ({
|
||||
package_policy,
|
||||
agent_policy,
|
||||
rules,
|
||||
});
|
||||
|
|
|
@ -23,12 +23,13 @@ import {
|
|||
import {
|
||||
defineGetBenchmarksRoute,
|
||||
PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
getPackagePolicies,
|
||||
getCspPackagePolicies,
|
||||
getAgentPolicies,
|
||||
createBenchmarkEntry,
|
||||
addPackagePolicyCspRules,
|
||||
} from './benchmarks';
|
||||
|
||||
import { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server';
|
||||
import {
|
||||
createMockAgentPolicyService,
|
||||
createPackagePolicyServiceMock,
|
||||
|
@ -221,7 +222,7 @@ describe('benchmarks API', () => {
|
|||
it('should format request by package name', async () => {
|
||||
const mockPackagePolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getPackagePolicies(mockSoClient, mockPackagePolicyService, 'myPackage', {
|
||||
await getCspPackagePolicies(mockSoClient, mockPackagePolicyService, 'myPackage', {
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_order: 'desc',
|
||||
|
@ -239,7 +240,7 @@ describe('benchmarks API', () => {
|
|||
it('should build sort request by `sort_field` and default `sort_order`', async () => {
|
||||
const mockAgentPolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getPackagePolicies(mockSoClient, mockAgentPolicyService, 'myPackage', {
|
||||
await getCspPackagePolicies(mockSoClient, mockAgentPolicyService, 'myPackage', {
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_field: 'package_policy.name',
|
||||
|
@ -260,7 +261,7 @@ describe('benchmarks API', () => {
|
|||
it('should build sort request by `sort_field` and asc `sort_order`', async () => {
|
||||
const mockAgentPolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getPackagePolicies(mockSoClient, mockAgentPolicyService, 'myPackage', {
|
||||
await getCspPackagePolicies(mockSoClient, mockAgentPolicyService, 'myPackage', {
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_field: 'package_policy.name',
|
||||
|
@ -282,7 +283,7 @@ describe('benchmarks API', () => {
|
|||
it('should format request by benchmark_name', async () => {
|
||||
const mockAgentPolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
await getPackagePolicies(mockSoClient, mockAgentPolicyService, 'myPackage', {
|
||||
await getCspPackagePolicies(mockSoClient, mockAgentPolicyService, 'myPackage', {
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
sort_order: 'desc',
|
||||
|
@ -322,6 +323,32 @@ describe('benchmarks API', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('test addPackagePolicyCspRules', () => {
|
||||
it('should filter enabled rules', async () => {
|
||||
const packagePolicy = createPackagePolicyMock();
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
aggregations: { enabled_status: { doc_count: 2 } },
|
||||
page: 1,
|
||||
per_page: 10000,
|
||||
total: 3,
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'csp_rule',
|
||||
id: '0af387d0-c933-11ec-b6c8-4f8afc058cc3',
|
||||
},
|
||||
],
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
const cspRulesStatus = await addPackagePolicyCspRules(mockSoClient, packagePolicy);
|
||||
|
||||
expect(cspRulesStatus).toEqual({
|
||||
all: 3,
|
||||
enabled: 2,
|
||||
disabled: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('test createBenchmarkEntry', () => {
|
||||
it('should build benchmark entry agent policy and package policy', async () => {
|
||||
const packagePolicy = createPackagePolicyMock();
|
||||
|
@ -329,9 +356,18 @@ describe('benchmarks API', () => {
|
|||
// @ts-expect-error
|
||||
agentPolicy.agents = 3;
|
||||
|
||||
const enrichAgentPolicy = await createBenchmarkEntry(agentPolicy, packagePolicy);
|
||||
const cspRulesStatus = {
|
||||
all: 100,
|
||||
enabled: 52,
|
||||
disabled: 48,
|
||||
};
|
||||
const enrichAgentPolicy = await createBenchmarkEntry(
|
||||
agentPolicy,
|
||||
packagePolicy,
|
||||
cspRulesStatus
|
||||
);
|
||||
|
||||
expect(enrichAgentPolicy).toMatchObject({
|
||||
expect(enrichAgentPolicy).toEqual({
|
||||
package_policy: {
|
||||
id: 'c6d16e42-c32d-4dce-8a88-113cfe276ad1',
|
||||
name: 'endpoint-1',
|
||||
|
@ -348,6 +384,11 @@ describe('benchmarks API', () => {
|
|||
},
|
||||
},
|
||||
agent_policy: { id: 'some-uuid1', name: 'Test Policy', agents: 3 },
|
||||
rules: {
|
||||
all: 100,
|
||||
disabled: 48,
|
||||
enabled: 52,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { uniq, map } from 'lodash';
|
||||
import type { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import type { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server';
|
||||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import type {
|
||||
PackagePolicyServiceInterface,
|
||||
|
@ -19,6 +19,7 @@ import type {
|
|||
AgentPolicy,
|
||||
ListResult,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import { cspRuleAssetSavedObjectType, CspRuleSchema } from '../../../common/schemas/csp_rule';
|
||||
import {
|
||||
BENCHMARKS_ROUTE_PATH,
|
||||
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
|
||||
|
@ -29,7 +30,7 @@ import {
|
|||
BenchmarksQuerySchema,
|
||||
} from '../../../common/schemas/benchmark';
|
||||
import { CspAppContext } from '../../plugin';
|
||||
import type { Benchmark } from '../../../common/types';
|
||||
import type { Benchmark, CspRulesStatus } from '../../../common/types';
|
||||
import { isNonNullable } from '../../../common/utils/helpers';
|
||||
import { CspRouter } from '../../types';
|
||||
|
||||
|
@ -44,7 +45,7 @@ const getPackageNameQuery = (packageName: string, benchmarkFilter?: string): str
|
|||
return kquery;
|
||||
};
|
||||
|
||||
export const getPackagePolicies = (
|
||||
export const getCspPackagePolicies = (
|
||||
soClient: SavedObjectsClientContract,
|
||||
packagePolicyService: PackagePolicyServiceInterface,
|
||||
packageName: string,
|
||||
|
@ -94,10 +95,49 @@ const addRunningAgentToAgentPolicy = async (
|
|||
)
|
||||
);
|
||||
};
|
||||
export interface RulesStatusAggregation {
|
||||
enabled_status: {
|
||||
doc_count: number;
|
||||
};
|
||||
}
|
||||
export const getCspRulesStatus = (
|
||||
soClient: SavedObjectsClientContract,
|
||||
packagePolicy: PackagePolicy
|
||||
): Promise<SavedObjectsFindResponse<CspRuleSchema, RulesStatusAggregation>> => {
|
||||
const cspRules = soClient.find<CspRuleSchema, RulesStatusAggregation>({
|
||||
type: cspRuleAssetSavedObjectType,
|
||||
filter: `${cspRuleAssetSavedObjectType}.attributes.package_policy_id: ${packagePolicy.id} AND ${cspRuleAssetSavedObjectType}.attributes.policy_id: ${packagePolicy.policy_id}`,
|
||||
aggs: {
|
||||
enabled_status: {
|
||||
filter: {
|
||||
term: {
|
||||
[`${cspRuleAssetSavedObjectType}.attributes.enabled`]: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
perPage: 0,
|
||||
});
|
||||
return cspRules;
|
||||
};
|
||||
|
||||
export const addPackagePolicyCspRules = async (
|
||||
soClient: SavedObjectsClientContract,
|
||||
packagePolicy: PackagePolicy
|
||||
): Promise<CspRulesStatus> => {
|
||||
const rules = await getCspRulesStatus(soClient, packagePolicy);
|
||||
const packagePolicyRules = {
|
||||
all: rules.total,
|
||||
enabled: rules.aggregations?.enabled_status.doc_count || 0,
|
||||
disabled: rules.total - (rules.aggregations?.enabled_status.doc_count || 0),
|
||||
};
|
||||
return packagePolicyRules;
|
||||
};
|
||||
|
||||
export const createBenchmarkEntry = (
|
||||
agentPolicy: GetAgentPoliciesResponseItem,
|
||||
packagePolicy: PackagePolicy
|
||||
packagePolicy: PackagePolicy,
|
||||
cspRulesStatus: CspRulesStatus
|
||||
): Benchmark => ({
|
||||
package_policy: {
|
||||
id: packagePolicy.id,
|
||||
|
@ -121,26 +161,33 @@ export const createBenchmarkEntry = (
|
|||
name: agentPolicy.name,
|
||||
agents: agentPolicy.agents,
|
||||
},
|
||||
rules: cspRulesStatus,
|
||||
});
|
||||
|
||||
const createBenchmarks = (
|
||||
soClient: SavedObjectsClientContract,
|
||||
agentPolicies: GetAgentPoliciesResponseItem[],
|
||||
packagePolicies: PackagePolicy[]
|
||||
): Benchmark[] =>
|
||||
packagePolicies.flatMap((packagePolicy) => {
|
||||
return agentPolicies
|
||||
.map((agentPolicy) => {
|
||||
const agentPkgPolicies = agentPolicy.package_policies as string[];
|
||||
const isExistsOnAgent = agentPkgPolicies.find(
|
||||
(pkgPolicy) => pkgPolicy === packagePolicy.id
|
||||
);
|
||||
if (isExistsOnAgent) {
|
||||
return createBenchmarkEntry(agentPolicy, packagePolicy);
|
||||
}
|
||||
return;
|
||||
})
|
||||
.filter(isNonNullable);
|
||||
});
|
||||
cspPackagePolicies: PackagePolicy[]
|
||||
): Promise<Benchmark[]> => {
|
||||
const cspPackagePoliciesMap = new Map(
|
||||
cspPackagePolicies.map((packagePolicy) => [packagePolicy.id, packagePolicy])
|
||||
);
|
||||
return Promise.all(
|
||||
agentPolicies.flatMap((agentPolicy) => {
|
||||
const cspPackagesOnAgent = agentPolicy.package_policies
|
||||
.map((pckPolicyId) => {
|
||||
if (typeof pckPolicyId === 'string') return cspPackagePoliciesMap.get(pckPolicyId);
|
||||
})
|
||||
.filter(isNonNullable);
|
||||
const benchmarks = cspPackagesOnAgent.map(async (cspPackage) => {
|
||||
const cspRulesStatus = await addPackagePolicyCspRules(soClient, cspPackage);
|
||||
const benchmark = createBenchmarkEntry(agentPolicy, cspPackage, cspRulesStatus);
|
||||
return benchmark;
|
||||
});
|
||||
return benchmarks;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const defineGetBenchmarksRoute = (router: CspRouter, cspContext: CspAppContext): void =>
|
||||
router.get(
|
||||
|
@ -165,7 +212,7 @@ export const defineGetBenchmarksRoute = (router: CspRouter, cspContext: CspAppCo
|
|||
throw new Error(`Failed to get Fleet services`);
|
||||
}
|
||||
|
||||
const packagePolicies = await getPackagePolicies(
|
||||
const cspPackagePolicies = await getCspPackagePolicies(
|
||||
soClient,
|
||||
packagePolicyService,
|
||||
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
|
||||
|
@ -174,15 +221,20 @@ export const defineGetBenchmarksRoute = (router: CspRouter, cspContext: CspAppCo
|
|||
|
||||
const agentPolicies = await getAgentPolicies(
|
||||
soClient,
|
||||
packagePolicies.items,
|
||||
cspPackagePolicies.items,
|
||||
agentPolicyService
|
||||
);
|
||||
|
||||
const enrichAgentPolicies = await addRunningAgentToAgentPolicy(agentService, agentPolicies);
|
||||
const benchmarks = createBenchmarks(enrichAgentPolicies, packagePolicies.items);
|
||||
const benchmarks = await createBenchmarks(
|
||||
soClient,
|
||||
enrichAgentPolicies,
|
||||
cspPackagePolicies.items
|
||||
);
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
...packagePolicies,
|
||||
...cspPackagePolicies,
|
||||
items: benchmarks,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -45,18 +45,17 @@ export const getPackagePolicy = async (
|
|||
return packagePolicies![0];
|
||||
};
|
||||
|
||||
export const getCspRules = async (
|
||||
export const getCspRules = (
|
||||
soClient: SavedObjectsClientContract,
|
||||
packagePolicy: PackagePolicy
|
||||
) => {
|
||||
const cspRules = await soClient.find<CspRuleSchema>({
|
||||
): Promise<SavedObjectsFindResponse<CspRuleSchema, unknown>> => {
|
||||
return soClient.find<CspRuleSchema>({
|
||||
type: cspRuleAssetSavedObjectType,
|
||||
filter: `${cspRuleAssetSavedObjectType}.attributes.package_policy_id: ${packagePolicy.id} AND ${cspRuleAssetSavedObjectType}.attributes.policy_id: ${packagePolicy.policy_id}`,
|
||||
searchFields: ['name'],
|
||||
// TODO: research how to get all rules
|
||||
perPage: 10000,
|
||||
});
|
||||
return cspRules;
|
||||
};
|
||||
|
||||
export const createRulesConfig = (
|
||||
|
|
|
@ -38,6 +38,14 @@ export const ruleAssetSavedObjectMappings: SavedObjectsType<CspRuleSchema>['mapp
|
|||
description: {
|
||||
type: 'text',
|
||||
},
|
||||
enabled: {
|
||||
type: 'boolean',
|
||||
fields: {
|
||||
keyword: {
|
||||
type: 'keyword', // sort
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue