[Cloud Security] add rules status to benchmark API

This commit is contained in:
CohenIdo 2022-05-04 14:43:36 +03:00 committed by GitHub
parent 71a1f04703
commit 876d65c479
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 149 additions and 36 deletions

View file

@ -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;
}

View file

@ -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,
});

View file

@ -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,
},
});
});
});

View file

@ -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,
},
});

View file

@ -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 = (

View file

@ -38,6 +38,14 @@ export const ruleAssetSavedObjectMappings: SavedObjectsType<CspRuleSchema>['mapp
description: {
type: 'text',
},
enabled: {
type: 'boolean',
fields: {
keyword: {
type: 'keyword', // sort
},
},
},
},
};