[Security Solution] Add new default policy 'Data Collection' to endpoint onboarding (#149588)

## Summary

Added new configuration option for Elastic Defend integration's
Traditional Endpoint environment:
- Data Collection only configuration option
- uses the already available config policy (added here #144087)
- the default option is NGAV (as before)

Test:
- go to Management / Integrations
- select Elastic Defend
- press the 'Add Elastic Defend' button

<img width="1321" alt="image"
src="https://user-images.githubusercontent.com/39014407/214846703-9632f6e7-18a8-4312-a61d-8ee9255833e0.png">


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Gergő Ábrahám 2023-01-30 13:11:52 +01:00 committed by GitHub
parent 68cb20d66d
commit 7eaa352c6c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 102 additions and 52 deletions

View file

@ -22,7 +22,6 @@ jest.mock('../../../../../../common/lib/kibana');
jest.mock('../../../../../../common/hooks/use_license', () => {
const licenseServiceInstance = {
isPlatinumPlus: jest.fn(),
isGoldPlus: jest.fn(),
isEnterprise: jest.fn(() => true),
};
return {
@ -102,13 +101,14 @@ describe('Onboarding Component new section', () => {
expect(mockedOnChange).toHaveBeenCalledTimes(2);
});
it('make sure NGAV is the default value for endpoint environment', async () => {
it('make sure EDR Complete is the default value for endpoint environment', async () => {
renderResult = mockedContext.render(
<EndpointPolicyCreateExtension newPolicy={getMockNewPackage()} onChange={jest.fn()} />
);
expect(renderResult.getByDisplayValue('NGAV')).toBeChecked();
expect(renderResult.getByDisplayValue('DataCollection')).not.toBeChecked();
expect(renderResult.getByDisplayValue('NGAV')).not.toBeChecked();
expect(renderResult.getByDisplayValue('EDREssential')).not.toBeChecked();
expect(renderResult.getByDisplayValue('EDRComplete')).not.toBeChecked();
expect(renderResult.getByDisplayValue('EDRComplete')).toBeChecked();
});
it('make sure interactive only is the default value for cloud environment', async () => {
@ -120,49 +120,43 @@ describe('Onboarding Component new section', () => {
expect(renderResult.getByDisplayValue('INTERACTIVE_ONLY')).toBeChecked();
});
it('all license should be able to see EDR Licese', async () => {
const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>;
describe('showing license notes for config presets', () => {
it.each`
preset | license | result | text
${'EDREssential'} | ${'below platinum'} | ${'should see'} | ${'Note: advanced protections require a platinum license, and full response capabilities require an enterprise license.'}
${'EDREssential'} | ${'platinum'} | ${'should see'} | ${'Note: advanced protections require a platinum license, and full response capabilities require an enterprise license.'}
${'EDREssential'} | ${'enterprise'} | ${'should NOT see'} | ${''}
${'EDRComplete'} | ${'below platinum'} | ${'should see'} | ${'Note: advanced protections require a platinum license, and full response capabilities require an enterprise license.'}
${'EDRComplete'} | ${'platinum'} | ${'should see'} | ${'Note: advanced protections require a platinum license, and full response capabilities require an enterprise license.'}
${'EDRComplete'} | ${'enterprise'} | ${'should NOT see'} | ${''}
${'NGAV'} | ${'below platinum'} | ${'should see'} | ${'Note: advanced protections require a platinum license level.'}
${'NGAV'} | ${'platinum'} | ${'should NOT see'} | ${''}
${'NGAV'} | ${'enterprise'} | ${'should NOT see'} | ${''}
${'DataCollection'} | ${'below platinum'} | ${'should NOT see'} | ${''}
${'DataCollection'} | ${'platinum'} | ${'should NOT see'} | ${''}
${'DataCollection'} | ${'enterprise'} | ${'should NOT see'} | ${''}
`('$preset: $license users $result notes', ({ license, preset, result, text }) => {
const isEnterprise = license === 'enterprise';
const isPlatinumPlus = ['platinum', 'enterprise'].includes(license);
licenseServiceMock.isEnterprise.mockReturnValue(false);
renderResult = mockedContext.render(
<EndpointPolicyCreateExtension newPolicy={getMockNewPackage()} onChange={jest.fn()} />
);
userEvent.click(screen.getByDisplayValue('EDREssential'));
expect(renderResult.getByDisplayValue('EDREssential')).toBeChecked();
expect(
renderResult.getByText(
'Note: advanced protections require a platinum license, and full response capabilities require an enterprise license.',
{ exact: false }
)
).toBeInTheDocument();
});
const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>;
licenseServiceMock.isEnterprise.mockReturnValue(isEnterprise);
licenseServiceMock.isPlatinumPlus.mockReturnValue(isPlatinumPlus);
it('gold license below users will be able to see NGAV notes', async () => {
const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>;
renderResult = mockedContext.render(
<EndpointPolicyCreateExtension newPolicy={getMockNewPackage()} onChange={jest.fn()} />
);
userEvent.click(screen.getByDisplayValue(preset));
expect(renderResult.getByDisplayValue(preset)).toBeChecked();
licenseServiceMock.isGoldPlus.mockReturnValue(true);
renderResult = mockedContext.render(
<EndpointPolicyCreateExtension newPolicy={getMockNewPackage()} onChange={jest.fn()} />
);
expect(
renderResult.getByText('Note: advanced protections require a platinum license level.', {
exact: false,
})
).toBeInTheDocument();
});
it('platinum license users will not be able to see NGAV notes', async () => {
const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>;
licenseServiceMock.isPlatinumPlus.mockReturnValue(true);
renderResult = mockedContext.render(
<EndpointPolicyCreateExtension newPolicy={getMockNewPackage()} onChange={jest.fn()} />
);
expect(
renderResult.queryByText('Note: advanced protections require a platinum license level.', {
exact: false,
})
).not.toBeInTheDocument();
if (result === 'should see') {
expect(renderResult.getByText(text, { exact: false })).toBeInTheDocument();
} else {
expect(
renderResult.queryByTestId('create-endpoint-policy-license-note')
).not.toBeInTheDocument();
}
});
});
});
});

View file

@ -32,6 +32,7 @@ import {
INTERACTIVE_ONLY,
NGAV_NOTE,
EDR_NOTE,
DATA_COLLECTION,
} from './translations';
const PREFIX = 'endpoint_policy_create_extension';
@ -56,6 +57,10 @@ const endpointPresetsMapping = {
label: EDR_COMPLETE,
note: EDR_NOTE,
},
DataCollection: {
label: DATA_COLLECTION,
note: null,
},
};
const cloudEventMapping = {
@ -85,16 +90,15 @@ export const EndpointPolicyCreateExtension = memo<PackagePolicyCreateExtensionCo
const isPlatinumPlus = useLicense().isPlatinumPlus();
const isEnterprise = useLicense().isEnterprise();
// / Endpoint Radio Options (NGAV and EDRs)
const [endpointPreset, setEndpointPreset] = useState<EndpointPreset>('NGAV');
const [endpointPreset, setEndpointPreset] = useState<EndpointPreset>('EDRComplete');
const [selectedCloudEvent, setSelectedCloudEvent] = useState<CloudEvent>('INTERACTIVE_ONLY');
const [selectedEnvironment, setSelectedEnvironment] = useState<Environment>('endpoint');
// Show NGAV license note when Gold and below
// Show other licenses note when Platinum and Below
// Show EDR licenses note when Platinum and Below
const showNote =
(endpointPreset === 'NGAV' && !isPlatinumPlus) ||
(endpointPreset !== 'NGAV' && !isEnterprise);
(['EDREssential', 'EDRComplete'].includes(endpointPreset) && !isEnterprise);
// Fleet will initialize the create form with a default name for the integrating policy, however,
// for endpoint security, we want the user to explicitly type in a name, so we blank it out
@ -242,6 +246,20 @@ export const EndpointPolicyCreateExtension = memo<PackagePolicyCreateExtensionCo
{selectedEnvironment === 'endpoint' ? (
<>
<EuiSpacer size="m" />
<EuiFormRow
fullWidth
helpText={
<HelpTextWithPadding>
<FormattedMessage
id="xpack.securitySolution.createPackagePolicy.stepConfigure.packagePolicyTypeEndpointDataCollection"
defaultMessage="Augment your existing anti-virus solution with advanced data collection and detection"
/>
</HelpTextWithPadding>
}
>
<EuiRadio {...getEndpointPresetsProps('DataCollection')} />
</EuiFormRow>
<EuiSpacer size="s" />
<EuiFormRow
fullWidth
helpText={
@ -287,7 +305,7 @@ export const EndpointPolicyCreateExtension = memo<PackagePolicyCreateExtensionCo
<>
<EuiSpacer size="m" />
<EuiCallOut iconType="iInCircle">
<EuiText size="s">
<EuiText size="s" data-test-subj="create-ensdpoint-policy-license-note">
<p>
{endpointPresetsMapping[endpointPreset].note}{' '}
<FormattedMessage

View file

@ -42,6 +42,13 @@ export const EDR_NOTE = i18n.translate(
}
);
export const DATA_COLLECTION = i18n.translate(
'xpack.securitySolution.createPackagePolicy.stepConfigure.endpointDropdownOptionDataCollection',
{
defaultMessage: 'Data Collection',
}
);
export const ENDPOINT = i18n.translate(
'xpack.securitySolution.createPackagePolicy.stepConfigure.endpointDropdownOption',
{

View file

@ -13,5 +13,6 @@
export const ENDPOINT_CONFIG_PRESET_NGAV = 'NGAV';
export const ENDPOINT_CONFIG_PRESET_EDR_ESSENTIAL = 'EDREssential';
export const ENDPOINT_CONFIG_PRESET_EDR_COMPLETE = 'EDRComplete';
export const ENDPOINT_CONFIG_PRESET_DATA_COLLECTION = 'DataCollection';
export const ENDPOINT_INTEGRATION_CONFIG_KEY = 'ENDPOINT_INTEGRATION_CONFIG';

View file

@ -116,6 +116,28 @@ describe('Create Default Policy tests ', () => {
});
const OSTypes = ['linux', 'mac', 'windows'] as const;
it('Should return PolicyConfig for events only when preset is DataCollection', () => {
const defaultPolicy = policyFactory();
const config = createEndpointConfig({ preset: 'DataCollection' });
const policy = createDefaultPolicyCallback(config);
// events are the same
expect(policy.windows.events).toEqual(defaultPolicy.windows.events);
expect(policy.linux.events).toEqual(defaultPolicy.linux.events);
expect(policy.mac.events).toEqual(defaultPolicy.mac.events);
// check some of the protections to be disabled
const disabledButSupported = { mode: ProtectionModes.off, supported: true };
expect(policy.windows.behavior_protection).toEqual(disabledButSupported);
expect(policy.mac.memory_protection).toEqual(disabledButSupported);
expect(policy.linux.behavior_protection).toEqual(disabledButSupported);
// malware popups should be disabled
expect(policy.windows.popup.malware.enabled).toBeFalsy();
expect(policy.mac.popup.malware.enabled).toBeFalsy();
expect(policy.linux.popup.malware.enabled).toBeFalsy();
});
it('Should return only process event enabled on policy when preset is NGAV', () => {
const config = createEndpointConfig({ preset: 'NGAV' });
const policy = createDefaultPolicyCallback(config);

View file

@ -16,6 +16,7 @@ import {
ENDPOINT_CONFIG_PRESET_EDR_COMPLETE,
ENDPOINT_CONFIG_PRESET_EDR_ESSENTIAL,
ENDPOINT_CONFIG_PRESET_NGAV,
ENDPOINT_CONFIG_PRESET_DATA_COLLECTION,
} from '../constants';
import { disableProtections } from '../../../common/endpoint/models/policy_config_helpers';
@ -52,8 +53,10 @@ const getEndpointPolicyConfigPreset = (config: PolicyCreateEndpointConfig | unde
const isNGAV = config?.endpointConfig?.preset === ENDPOINT_CONFIG_PRESET_NGAV;
const isEDREssential = config?.endpointConfig?.preset === ENDPOINT_CONFIG_PRESET_EDR_ESSENTIAL;
const isEDRComplete = config?.endpointConfig?.preset === ENDPOINT_CONFIG_PRESET_EDR_COMPLETE;
const isDataCollection =
config?.endpointConfig?.preset === ENDPOINT_CONFIG_PRESET_DATA_COLLECTION;
return { isNGAV, isEDREssential, isEDRComplete };
return { isNGAV, isEDREssential, isEDRComplete, isDataCollection };
};
/**
@ -63,7 +66,8 @@ const getEndpointPolicyWithIntegrationConfig = (
policy: PolicyConfig,
config: PolicyCreateEndpointConfig | undefined
): PolicyConfig => {
const { isNGAV, isEDREssential, isEDRComplete } = getEndpointPolicyConfigPreset(config);
const { isNGAV, isEDREssential, isEDRComplete, isDataCollection } =
getEndpointPolicyConfigPreset(config);
if (isEDRComplete) {
return policy;
@ -98,6 +102,8 @@ const getEndpointPolicyWithIntegrationConfig = (
},
},
};
} else if (isDataCollection) {
return disableProtections(policy);
}
// data collection by default

View file

@ -7,6 +7,7 @@
import type { Logger } from '@kbn/core/server';
import {
ENDPOINT_CONFIG_PRESET_DATA_COLLECTION,
ENDPOINT_CONFIG_PRESET_EDR_COMPLETE,
ENDPOINT_CONFIG_PRESET_EDR_ESSENTIAL,
ENDPOINT_CONFIG_PRESET_NGAV,
@ -39,6 +40,7 @@ const validateEndpointIntegrationConfig = (
ENDPOINT_CONFIG_PRESET_NGAV,
ENDPOINT_CONFIG_PRESET_EDR_COMPLETE,
ENDPOINT_CONFIG_PRESET_EDR_ESSENTIAL,
ENDPOINT_CONFIG_PRESET_DATA_COLLECTION,
].includes(config.endpointConfig.preset)
) {
logger.warn(`invalid endpointConfig preset: ${config.endpointConfig.preset}`);

View file

@ -8,7 +8,7 @@
export interface PolicyCreateEndpointConfig {
type: 'endpoint';
endpointConfig: {
preset: 'NGAV' | 'EDREssential' | 'EDRComplete';
preset: 'NGAV' | 'EDREssential' | 'EDRComplete' | 'DataCollection';
};
}