mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Deprecate csp rule (#147878)
[Cloud-security-posture] - Deprecating `csp-rule` ## Summary We no longer have a need in csp_rule SO. It is time to deprecate it We would like to replace all the usage of the csp_rule with the csp_rule template. All kinds of migrations will be performed in a different PR related to https://github.com/elastic/kibana/issues/147880 ## Related issues - https://github.com/elastic/kibana/issues/143523 Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f4b148c283
commit
81329dac5a
17 changed files with 295 additions and 507 deletions
|
@ -79,7 +79,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"config-global": "b8f559884931609a349e129c717af73d23e7bc76",
|
||||
"connector_token": "fa5301aa5a2914795d3b1b82d0a49939444009da",
|
||||
"core-usage-stats": "f40a213da2c597b0de94e364a4326a5a1baa4ca9",
|
||||
"csp-rule-template": "3679c5f2431da8153878db79c78a4e695357fb61",
|
||||
"csp-rule-template": "d7e403244d466ee0daaf75e1616b9c5d5fd8c1cb",
|
||||
"csp_rule": "d2bb53ea5d2bdfba1a835ad8956dfcd2b2c32e19",
|
||||
"dashboard": "7e37790f802b39c852f905c010e13674e893105a",
|
||||
"endpoint:user-artifact": "f94c250a52b30d0a2d32635f8b4c5bdabd1e25c0",
|
||||
|
|
|
@ -90,18 +90,12 @@ interface CspSetupInstalledStatus extends BaseCspSetupStatus {
|
|||
|
||||
export type CspSetupStatus = CspSetupInstalledStatus | CspSetupNotInstalledStatus;
|
||||
|
||||
export interface CspRulesStatus {
|
||||
all: number;
|
||||
enabled: number;
|
||||
disabled: number;
|
||||
}
|
||||
|
||||
export type AgentPolicyStatus = Pick<AgentPolicy, 'id' | 'name'> & { agents: number };
|
||||
|
||||
export interface Benchmark {
|
||||
package_policy: PackagePolicy;
|
||||
agent_policy: AgentPolicyStatus;
|
||||
rules: CspRulesStatus;
|
||||
rules_count: number;
|
||||
}
|
||||
|
||||
export type BenchmarkId = CspRuleMetadata['benchmark']['id'];
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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 { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { getBenchmarkFromPackagePolicy, getBenchmarkTypeFilter } from './helpers';
|
||||
|
||||
describe('test helper methods', () => {
|
||||
it('get default integration type from inputs with multiple enabled types', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// Both enabled falls back to default
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: true, streams: [] },
|
||||
{ type: 'cloudbeat/cis_eks', enabled: true, streams: [] },
|
||||
];
|
||||
const type = getBenchmarkFromPackagePolicy(mockPackagePolicy.inputs);
|
||||
expect(type).toMatch('cis_k8s');
|
||||
});
|
||||
|
||||
it('get default integration type from inputs without any enabled types', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// None enabled falls back to default
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: false, streams: [] },
|
||||
{ type: 'cloudbeat/cis_eks', enabled: false, streams: [] },
|
||||
];
|
||||
const type = getBenchmarkFromPackagePolicy(mockPackagePolicy.inputs);
|
||||
expect(type).toMatch('cis_k8s');
|
||||
});
|
||||
|
||||
it('get EKS integration type', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// Single EKS selected
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_eks', enabled: true, streams: [] },
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: false, streams: [] },
|
||||
];
|
||||
const typeEks = getBenchmarkFromPackagePolicy(mockPackagePolicy.inputs);
|
||||
expect(typeEks).toMatch('cis_eks');
|
||||
});
|
||||
|
||||
it('get Vanilla K8S integration type', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// Single k8s selected
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_eks', enabled: false, streams: [] },
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: true, streams: [] },
|
||||
];
|
||||
const typeK8s = getBenchmarkFromPackagePolicy(mockPackagePolicy.inputs);
|
||||
expect(typeK8s).toMatch('cis_k8s');
|
||||
});
|
||||
it('get benchmark type filter based on a benchmark id', () => {
|
||||
const typeFilter = getBenchmarkTypeFilter('cis_eks');
|
||||
expect(typeFilter).toMatch('csp-rule-template.attributes.metadata.benchmark.id: "cis_eks"');
|
||||
});
|
||||
});
|
|
@ -6,7 +6,19 @@
|
|||
*/
|
||||
|
||||
import { Truthy } from 'lodash';
|
||||
import { CSP_RULE_SAVED_OBJECT_TYPE } from '../constants';
|
||||
import {
|
||||
NewPackagePolicy,
|
||||
NewPackagePolicyInput,
|
||||
PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
PackagePolicy,
|
||||
PackagePolicyInput,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
|
||||
CLOUDBEAT_VANILLA,
|
||||
CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE,
|
||||
} from '../constants';
|
||||
import { BenchmarkId } from '../types';
|
||||
|
||||
/**
|
||||
* @example
|
||||
|
@ -25,16 +37,34 @@ export const extractErrorMessage = (e: unknown, defaultMessage = 'Unknown Error'
|
|||
return defaultMessage; // TODO: i18n
|
||||
};
|
||||
|
||||
export const createCspRuleSearchFilterByPackagePolicy = ({
|
||||
packagePolicyId,
|
||||
policyId,
|
||||
}: {
|
||||
packagePolicyId: string;
|
||||
policyId?: string;
|
||||
}): string =>
|
||||
`${CSP_RULE_SAVED_OBJECT_TYPE}.attributes.package_policy_id: "${packagePolicyId}"${
|
||||
policyId ? ` AND ${CSP_RULE_SAVED_OBJECT_TYPE}.attributes.policy_id: "${policyId}"` : ''
|
||||
}`;
|
||||
export const getBenchmarkTypeFilter = (type: BenchmarkId): string =>
|
||||
`${CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE}.attributes.metadata.benchmark.id: "${type}"`;
|
||||
|
||||
export const isEnabledBenchmarkInputType = (input: PackagePolicyInput | NewPackagePolicyInput) =>
|
||||
input.enabled;
|
||||
|
||||
export const isCspPackage = (packageName?: string) =>
|
||||
packageName === CLOUD_SECURITY_POSTURE_PACKAGE_NAME;
|
||||
|
||||
export const getBenchmarkFromPackagePolicy = (
|
||||
inputs: PackagePolicy['inputs'] | NewPackagePolicy['inputs']
|
||||
): BenchmarkId => {
|
||||
const enabledInputs = inputs.filter(isEnabledBenchmarkInputType);
|
||||
|
||||
// Use the only enabled input
|
||||
if (enabledInputs.length === 1) {
|
||||
return getInputType(enabledInputs[0].type);
|
||||
}
|
||||
|
||||
// Use the default benchmark id for multiple/none selected
|
||||
return getInputType(CLOUDBEAT_VANILLA);
|
||||
};
|
||||
|
||||
const getInputType = (inputType: string): string => {
|
||||
// Get the last part of the input type, input type structure: cloudbeat/<benchmark_id>
|
||||
return inputType.split('/')[1];
|
||||
};
|
||||
export const getCSPKuery = `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${CLOUD_SECURITY_POSTURE_PACKAGE_NAME}`;
|
||||
|
||||
export function assert(condition: any, msg?: string): asserts condition {
|
||||
if (!condition) {
|
||||
|
|
|
@ -50,7 +50,6 @@ const IntegrationButtonLink = ({
|
|||
policyId: string;
|
||||
}) => {
|
||||
const { application } = useKibana().services;
|
||||
|
||||
return (
|
||||
<EuiLink
|
||||
href={application.getUrlForApp('security', {
|
||||
|
@ -83,7 +82,7 @@ const BENCHMARKS_TABLE_COLUMNS: Array<EuiBasicTableColumn<Benchmark>> = [
|
|||
'data-test-subj': TEST_SUBJ.BENCHMARKS_TABLE_COLUMNS.INTEGRATION_NAME,
|
||||
},
|
||||
{
|
||||
field: 'rules.enabled',
|
||||
field: 'rules_count',
|
||||
name: i18n.translate('xpack.csp.benchmarks.benchmarksTable.rulesColumnTitle', {
|
||||
defaultMessage: 'Rules',
|
||||
}),
|
||||
|
|
|
@ -52,14 +52,9 @@ const getWrapper =
|
|||
};
|
||||
|
||||
const getRuleMock = ({
|
||||
packagePolicyId = chance.guid(),
|
||||
policyId = chance.guid(),
|
||||
savedObjectId = chance.guid(),
|
||||
id = chance.guid(),
|
||||
enabled,
|
||||
}: {
|
||||
packagePolicyId?: string;
|
||||
policyId?: string;
|
||||
savedObjectId?: string;
|
||||
id?: string;
|
||||
enabled: boolean;
|
||||
|
@ -73,6 +68,7 @@ const getRuleMock = ({
|
|||
benchmark: {
|
||||
name: chance.word(),
|
||||
version: chance.sentence(),
|
||||
id: chance.word(),
|
||||
},
|
||||
default_value: chance.sentence(),
|
||||
description: chance.sentence(),
|
||||
|
@ -88,15 +84,11 @@ const getRuleMock = ({
|
|||
tags: [chance.word(), chance.word()],
|
||||
version: chance.sentence(),
|
||||
},
|
||||
package_policy_id: packagePolicyId,
|
||||
policy_id: policyId,
|
||||
enabled,
|
||||
muted: false,
|
||||
},
|
||||
} as RuleSavedObject);
|
||||
|
||||
const params = {
|
||||
policyId: chance.guid(),
|
||||
packagePolicyId: chance.guid(),
|
||||
};
|
||||
|
||||
|
@ -118,6 +110,7 @@ describe('<RulesContainer />', () => {
|
|||
total: 1,
|
||||
savedObjects: [rule1],
|
||||
},
|
||||
policyId: params.packagePolicyId,
|
||||
});
|
||||
|
||||
render(
|
||||
|
|
|
@ -7,11 +7,7 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import { EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import {
|
||||
extractErrorMessage,
|
||||
createCspRuleSearchFilterByPackagePolicy,
|
||||
isNonNullable,
|
||||
} from '../../../common/utils/helpers';
|
||||
import { extractErrorMessage, isNonNullable } from '../../../common/utils/helpers';
|
||||
import { RulesTable } from './rules_table';
|
||||
import { RulesTableHeader } from './rules_table_header';
|
||||
import {
|
||||
|
@ -72,21 +68,21 @@ export const RulesContainer = () => {
|
|||
const [selectedRuleId, setSelectedRuleId] = useState<string | null>(null);
|
||||
const { pageSize, setPageSize } = usePageSize(LOCAL_STORAGE_PAGE_SIZE_RULES_KEY);
|
||||
const [rulesQuery, setRulesQuery] = useState<RulesQuery>({
|
||||
filter: createCspRuleSearchFilterByPackagePolicy({
|
||||
packagePolicyId: params.packagePolicyId,
|
||||
policyId: params.policyId,
|
||||
}),
|
||||
filter: '',
|
||||
search: '',
|
||||
page: 0,
|
||||
perPage: pageSize || 10,
|
||||
});
|
||||
|
||||
const { data, status, error } = useFindCspRules({
|
||||
filter: rulesQuery.filter,
|
||||
search: rulesQuery.search,
|
||||
page: 1,
|
||||
perPage: MAX_ITEMS_PER_PAGE,
|
||||
});
|
||||
const { data, status, error } = useFindCspRules(
|
||||
{
|
||||
filter: rulesQuery.filter,
|
||||
search: rulesQuery.search,
|
||||
page: 1,
|
||||
perPage: MAX_ITEMS_PER_PAGE,
|
||||
},
|
||||
params.packagePolicyId
|
||||
);
|
||||
|
||||
const rulesPageData = useMemo(
|
||||
() => getRulesPageData({ data, error, status }, rulesQuery),
|
||||
|
|
|
@ -7,29 +7,46 @@
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
import { FunctionKeys } from 'utility-types';
|
||||
import type { SavedObjectsFindOptions, SimpleSavedObject } from '@kbn/core/public';
|
||||
import { CSP_RULE_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
import type { CspRule } from '../../../common/schemas';
|
||||
import { NewPackagePolicy, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
getBenchmarkFromPackagePolicy,
|
||||
getBenchmarkTypeFilter,
|
||||
} from '../../../common/utils/helpers';
|
||||
import { CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
import { CspRuleTemplate } from '../../../common/schemas';
|
||||
import { useKibana } from '../../common/hooks/use_kibana';
|
||||
|
||||
export type RuleSavedObject = Omit<SimpleSavedObject<CspRule>, FunctionKeys<SimpleSavedObject>>;
|
||||
export type RuleSavedObject = Omit<
|
||||
SimpleSavedObject<CspRuleTemplate>,
|
||||
FunctionKeys<SimpleSavedObject>
|
||||
>;
|
||||
|
||||
export type RulesQuery = Required<
|
||||
Pick<SavedObjectsFindOptions, 'search' | 'page' | 'perPage' | 'filter'>
|
||||
>;
|
||||
export type RulesQueryResult = ReturnType<typeof useFindCspRules>;
|
||||
|
||||
export const useFindCspRules = ({ search, page, perPage, filter }: RulesQuery) => {
|
||||
export const useFindCspRules = (
|
||||
{ search, page, perPage, filter }: RulesQuery,
|
||||
packagePolicyId: string
|
||||
) => {
|
||||
const { savedObjects } = useKibana().services;
|
||||
|
||||
return useQuery([CSP_RULE_SAVED_OBJECT_TYPE, { search, page, perPage }], () =>
|
||||
savedObjects.client.find<CspRule>({
|
||||
type: CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
search: search ? `"${search}"*` : '',
|
||||
searchFields: ['metadata.name.text'],
|
||||
page: 1,
|
||||
sortField: 'metadata.name',
|
||||
perPage,
|
||||
filter,
|
||||
})
|
||||
return useQuery([CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE, { search, page, perPage }], () =>
|
||||
savedObjects.client
|
||||
.get<NewPackagePolicy>(PACKAGE_POLICY_SAVED_OBJECT_TYPE, packagePolicyId)
|
||||
.then((res) => {
|
||||
const benchmarkId = getBenchmarkFromPackagePolicy(res.attributes.inputs);
|
||||
|
||||
return savedObjects.client.find<CspRuleTemplate>({
|
||||
type: CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE,
|
||||
search: search ? `"${search}"*` : '',
|
||||
searchFields: ['metadata.name.text'],
|
||||
page: 1,
|
||||
sortField: 'metadata.name',
|
||||
perPage,
|
||||
filter: getBenchmarkTypeFilter(benchmarkId),
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
@ -55,13 +55,9 @@ export const createCspBenchmarkIntegrationFixture = ({
|
|||
name: chance.sentence(),
|
||||
agents: chance.integer({ min: 0 }),
|
||||
},
|
||||
rules = {
|
||||
all: chance.integer(),
|
||||
enabled: chance.integer(),
|
||||
disabled: chance.integer(),
|
||||
},
|
||||
rules_count = chance.integer({ min: 0, max: 10 }),
|
||||
}: CreateCspBenchmarkIntegrationFixtureInput = {}): Benchmark => ({
|
||||
package_policy,
|
||||
agent_policy,
|
||||
rules,
|
||||
rules_count,
|
||||
});
|
||||
|
|
|
@ -5,123 +5,26 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createPackagePolicyServiceMock } from '@kbn/fleet-plugin/server/mocks';
|
||||
import { ListResult, PackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import {
|
||||
loggingSystemMock,
|
||||
savedObjectsClientMock,
|
||||
savedObjectsRepositoryMock,
|
||||
} from '@kbn/core/server/mocks';
|
||||
import {
|
||||
ISavedObjectsRepository,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsFindResponse,
|
||||
} from '@kbn/core/server';
|
||||
import { createPackagePolicyMock, deletePackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../../common/constants';
|
||||
import {
|
||||
getBenchmarkInputType,
|
||||
isCspPackagePolicyInstalled,
|
||||
onPackagePolicyPostCreateCallback,
|
||||
removeCspRulesInstancesCallback,
|
||||
} from './fleet_integration';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../../common/constants';
|
||||
import { SavedObjectsFindResponse } from '@kbn/core-saved-objects-api-server';
|
||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
|
||||
describe('create CSP rules with post package create callback', () => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
|
||||
let mockSoClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
let savedObjectRepositoryMock: jest.Mocked<ISavedObjectsRepository>;
|
||||
const ruleAttributes = {
|
||||
id: '41308bcdaaf665761478bb6f0d745a5c',
|
||||
name: 'Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)',
|
||||
tags: ['CIS', 'Kubernetes', 'CIS 1.1.1', 'Master Node Configuration Files'],
|
||||
description:
|
||||
'Ensure that the API server pod specification file has permissions of `644` or more restrictive.\n',
|
||||
rationale:
|
||||
'The API server pod specification file controls various parameters that set the behavior of the API server. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.\n',
|
||||
default_value: 'By default, the `kube-apiserver.yaml` file has permissions of `640`.\n',
|
||||
impact: 'None\n',
|
||||
remediation:
|
||||
'Run the below command (based on the file location on your system) on the\nmaster node.\nFor example,\n```\nchmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n```\n',
|
||||
benchmark: {
|
||||
name: 'CIS Kubernetes V1.20',
|
||||
version: 'v1.0.0',
|
||||
id: 'cis_k8s',
|
||||
},
|
||||
enabled: true,
|
||||
rego_rule_id: 'cis_1_2_2',
|
||||
};
|
||||
describe('is Csp package installed tests', () => {
|
||||
const logger = loggingSystemMock.createLogger();
|
||||
const mockSoClient = savedObjectsClientMock.create();
|
||||
const packagePolicyService = createPackagePolicyServiceMock();
|
||||
|
||||
beforeEach(() => {
|
||||
logger = loggingSystemMock.createLogger();
|
||||
mockSoClient = savedObjectsClientMock.create();
|
||||
return jest.clearAllMocks();
|
||||
});
|
||||
it('should create stateful rules based on rule template', async () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
mockPackagePolicy.package!.name = CLOUD_SECURITY_POSTURE_PACKAGE_NAME;
|
||||
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'index-pattern',
|
||||
title: 'cloud_security_posture-41308bcdaaf665761478bb6f0d745a5c',
|
||||
namespaces: ['default'],
|
||||
},
|
||||
],
|
||||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'csp-rule-template',
|
||||
id: 'csp_rule_template-41308bcdaaf665761478bb6f0d745a5c',
|
||||
attributes: { ...ruleAttributes },
|
||||
},
|
||||
],
|
||||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
await onPackagePolicyPostCreateCallback(logger, mockPackagePolicy, mockSoClient);
|
||||
|
||||
expect(mockSoClient.bulkCreate.mock.calls[0][0]).toMatchObject([
|
||||
{
|
||||
type: 'csp_rule',
|
||||
attributes: {
|
||||
...ruleAttributes,
|
||||
package_policy_id: mockPackagePolicy.id,
|
||||
policy_id: mockPackagePolicy.policy_id,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('validate that all rules templates are fetched', async () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
mockPackagePolicy.package!.name = CLOUD_SECURITY_POSTURE_PACKAGE_NAME;
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'index-pattern',
|
||||
title: 'cloud_security_posture-41308bcdaaf665761478bb6f0d745a5c',
|
||||
namespaces: ['default'],
|
||||
},
|
||||
],
|
||||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'csp-rule-template',
|
||||
id: 'csp_rule_template-41308bcdaaf665761478bb6f0d745a5c',
|
||||
attributes: { ...ruleAttributes },
|
||||
},
|
||||
],
|
||||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
await onPackagePolicyPostCreateCallback(logger, mockPackagePolicy, mockSoClient);
|
||||
|
||||
expect(mockSoClient.find.mock.calls[1][0]).toMatchObject({ perPage: 10000 });
|
||||
});
|
||||
|
||||
it.each([
|
||||
['cloud_security_posture-41308bcdaaf665761478bb6f0d55555', ['default']],
|
||||
['cloud_security_posture-41308bcdaaf665761478bb6f0d88888', ['foo']],
|
||||
|
@ -141,17 +44,6 @@ describe('create CSP rules with post package create callback', () => {
|
|||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'csp-rule-template',
|
||||
title: 'csp_rule_template-41308bcdaaf665761478bb6f0d745a5c',
|
||||
attributes: { ...ruleAttributes },
|
||||
},
|
||||
],
|
||||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
await onPackagePolicyPostCreateCallback(logger, mockPackagePolicy, mockSoClient);
|
||||
|
||||
expect(mockSoClient.updateObjectsSpaces).toHaveBeenCalled();
|
||||
|
@ -167,74 +59,29 @@ describe('create CSP rules with post package create callback', () => {
|
|||
);
|
||||
}
|
||||
);
|
||||
it.each([
|
||||
[1, [createPackagePolicyMock()], true],
|
||||
[0, [], false],
|
||||
])(
|
||||
'isCspPackagePolicyInstalled should return true when other packages exist',
|
||||
async (total, items, expectedCspPolicyResponse) => {
|
||||
packagePolicyService.list.mockImplementationOnce(
|
||||
async (): Promise<ListResult<PackagePolicy>> => {
|
||||
return {
|
||||
items,
|
||||
total,
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
it('validate that all rules templates are deleted', async () => {
|
||||
savedObjectRepositoryMock = savedObjectsRepositoryMock.create();
|
||||
const mockDeletePackagePolicy = deletePackagePolicyMock();
|
||||
savedObjectRepositoryMock.find.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'csp-rule-template',
|
||||
id: 'csp_rule_template-41308bcdaaf665761478bb6f0d745a5c',
|
||||
attributes: { ...ruleAttributes },
|
||||
},
|
||||
],
|
||||
pit_id: undefined,
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
await removeCspRulesInstancesCallback(
|
||||
mockDeletePackagePolicy[0],
|
||||
savedObjectRepositoryMock,
|
||||
logger
|
||||
);
|
||||
|
||||
expect(savedObjectRepositoryMock.find.mock.calls[0][0]).toMatchObject({ perPage: 10000 });
|
||||
});
|
||||
|
||||
it('get default integration type from inputs with multiple enabled types', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// Both enabled falls back to default
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: true, streams: [] },
|
||||
{ type: 'cloudbeat/cis_eks', enabled: true, streams: [] },
|
||||
];
|
||||
const type = getBenchmarkInputType(mockPackagePolicy.inputs);
|
||||
expect(type).toMatch('cis_k8s');
|
||||
});
|
||||
|
||||
it('get default integration type from inputs without any enabled types', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// None enabled falls back to default
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: false, streams: [] },
|
||||
{ type: 'cloudbeat/cis_eks', enabled: false, streams: [] },
|
||||
];
|
||||
const type = getBenchmarkInputType(mockPackagePolicy.inputs);
|
||||
expect(type).toMatch('cis_k8s');
|
||||
});
|
||||
|
||||
it('get EKS integration type', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// Single EKS selected
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_eks', enabled: true, streams: [] },
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: false, streams: [] },
|
||||
];
|
||||
const typeEks = getBenchmarkInputType(mockPackagePolicy.inputs);
|
||||
expect(typeEks).toMatch('cis_eks');
|
||||
});
|
||||
|
||||
it('get Vanilla K8S integration type', () => {
|
||||
const mockPackagePolicy = createPackagePolicyMock();
|
||||
|
||||
// Single k8s selected
|
||||
mockPackagePolicy.inputs = [
|
||||
{ type: 'cloudbeat/cis_eks', enabled: false, streams: [] },
|
||||
{ type: 'cloudbeat/cis_k8s', enabled: true, streams: [] },
|
||||
];
|
||||
const typeK8s = getBenchmarkInputType(mockPackagePolicy.inputs);
|
||||
expect(typeK8s).toMatch('cis_k8s');
|
||||
});
|
||||
const isInstalled = await isCspPackagePolicyInstalled(
|
||||
packagePolicyService,
|
||||
mockSoClient,
|
||||
logger
|
||||
);
|
||||
expect(isInstalled).toEqual(expectedCspPolicyResponse);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,85 +4,20 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type {
|
||||
SavedObjectsBulkCreateObject,
|
||||
SavedObjectsFindResponse,
|
||||
SavedObjectsFindResult,
|
||||
ISavedObjectsRepository,
|
||||
SavedObjectsClientContract,
|
||||
Logger,
|
||||
} from '@kbn/core/server';
|
||||
import {
|
||||
PackagePolicy,
|
||||
DeletePackagePoliciesResponse,
|
||||
PackagePolicyInput,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
import { DeepReadonly } from 'utility-types';
|
||||
import type { Logger } from '@kbn/core/server';
|
||||
import { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { PackagePolicyClient } from '@kbn/fleet-plugin/server';
|
||||
import { PackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import { DataViewSavedObjectAttrs } from '@kbn/data-views-plugin/common';
|
||||
import { createCspRuleSearchFilterByPackagePolicy } from '../../common/utils/helpers';
|
||||
import {
|
||||
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
|
||||
CLOUDBEAT_VANILLA,
|
||||
CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE,
|
||||
} from '../../common/constants';
|
||||
import type { CspRule, CspRuleTemplate } from '../../common/schemas';
|
||||
import type { BenchmarkId } from '../../common/types';
|
||||
import { getCSPKuery } from '../../common/utils/helpers';
|
||||
import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../../common/constants';
|
||||
|
||||
const getBenchmarkTypeFilter = (type: BenchmarkId): string =>
|
||||
`${CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE}.attributes.metadata.benchmark.id: "${type}"`;
|
||||
|
||||
const isEnabledBenchmarkInputType = (input: PackagePolicyInput) => !!input.type && input.enabled;
|
||||
|
||||
export const getBenchmarkInputType = (inputs: PackagePolicy['inputs']): BenchmarkId => {
|
||||
const enabledInputs = inputs.filter(isEnabledBenchmarkInputType);
|
||||
|
||||
// Use the only enabled input
|
||||
if (enabledInputs.length === 1) {
|
||||
return getInputType(enabledInputs[0].type);
|
||||
}
|
||||
|
||||
// Use the default benchmark id for multiple/none selected
|
||||
return getInputType(CLOUDBEAT_VANILLA);
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback to handle creation of PackagePolicies in Fleet
|
||||
*/
|
||||
export const onPackagePolicyPostCreateCallback = async (
|
||||
logger: Logger,
|
||||
packagePolicy: PackagePolicy,
|
||||
savedObjectsClient: SavedObjectsClientContract
|
||||
): Promise<void> => {
|
||||
addDataViewToAllSpaces(savedObjectsClient);
|
||||
|
||||
const benchmarkType = getBenchmarkInputType(packagePolicy.inputs);
|
||||
// Create csp-rules from the generic asset
|
||||
const existingRuleTemplates: SavedObjectsFindResponse<CspRuleTemplate> =
|
||||
await savedObjectsClient.find({
|
||||
type: CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE,
|
||||
perPage: 10000,
|
||||
filter: getBenchmarkTypeFilter(benchmarkType),
|
||||
});
|
||||
|
||||
if (existingRuleTemplates.total === 0) {
|
||||
logger.warn(`expected CSP rule templates to exists for type: ${benchmarkType}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const cspRules = generateRulesFromTemplates(
|
||||
packagePolicy.id,
|
||||
packagePolicy.policy_id,
|
||||
existingRuleTemplates.saved_objects
|
||||
);
|
||||
|
||||
try {
|
||||
await savedObjectsClient.bulkCreate(cspRules);
|
||||
logger.info(`Generated CSP rules for package ${packagePolicy.policy_id}`);
|
||||
} catch (e) {
|
||||
logger.error('failed to generate rules out of template');
|
||||
logger.error(e);
|
||||
}
|
||||
return addDataViewToAllSpaces(savedObjectsClient);
|
||||
};
|
||||
|
||||
async function addDataViewToAllSpaces(savedObjectsClient: SavedObjectsClientContract) {
|
||||
|
@ -99,69 +34,20 @@ async function addDataViewToAllSpaces(savedObjectsClient: SavedObjectsClientCont
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to handle deletion of PackagePolicies in Fleet
|
||||
*/
|
||||
export const removeCspRulesInstancesCallback = async (
|
||||
deletedPackagePolicy: DeepReadonly<DeletePackagePoliciesResponse[number]>,
|
||||
soClient: ISavedObjectsRepository,
|
||||
logger: Logger
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { saved_objects: cspRules }: SavedObjectsFindResponse<CspRule> = await soClient.find({
|
||||
type: CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
filter: createCspRuleSearchFilterByPackagePolicy({
|
||||
packagePolicyId: deletedPackagePolicy.id,
|
||||
policyId: deletedPackagePolicy.policy_id,
|
||||
}),
|
||||
perPage: 10000,
|
||||
});
|
||||
await Promise.all(cspRules.map((rule) => soClient.delete(CSP_RULE_SAVED_OBJECT_TYPE, rule.id)));
|
||||
} catch (e) {
|
||||
logger.error(`Failed to delete CSP rules after delete package ${deletedPackagePolicy.id}`);
|
||||
logger.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
export const isCspPackageInstalled = async (
|
||||
soClient: ISavedObjectsRepository,
|
||||
export const isCspPackagePolicyInstalled = async (
|
||||
packagePolicyClient: PackagePolicyClient,
|
||||
soClient: SavedObjectsClientContract,
|
||||
logger: Logger
|
||||
): Promise<boolean> => {
|
||||
// TODO: check if CSP package installed via the Fleet API
|
||||
try {
|
||||
const { saved_objects: postDeleteRules }: SavedObjectsFindResponse<CspRule> =
|
||||
await soClient.find({
|
||||
type: CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
});
|
||||
const { total } = await packagePolicyClient.list(soClient, {
|
||||
kuery: getCSPKuery,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
if (!postDeleteRules.length) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return total > 0;
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const isCspPackage = (packageName?: string) =>
|
||||
packageName === CLOUD_SECURITY_POSTURE_PACKAGE_NAME;
|
||||
|
||||
const generateRulesFromTemplates = (
|
||||
packagePolicyId: string,
|
||||
policyId: string,
|
||||
cspRuleTemplates: Array<SavedObjectsFindResult<CspRuleTemplate>>
|
||||
): Array<SavedObjectsBulkCreateObject<CspRule>> =>
|
||||
cspRuleTemplates.map((template) => ({
|
||||
type: CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
...template.attributes,
|
||||
package_policy_id: packagePolicyId,
|
||||
policy_id: policyId,
|
||||
},
|
||||
}));
|
||||
|
||||
const getInputType = (inputType: string): string => {
|
||||
// Get the last part of the input type, input type structure: cloudbeat/<benchmark_id>
|
||||
return inputType.split('/')[1];
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@ import { CspServerPluginStartDeps } from './types';
|
|||
import {
|
||||
createFleetAuthzMock,
|
||||
Installation,
|
||||
ListResult,
|
||||
PackagePolicy,
|
||||
UpdatePackagePolicy,
|
||||
} from '@kbn/fleet-plugin/common';
|
||||
|
@ -274,68 +275,57 @@ describe('Cloud Security Posture Plugin', () => {
|
|||
);
|
||||
expect(updatedPackagePolicy).toEqual(packageMock);
|
||||
}
|
||||
|
||||
expect(fleetMock.packagePolicyService.update).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should uninstall resources when package is removed', async () => {
|
||||
fleetMock.packageService.asInternalUser.getInstallation.mockImplementationOnce(
|
||||
async (): Promise<Installation | undefined> => {
|
||||
return;
|
||||
it.each([
|
||||
[1, [createPackagePolicyMock()], 0],
|
||||
[0, [], 1],
|
||||
])(
|
||||
'should uninstall resources when package is removed',
|
||||
async (total, items, expectedNumberOfCallsToUninstallResources) => {
|
||||
fleetMock.packagePolicyService.list.mockImplementationOnce(
|
||||
async (): Promise<ListResult<PackagePolicy>> => {
|
||||
return {
|
||||
items,
|
||||
total,
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const deletedPackagePolicyMock = deletePackagePolicyMock();
|
||||
deletedPackagePolicyMock[0].package!.name = CLOUD_SECURITY_POSTURE_PACKAGE_NAME;
|
||||
|
||||
const packagePolicyPostDeleteCallbacks: PostPackagePolicyDeleteCallback[] = [];
|
||||
fleetMock.registerExternalCallback.mockImplementation((...args) => {
|
||||
if (args[0] === 'postPackagePolicyDelete') {
|
||||
packagePolicyPostDeleteCallbacks.push(args[1]);
|
||||
}
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
const context = coreMock.createPluginInitializerContext<unknown>();
|
||||
plugin = new CspPlugin(context);
|
||||
const spy = jest.spyOn(plugin, 'uninstallResources').mockImplementation();
|
||||
|
||||
// Act
|
||||
await plugin.start(coreStart, mockPlugins);
|
||||
await mockPlugins.fleet.fleetSetupCompleted();
|
||||
|
||||
// Assert
|
||||
expect(fleetMock.packageService.asInternalUser.getInstallation).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(packagePolicyPostDeleteCallbacks.length).toBeGreaterThan(0);
|
||||
|
||||
for (const cb of packagePolicyPostDeleteCallbacks) {
|
||||
await cb(deletedPackagePolicyMock);
|
||||
}
|
||||
);
|
||||
|
||||
const deletedPackagePolicyMock = deletePackagePolicyMock();
|
||||
deletedPackagePolicyMock[0].package!.name = CLOUD_SECURITY_POSTURE_PACKAGE_NAME;
|
||||
|
||||
const packagePolicyPostDeleteCallbacks: PostPackagePolicyDeleteCallback[] = [];
|
||||
fleetMock.registerExternalCallback.mockImplementation((...args) => {
|
||||
if (args[0] === 'postPackagePolicyDelete') {
|
||||
packagePolicyPostDeleteCallbacks.push(args[1]);
|
||||
}
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
const repositoryFindMock = coreStart.savedObjects.createInternalRepository()
|
||||
.find as jest.Mock;
|
||||
|
||||
repositoryFindMock.mockReturnValueOnce(
|
||||
Promise.resolve({
|
||||
saved_objects: [
|
||||
{
|
||||
type: 'csp-rule-template',
|
||||
id: 'csp_rule_template-41308bcdaaf665761478bb6f0d745a5c',
|
||||
benchmark: {
|
||||
id: 'cis_k8s',
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
repositoryFindMock.mockReturnValueOnce(
|
||||
Promise.resolve({
|
||||
saved_objects: [],
|
||||
})
|
||||
);
|
||||
|
||||
const context = coreMock.createPluginInitializerContext<unknown>();
|
||||
plugin = new CspPlugin(context);
|
||||
const spy = jest.spyOn(plugin, 'uninstallResources').mockImplementation();
|
||||
|
||||
// Act
|
||||
await plugin.start(coreStart, mockPlugins);
|
||||
await mockPlugins.fleet.fleetSetupCompleted();
|
||||
|
||||
// Assert
|
||||
expect(fleetMock.packageService.asInternalUser.getInstallation).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(packagePolicyPostDeleteCallbacks.length).toBeGreaterThan(0);
|
||||
|
||||
for (const cb of packagePolicyPostDeleteCallbacks) {
|
||||
await cb(deletedPackagePolicyMock);
|
||||
expect(fleetMock.packagePolicyService.list).toHaveBeenCalledTimes(1);
|
||||
expect(spy).toHaveBeenCalledTimes(expectedNumberOfCallsToUninstallResources);
|
||||
}
|
||||
expect(repositoryFindMock).toHaveBeenCalledTimes(2);
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,6 +24,7 @@ import type {
|
|||
TaskManagerSetupContract,
|
||||
TaskManagerStartContract,
|
||||
} from '@kbn/task-manager-plugin/server';
|
||||
import { isCspPackage } from '../common/utils/helpers';
|
||||
import { isSubscriptionAllowed } from '../common/utils/subscription';
|
||||
import type {
|
||||
CspServerPluginSetup,
|
||||
|
@ -37,10 +38,8 @@ import { setupSavedObjects } from './saved_objects';
|
|||
import { initializeCspIndices } from './create_indices/create_indices';
|
||||
import { initializeCspTransforms } from './create_transforms/create_transforms';
|
||||
import {
|
||||
isCspPackage,
|
||||
isCspPackageInstalled,
|
||||
isCspPackagePolicyInstalled,
|
||||
onPackagePolicyPostCreateCallback,
|
||||
removeCspRulesInstancesCallback,
|
||||
} from './fleet_integration/fleet_integration';
|
||||
import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../common/constants';
|
||||
import {
|
||||
|
@ -135,7 +134,6 @@ export class CspPlugin
|
|||
): Promise<PackagePolicy> => {
|
||||
if (isCspPackage(packagePolicy.package?.name)) {
|
||||
await this.initialize(core, plugins.taskManager);
|
||||
|
||||
const soClient = (await context.core).savedObjects.client;
|
||||
await onPackagePolicyPostCreateCallback(this.logger, packagePolicy, soClient);
|
||||
|
||||
|
@ -152,11 +150,13 @@ export class CspPlugin
|
|||
for (const deletedPackagePolicy of deletedPackagePolicies) {
|
||||
if (isCspPackage(deletedPackagePolicy.package?.name)) {
|
||||
const soClient = core.savedObjects.createInternalRepository();
|
||||
await removeCspRulesInstancesCallback(deletedPackagePolicy, soClient, this.logger);
|
||||
|
||||
const isPackageExists = await isCspPackageInstalled(soClient, this.logger);
|
||||
|
||||
if (isPackageExists) {
|
||||
const packagePolicyService = plugins.fleet.packagePolicyService;
|
||||
const isPackageExists = await isCspPackagePolicyInstalled(
|
||||
packagePolicyService,
|
||||
soClient,
|
||||
this.logger
|
||||
);
|
||||
if (!isPackageExists) {
|
||||
await this.uninstallResources(plugins.taskManager, this.logger);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
getCspPackagePolicies,
|
||||
getCspAgentPolicies,
|
||||
} from '../../lib/fleet_util';
|
||||
import { defineGetBenchmarksRoute, addPackagePolicyCspRules } from './benchmarks';
|
||||
import { defineGetBenchmarksRoute, getRulesCountForPolicy } from './benchmarks';
|
||||
|
||||
import { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server';
|
||||
import {
|
||||
|
@ -259,8 +259,8 @@ describe('benchmarks API', () => {
|
|||
});
|
||||
|
||||
describe('test addPackagePolicyCspRules', () => {
|
||||
it('should filter enabled rules', async () => {
|
||||
const packagePolicy = createPackagePolicyMock();
|
||||
it('should retrieve the rules count by the filtered benchmark type', async () => {
|
||||
const benchmark = 'cis_k8s';
|
||||
mockSoClient.find.mockResolvedValueOnce({
|
||||
aggregations: { enabled_status: { doc_count: 2 } },
|
||||
page: 1,
|
||||
|
@ -274,13 +274,11 @@ describe('benchmarks API', () => {
|
|||
],
|
||||
} as unknown as SavedObjectsFindResponse);
|
||||
|
||||
const cspRulesStatus = await addPackagePolicyCspRules(mockSoClient, packagePolicy);
|
||||
const rulesCount = await getRulesCountForPolicy(mockSoClient, benchmark);
|
||||
|
||||
expect(cspRulesStatus).toEqual({
|
||||
all: 3,
|
||||
enabled: 2,
|
||||
disabled: 1,
|
||||
});
|
||||
const expectedFilter = `csp-rule-template.attributes.metadata.benchmark.id: "${benchmark}"`;
|
||||
expect(mockSoClient.find.mock.calls[0][0].filter).toEqual(expectedFilter);
|
||||
expect(rulesCount).toEqual(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,19 +4,20 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server';
|
||||
import type { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import type { AgentPolicy, PackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import { CspRuleTemplate } from '../../../common/schemas';
|
||||
import { CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
import {
|
||||
BENCHMARKS_ROUTE_PATH,
|
||||
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
|
||||
CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
} from '../../../common/constants';
|
||||
import { benchmarksQueryParamsSchema } from '../../../common/schemas/benchmark';
|
||||
import type { Benchmark, CspRulesStatus } from '../../../common/types';
|
||||
import type { CspRule } from '../../../common/schemas';
|
||||
import type { Benchmark } from '../../../common/types';
|
||||
import {
|
||||
createCspRuleSearchFilterByPackagePolicy,
|
||||
getBenchmarkFromPackagePolicy,
|
||||
getBenchmarkTypeFilter,
|
||||
isNonNullable,
|
||||
} from '../../../common/utils/helpers';
|
||||
import { CspRouter } from '../../types';
|
||||
|
@ -26,52 +27,21 @@ import {
|
|||
getCspAgentPolicies,
|
||||
getCspPackagePolicies,
|
||||
} from '../../lib/fleet_util';
|
||||
import { BenchmarkId } from '../../../common/types';
|
||||
|
||||
export const PACKAGE_POLICY_SAVED_OBJECT_TYPE = 'ingest-package-policies';
|
||||
|
||||
export interface RulesStatusAggregation {
|
||||
enabled_status: {
|
||||
doc_count: number;
|
||||
};
|
||||
}
|
||||
|
||||
export const getCspRulesStatus = (
|
||||
export const getRulesCountForPolicy = async (
|
||||
soClient: SavedObjectsClientContract,
|
||||
packagePolicy: PackagePolicy
|
||||
): Promise<SavedObjectsFindResponse<CspRule, RulesStatusAggregation>> => {
|
||||
const cspRules = soClient.find<CspRule, RulesStatusAggregation>({
|
||||
type: CSP_RULE_SAVED_OBJECT_TYPE,
|
||||
filter: createCspRuleSearchFilterByPackagePolicy({
|
||||
packagePolicyId: packagePolicy.id,
|
||||
policyId: packagePolicy.policy_id,
|
||||
}),
|
||||
aggs: {
|
||||
enabled_status: {
|
||||
filter: {
|
||||
term: {
|
||||
[`${CSP_RULE_SAVED_OBJECT_TYPE}.attributes.enabled`]: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
benchmarkId: BenchmarkId
|
||||
): Promise<number> => {
|
||||
const rules = await soClient.find<CspRuleTemplate>({
|
||||
type: CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE,
|
||||
filter: getBenchmarkTypeFilter(benchmarkId),
|
||||
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;
|
||||
return rules.total;
|
||||
};
|
||||
|
||||
const createBenchmarks = (
|
||||
|
@ -94,17 +64,17 @@ const createBenchmarks = (
|
|||
.filter(isNonNullable) ?? [];
|
||||
|
||||
const benchmarks = cspPackagesOnAgent.map(async (cspPackage) => {
|
||||
const cspRulesStatus = await addPackagePolicyCspRules(soClient, cspPackage);
|
||||
const benchmarkId = getBenchmarkFromPackagePolicy(cspPackage.inputs);
|
||||
const rulesCount = await getRulesCountForPolicy(soClient, benchmarkId);
|
||||
const agentPolicyStatus = {
|
||||
id: agentPolicy.id,
|
||||
name: agentPolicy.name,
|
||||
agents: agentStatusByAgentPolicyId[agentPolicy.id].total,
|
||||
};
|
||||
|
||||
return {
|
||||
package_policy: cspPackage,
|
||||
agent_policy: agentPolicyStatus,
|
||||
rules: cspRulesStatus,
|
||||
rules_count: rulesCount,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -46,6 +46,14 @@ export const cspRuleTemplateSavedObjectMapping: SavedObjectsTypeMappingDefinitio
|
|||
metadata: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'keyword',
|
||||
fields: {
|
||||
text: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
},
|
||||
benchmark: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
"@kbn/es-types",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
"@kbn/ecs",
|
||||
"@kbn/core-saved-objects-api-server",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue