[Security Solution] Session Data eventing switch in Linux Endpoint policy (#128149)

This commit is contained in:
Kevin Logan 2022-03-28 11:15:12 -04:00 committed by GitHub
parent 6ef78e69a0
commit 96554163ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 166 additions and 47 deletions

View file

@ -12,7 +12,12 @@ import type { PackagePolicy } from '../../../../common';
import { migratePackagePolicyToV820 as migration } from './to_v8_2_0';
describe('8.2.0 Endpoint Package Policy migration', () => {
const policyDoc = ({ windowsMalware = {}, macMalware = {}, linuxMalware = {} }) => {
const policyDoc = ({
windowsMalware = {},
macMalware = {},
linuxMalware = {},
linuxEvents = {},
}) => {
return {
id: 'mock-saved-object-id',
attributes: {
@ -48,6 +53,7 @@ describe('8.2.0 Endpoint Package Policy migration', () => {
},
linux: {
...linuxMalware,
...linuxEvents,
},
},
},
@ -64,12 +70,14 @@ describe('8.2.0 Endpoint Package Policy migration', () => {
windowsMalware: { malware: { mode: 'off' } },
macMalware: { malware: { mode: 'off' } },
linuxMalware: { malware: { mode: 'off' } },
linuxEvents: { events: { process: true, file: true, network: true } },
});
const migratedDoc = policyDoc({
windowsMalware: { malware: { mode: 'off', blocklist: false } },
macMalware: { malware: { mode: 'off', blocklist: false } },
linuxMalware: { malware: { mode: 'off', blocklist: false } },
linuxEvents: { events: { process: true, file: true, network: true, session_data: false } },
});
expect(migration(initialDoc, {} as SavedObjectMigrationContext)).toEqual(migratedDoc);
@ -80,12 +88,14 @@ describe('8.2.0 Endpoint Package Policy migration', () => {
windowsMalware: { malware: { mode: 'prevent' } },
macMalware: { malware: { mode: 'prevent' } },
linuxMalware: { malware: { mode: 'prevent' } },
linuxEvents: { events: { process: true, file: true, network: true } },
});
const migratedDoc = policyDoc({
windowsMalware: { malware: { mode: 'prevent', blocklist: true } },
macMalware: { malware: { mode: 'prevent', blocklist: true } },
linuxMalware: { malware: { mode: 'prevent', blocklist: true } },
linuxEvents: { events: { process: true, file: true, network: true, session_data: false } },
});
expect(migration(initialDoc, {} as SavedObjectMigrationContext)).toEqual(migratedDoc);
@ -96,12 +106,14 @@ describe('8.2.0 Endpoint Package Policy migration', () => {
windowsMalware: { malware: { mode: 'detect' } },
macMalware: { malware: { mode: 'detect' } },
linuxMalware: { malware: { mode: 'detect' } },
linuxEvents: { events: { process: true, file: true, network: true } },
});
const migratedDoc = policyDoc({
windowsMalware: { malware: { mode: 'detect', blocklist: true } },
macMalware: { malware: { mode: 'detect', blocklist: true } },
linuxMalware: { malware: { mode: 'detect', blocklist: true } },
linuxEvents: { events: { process: true, file: true, network: true, session_data: false } },
});
expect(migration(initialDoc, {} as SavedObjectMigrationContext)).toEqual(migratedDoc);

View file

@ -28,6 +28,8 @@ export const migratePackagePolicyToV820: SavedObjectMigrationFn<PackagePolicy, P
policy.windows.malware.blocklist = policy.windows.malware.mode !== 'off';
policy.mac.malware.blocklist = policy.mac.malware.mode !== 'off';
policy.linux.malware.blocklist = policy.linux.malware.mode !== 'off';
policy.linux.events.session_data = false;
}
return updatedPackagePolicyDoc;

View file

@ -104,6 +104,7 @@ export const policyFactory = (): PolicyConfig => {
process: true,
file: true,
network: true,
session_data: false,
},
malware: {
mode: ProtectionModes.prevent,

View file

@ -984,6 +984,7 @@ export interface PolicyConfig {
file: boolean;
process: boolean;
network: boolean;
session_data: boolean;
};
malware: ProtectionFields & BlocklistFields;
behavior_protection: ProtectionFields & SupportedFields;

View file

@ -873,4 +873,15 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [
}
),
},
{
key: 'linux.advanced.kernel.capture_mode',
first_supported_version: '8.2',
documentation: i18n.translate(
'xpack.securitySolution.endpoint.policy.advanced.linux.advanced.kernel.capture_mode',
{
defaultMessage:
'Allows users to control whether kprobes or ebpf are used to gather data. Possible options are kprobes, ebpf, or auto. Default: auto',
}
),
},
];

View file

@ -332,7 +332,7 @@ describe('policy details: ', () => {
logging: { file: 'info' },
},
linux: {
events: { process: true, file: true, network: true },
events: { process: true, file: true, network: true, session_data: false },
logging: { file: 'info' },
malware: { mode: 'prevent', blocklist: true },
behavior_protection: { mode: 'off', supported: false },

View file

@ -5,10 +5,21 @@
* 2.0.
*/
import React from 'react';
import React, { useContext, useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiCheckbox, EuiSpacer, EuiText, htmlIdGenerator } from '@elastic/eui';
import {
EuiCheckbox,
EuiSpacer,
EuiText,
htmlIdGenerator,
EuiSwitch,
EuiIconTip,
EuiBetaBadge,
EuiFlexItem,
EuiFlexGroup,
} from '@elastic/eui';
import { OperatingSystem } from '@kbn/securitysolution-utils';
import { ThemeContext } from 'styled-components';
import { PolicyOperatingSystem, UIPolicyConfig } from '../../../../../../../common/endpoint/types';
import { ConfigForm, ConfigFormHeading } from '../../components/config_form';
@ -34,54 +45,110 @@ export interface EventFormOption<T extends OperatingSystem> {
protectionField: ProtectionField<T>;
}
export interface SupplementalEventFormOption<T extends OperatingSystem> {
name: string;
protectionField: ProtectionField<T>;
tooltipText?: string;
beta?: boolean;
}
export interface EventsFormProps<T extends OperatingSystem> {
os: T;
options: ReadonlyArray<EventFormOption<T>>;
selection: EventFormSelection<T>;
onValueSelection: (value: ProtectionField<T>, selected: boolean) => void;
supplementalOptions?: ReadonlyArray<SupplementalEventFormOption<T>>;
}
const countSelected = <T extends OperatingSystem>(selection: EventFormSelection<T>) => {
return Object.values(selection).filter((value) => value).length;
};
export const EventsForm = <T extends OperatingSystem>({
const InnerEventsForm = <T extends OperatingSystem>({
os,
options,
selection,
onValueSelection,
}: EventsFormProps<T>) => (
<ConfigForm
type={i18n.translate('xpack.securitySolution.endpoint.policy.details.eventCollection', {
defaultMessage: 'Event collection',
})}
supportedOss={[os]}
rightCorner={
<EuiText size="s" color="subdued">
{i18n.translate('xpack.securitySolution.endpoint.policy.details.eventCollectionsEnabled', {
defaultMessage: '{selected} / {total} event collections enabled',
values: { selected: countSelected(selection), total: options.length },
})}
</EuiText>
}
>
<ConfigFormHeading>
{i18n.translate('xpack.securitySolution.endpoint.policyDetailsConfig.eventingEvents', {
defaultMessage: 'Events',
})}
</ConfigFormHeading>
<EuiSpacer size="s" />
{options.map(({ name, protectionField }) => (
<EuiCheckbox
key={String(protectionField)}
id={htmlIdGenerator()()}
label={name}
data-test-subj={`policy${OPERATING_SYSTEM_TO_TEST_SUBJ[os]}Event_${protectionField}`}
checked={selection[protectionField]}
onChange={(event) => onValueSelection(protectionField, event.target.checked)}
/>
))}
</ConfigForm>
);
supplementalOptions,
}: EventsFormProps<T>) => {
const theme = useContext(ThemeContext);
const countSelected = useCallback(() => {
const supplementalSelectionFields: string[] = supplementalOptions
? supplementalOptions.map((value) => value.protectionField as string)
: [];
return Object.entries(selection).filter(([key, value]) =>
!supplementalSelectionFields.includes(key) ? value : false
).length;
}, [selection, supplementalOptions]);
EventsForm.displayName = 'EventsForm';
return (
<ConfigForm
type={i18n.translate('xpack.securitySolution.endpoint.policy.details.eventCollection', {
defaultMessage: 'Event collection',
})}
supportedOss={[os]}
rightCorner={
<EuiText size="s" color="subdued">
{i18n.translate(
'xpack.securitySolution.endpoint.policy.details.eventCollectionsEnabled',
{
defaultMessage: '{selected} / {total} event collections enabled',
values: {
selected: countSelected(),
total: options.length,
},
}
)}
</EuiText>
}
>
<ConfigFormHeading>
{i18n.translate('xpack.securitySolution.endpoint.policyDetailsConfig.eventingEvents', {
defaultMessage: 'Events',
})}
</ConfigFormHeading>
<EuiSpacer size="s" />
{options.map(({ name, protectionField }) => {
return (
<EuiCheckbox
key={String(protectionField)}
id={htmlIdGenerator()()}
label={name}
data-test-subj={`policy${OPERATING_SYSTEM_TO_TEST_SUBJ[os]}Event_${protectionField}`}
checked={selection[protectionField]}
onChange={(event) => onValueSelection(protectionField, event.target.checked)}
/>
);
})}
{supplementalOptions &&
supplementalOptions.map(({ name, protectionField, tooltipText, beta }) => {
return (
<div key={String(protectionField)} style={{ paddingLeft: theme.eui.paddingSizes.s }}>
<EuiFlexGroup direction="row" gutterSize="xs" alignItems="center">
<EuiFlexItem grow={false}>
<EuiSpacer size="s" />
<EuiSwitch
id={htmlIdGenerator()()}
label={name}
data-test-subj={`policy${OPERATING_SYSTEM_TO_TEST_SUBJ[os]}Event_${protectionField}`}
checked={selection[protectionField]}
onChange={(event) => onValueSelection(protectionField, event.target.checked)}
/>
</EuiFlexItem>
{tooltipText && (
<EuiFlexItem grow={false}>
<EuiIconTip position="right" content={tooltipText} />
</EuiFlexItem>
)}
{beta && (
<EuiFlexItem grow={false}>
<EuiBetaBadge label="beta" size="s" />
</EuiFlexItem>
)}
</EuiFlexGroup>
</div>
);
})}
</ConfigForm>
);
};
InnerEventsForm.displayName = 'EventsForm';
export const EventsForm = React.memo(InnerEventsForm) as typeof InnerEventsForm;

View file

@ -12,7 +12,11 @@ import { OperatingSystem } from '@kbn/securitysolution-utils';
import { policyConfig } from '../../../store/policy_details/selectors';
import { setIn } from '../../../models/policy_details_config';
import { usePolicyDetailsSelector } from '../../policy_hooks';
import { EventFormOption, EventsForm } from '../../components/events_form';
import {
EventFormOption,
EventsForm,
SupplementalEventFormOption,
} from '../../components/events_form';
const OPTIONS: ReadonlyArray<EventFormOption<OperatingSystem.LINUX>> = [
{
@ -21,6 +25,15 @@ const OPTIONS: ReadonlyArray<EventFormOption<OperatingSystem.LINUX>> = [
}),
protectionField: 'file',
},
{
name: i18n.translate(
'xpack.securitySolution.endpoint.policyDetailsConfig.linux.events.network',
{
defaultMessage: 'Network',
}
),
protectionField: 'network',
},
{
name: i18n.translate(
'xpack.securitySolution.endpoint.policyDetailsConfig.linux.events.process',
@ -30,14 +43,25 @@ const OPTIONS: ReadonlyArray<EventFormOption<OperatingSystem.LINUX>> = [
),
protectionField: 'process',
},
];
const SUPPLEMENTAL_OPTIONS: ReadonlyArray<SupplementalEventFormOption<OperatingSystem.LINUX>> = [
{
name: i18n.translate(
'xpack.securitySolution.endpoint.policyDetailsConfig.linux.events.network',
'xpack.securitySolution.endpoint.policyDetailsConfig.linux.events.session_data',
{
defaultMessage: 'Network',
defaultMessage: 'Include session data',
}
),
protectionField: 'network',
protectionField: 'session_data',
tooltipText: i18n.translate(
'xpack.securitySolution.endpoint.policyDetailsConfig.linux.events.session_data.tooltip',
{
defaultMessage:
'Capture the extended process event data required for Session View. Session View helps you investigate process, user, and service activity on your Linux infrastructure by displaying session and process execution data organized in a tree according to the Linux process model. NOTE: Capturing extended process events substantially increases data usage.',
}
),
beta: true,
},
];
@ -50,6 +74,7 @@ export const LinuxEvents = memo(() => {
os={OperatingSystem.LINUX}
selection={policyDetailsConfig.linux.events}
options={OPTIONS}
supplementalOptions={SUPPLEMENTAL_OPTIONS}
onValueSelection={(value, selected) =>
dispatch({
type: 'userChangedPolicyConfig',