Skip to content

Commit

Permalink
Migrate Host risk and User risk UI to ECS schema (#140080)
Browse files Browse the repository at this point in the history
* Migrate Host risk and User risk indices to ECS schema

* Update es_archiver to match the new calculated_level type
  • Loading branch information
machadoum authored Sep 9, 2022
1 parent 46a4762 commit 8ce4748
Show file tree
Hide file tree
Showing 52 changed files with 543 additions and 520 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,35 @@ export interface RiskScoreRequestOptions extends IEsSearchRequest {
export interface HostsRiskScoreStrategyResponse extends IEsSearchResponse {
inspect?: Maybe<Inspect>;
totalCount: number;
data: HostsRiskScore[] | undefined;
data: HostRiskScore[] | undefined;
}

export interface UsersRiskScoreStrategyResponse extends IEsSearchResponse {
inspect?: Maybe<Inspect>;
totalCount: number;
data: UsersRiskScore[] | undefined;
data: UserRiskScore[] | undefined;
}

export interface RiskScore {
'@timestamp': string;
risk: string;
risk_stats: {
rule_risks: RuleRisk[];
risk_score: number;
};
export interface RiskStats {
rule_risks: RuleRisk[];
calculated_score_norm: number;
multipliers: string[];
calculated_level: RiskSeverity;
}

export interface HostsRiskScore extends RiskScore {
export interface HostRiskScore {
'@timestamp': string;
host: {
name: string;
risk: RiskStats;
};
}

export interface UsersRiskScore extends RiskScore {
export interface UserRiskScore {
'@timestamp': string;
user: {
name: string;
risk: RiskStats;
};
}

Expand All @@ -66,17 +68,23 @@ export type RiskScoreSortField = SortField<RiskScoreFields>;
export const enum RiskScoreFields {
timestamp = '@timestamp',
hostName = 'host.name',
hostRiskScore = 'host.risk.calculated_score_norm',
hostRisk = 'host.risk.calculated_level',
userName = 'user.name',
riskScore = 'risk_stats.risk_score',
risk = 'risk',
userRiskScore = 'user.risk.calculated_score_norm',
userRisk = 'user.risk.calculated_level',
}

export interface RiskScoreItem {
_id?: Maybe<string>;
[RiskScoreFields.hostName]: Maybe<string>;
[RiskScoreFields.userName]: Maybe<string>;
[RiskScoreFields.risk]: Maybe<RiskSeverity>;
[RiskScoreFields.riskScore]: Maybe<number>;

[RiskScoreFields.hostRisk]: Maybe<RiskSeverity>;
[RiskScoreFields.userRisk]: Maybe<RiskSeverity>;

[RiskScoreFields.hostRiskScore]: Maybe<number>;
[RiskScoreFields.userRiskScore]: Maybe<number>;
}

export const enum RiskSeverity {
Expand All @@ -86,3 +94,6 @@ export const enum RiskSeverity {
high = 'High',
critical = 'Critical',
}

export const isUserRiskScore = (risk: HostRiskScore | UserRiskScore): risk is UserRiskScore =>
'user' in risk;
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ export enum RiskQueries {
kpiRiskScore = 'kpiRiskScore',
}

export type RiskScoreAggByFields = 'host.name' | 'user.name';
export const enum RiskScoreEntity {
host = 'host',
user = 'user',
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import type { IEsSearchRequest, IEsSearchResponse } from '@kbn/data-plugin/common';
import type { FactoryQueryTypes, RiskScoreAggByFields, RiskSeverity } from '../..';
import type { FactoryQueryTypes, RiskScoreEntity, RiskSeverity } from '../..';
import type { ESQuery } from '../../../../typed_json';

import type { Inspect, Maybe } from '../../../common';
Expand All @@ -15,7 +15,7 @@ export interface KpiRiskScoreRequestOptions extends IEsSearchRequest {
defaultIndex: string[];
factoryQueryType?: FactoryQueryTypes;
filterQuery?: ESQuery | string | undefined;
aggBy: RiskScoreAggByFields;
entity: RiskScoreEntity;
}

export interface KpiRiskScoreStrategyResponse extends IEsSearchResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,15 @@
* 2.0.
*/

import type { CommonFields, Maybe, RiskSeverity, SortField } from '../../..';
import type { CommonFields, Maybe, RiskScoreFields, RiskSeverity, SortField } from '../../..';
import type { HostEcs } from '../../../../ecs/host';
import type { UserEcs } from '../../../../ecs/user';

export const enum UserRiskScoreFields {
timestamp = '@timestamp',
userName = 'user.name',
riskScore = 'risk_stats.risk_score',
risk = 'risk',
}

export interface UserRiskScoreItem {
_id?: Maybe<string>;
[UserRiskScoreFields.userName]: Maybe<string>;
[UserRiskScoreFields.risk]: Maybe<RiskSeverity>;
[UserRiskScoreFields.riskScore]: Maybe<number>;
[RiskScoreFields.userName]: Maybe<string>;
[RiskScoreFields.userRisk]: Maybe<RiskSeverity>;
[RiskScoreFields.userRiskScore]: Maybe<number>;
}

export interface UserItem {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { render } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import { NO_HOST_RISK_DATA_DESCRIPTION } from './translations';
import { HostRiskSummary } from './host_risk_summary';
import { RiskSeverity } from '../../../../../common/search_strategy';

describe('HostRiskSummary', () => {
it('renders host risk data', () => {
const riskKeyword = 'test risk';
const riskSeverity = RiskSeverity.low;
const hostRisk = {
loading: false,
isModuleEnabled: true,
Expand All @@ -23,11 +24,12 @@ describe('HostRiskSummary', () => {
'@timestamp': '1641902481',
host: {
name: 'test-host-name',
},
risk: riskKeyword,
risk_stats: {
risk_score: 9999,
rule_risks: [],
risk: {
multipliers: [],
calculated_score_norm: 9999,
calculated_level: riskSeverity,
rule_risks: [],
},
},
},
],
Expand All @@ -39,7 +41,7 @@ describe('HostRiskSummary', () => {
</TestProviders>
);

expect(getByText(riskKeyword)).toBeInTheDocument();
expect(getByText(riskSeverity)).toBeInTheDocument();
});

it('renders spinner when loading', () => {
Expand Down Expand Up @@ -67,11 +69,12 @@ describe('HostRiskSummary', () => {
'@timestamp': '1641902530',
host: {
name: 'test-host-name',
},
risk: 'test-risk',
risk_stats: {
risk_score: 9999,
rule_risks: [],
risk: {
multipliers: [],
calculated_score_norm: 9999,
calculated_level: RiskSeverity.low,
rule_risks: [],
},
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import * as i18n from './translations';
import { RISKY_HOSTS_DOC_LINK } from '../../../../overview/components/overview_risky_host_links/risky_hosts_disabled_module';
import { EnrichedDataRow, ThreatSummaryPanelHeader } from './threat_summary_view';
import { RiskScore } from '../../severity/common';
import type { RiskSeverity } from '../../../../../common/search_strategy';
import type { HostRisk } from '../../../../risk_score/containers';

const HostRiskSummaryComponent: React.FC<{
Expand All @@ -25,12 +24,12 @@ const HostRiskSummaryComponent: React.FC<{
toolTipContent={
<FormattedMessage
id="xpack.securitySolution.alertDetails.overview.hostDataTooltipContent"
defaultMessage="Risk classification is displayed only when available for a host. Ensure {hostsRiskScoreDocumentationLink} is enabled within your environment."
defaultMessage="Risk classification is displayed only when available for a host. Ensure {hostRiskScoreDocumentationLink} is enabled within your environment."
values={{
hostsRiskScoreDocumentationLink: (
hostRiskScoreDocumentationLink: (
<EuiLink href={RISKY_HOSTS_DOC_LINK} target="_blank">
<FormattedMessage
id="xpack.securitySolution.alertDetails.overview.hostsRiskScoreLink"
id="xpack.securitySolution.alertDetails.overview.hostRiskScoreLink"
defaultMessage="Host Risk Score"
/>
</EuiLink>
Expand All @@ -56,7 +55,10 @@ const HostRiskSummaryComponent: React.FC<{
<EnrichedDataRow
field={i18n.HOST_RISK_CLASSIFICATION}
value={
<RiskScore severity={hostRisk.result[0].risk as RiskSeverity} hideBackgroundColor />
<RiskScore
severity={hostRisk.result[0].host.risk.calculated_level}
hideBackgroundColor
/>
}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ import { HeaderSection } from '../header_section';
import { InspectButton, InspectButtonContainer } from '../inspect';
import * as i18n from './translations';
import { PreferenceFormattedDate } from '../formatted_date';
import type { RiskScore } from '../../../../common/search_strategy';
import type { HostRiskScore, UserRiskScore } from '../../../../common/search_strategy';
import { isUserRiskScore } from '../../../../common/search_strategy';

export interface RiskScoreOverTimeProps {
from: string;
to: string;
loading: boolean;
riskScore?: RiskScore[];
riskScore?: Array<HostRiskScore | UserRiskScore>;
queryId: string;
title: string;
toggleStatus: boolean;
Expand Down Expand Up @@ -81,7 +82,7 @@ const RiskScoreOverTimeComponent: React.FC<RiskScoreOverTimeProps> = ({
riskScore
?.map((data) => ({
x: data['@timestamp'],
y: data.risk_stats.risk_score,
y: (isUserRiskScore(data) ? data.user : data.host).risk.calculated_score_norm,
}))
.reverse() ?? [],
[riskScore]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const mockGlobalState: State = {
hostRisk: {
activePage: 0,
limit: 10,
sort: { field: RiskScoreFields.riskScore, direction: Direction.desc },
sort: { field: RiskScoreFields.hostRiskScore, direction: Direction.desc },
severitySelection: [],
},
sessions: { activePage: 0, limit: 10 },
Expand All @@ -106,7 +106,7 @@ export const mockGlobalState: State = {
hostRisk: {
activePage: 0,
limit: 10,
sort: { field: RiskScoreFields.riskScore, direction: Direction.desc },
sort: { field: RiskScoreFields.hostRiskScore, direction: Direction.desc },
severitySelection: [],
},
sessions: { activePage: 0, limit: 10 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ const HostRiskInformationFlyout = ({ handleOnClose }: { handleOnClose: () => voi
<EuiSpacer size="l" />
<FormattedMessage
id="xpack.securitySolution.hosts.hostRiskInformation.learnMore"
defaultMessage="You can learn more about host risk {hostsRiskScoreDocumentationLink}"
defaultMessage="You can learn more about host risk {HostRiskScoreDocumentationLink}"
values={{
hostsRiskScoreDocumentationLink: (
HostRiskScoreDocumentationLink: (
<EuiLink href={RISKY_HOSTS_DOC_LINK} target="_blank">
<FormattedMessage
id="xpack.securitySolution.hosts.hostRiskInformation.link"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { HostRiskScoreColumns } from '.';
import * as i18n from './translations';
import { HostsTableType } from '../../store/model';
import type { RiskSeverity } from '../../../../common/search_strategy';
import { RiskScoreFields } from '../../../../common/search_strategy';
import { RiskScore } from '../../../common/components/severity/common';

export const getHostRiskScoreColumns = ({
Expand Down Expand Up @@ -67,7 +68,7 @@ export const getHostRiskScoreColumns = ({
},
},
{
field: 'risk_stats.risk_score',
field: RiskScoreFields.hostRiskScore,
name: i18n.HOST_RISK_SCORE,
truncateText: true,
mobileOptions: { show: true },
Expand All @@ -84,7 +85,7 @@ export const getHostRiskScoreColumns = ({
},
},
{
field: 'risk',
field: RiskScoreFields.hostRisk,
name: (
<EuiToolTip content={i18n.HOST_RISK_TOOLTIP}>
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
import { hostsActions, hostsModel, hostsSelectors } from '../../store';
import { getHostRiskScoreColumns } from './columns';
import type {
HostsRiskScore,
HostRiskScore,
RiskScoreItem,
RiskScoreSortField,
RiskSeverity,
Expand Down Expand Up @@ -50,7 +50,7 @@ const IconWrapper = styled.span`
const tableType = hostsModel.HostsTableType.risk;

interface HostRiskScoreTableProps {
data: HostsRiskScore[];
data: HostRiskScore[];
id: string;
isInspect: boolean;
loading: boolean;
Expand All @@ -63,8 +63,8 @@ interface HostRiskScoreTableProps {

export type HostRiskScoreColumns = [
Columns<RiskScoreItem[RiskScoreFields.hostName]>,
Columns<RiskScoreItem[RiskScoreFields.riskScore]>,
Columns<RiskScoreItem[RiskScoreFields.risk]>
Columns<RiskScoreItem[RiskScoreFields.hostRiskScore]>,
Columns<RiskScoreItem[RiskScoreFields.hostRisk]>
];

const HostRiskScoreTableComponent: React.FC<HostRiskScoreTableProps> = ({
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { SecuritySolutionPageWrapper } from '../../common/components/page_wrappe
import { useGlobalFullScreen } from '../../common/containers/use_full_screen';
import { useGlobalTime } from '../../common/containers/use_global_time';
import { TimelineId } from '../../../common/types/timeline';
import { LastEventIndexKey } from '../../../common/search_strategy';
import { LastEventIndexKey, RiskScoreEntity } from '../../../common/search_strategy';
import { useKibana } from '../../common/lib/kibana';
import { convertToBuildEsQuery } from '../../common/lib/keury';
import type { State } from '../../common/store';
Expand Down Expand Up @@ -103,7 +103,7 @@ const HostsComponent = () => {
}

if (tabName === HostsTableType.risk) {
const severityFilter = generateSeverityFilter(severitySelection);
const severityFilter = generateSeverityFilter(severitySelection, RiskScoreEntity.host);

return [...severityFilter, ...hostNameExistsFilter, ...filters];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';

import { last } from 'lodash/fp';
import type { HostsComponentsQueryProps } from './types';
import * as i18n from '../translations';
import { HostRiskInformationButtonEmpty } from '../../components/host_risk_information';
Expand Down Expand Up @@ -86,7 +87,7 @@ const HostRiskTabBodyComponent: React.FC<
[setOverTimeToggleStatus]
);

const rules = data && data.length > 0 ? data[data.length - 1].risk_stats.rule_risks : [];
const lastHostRiskItem = last(data);

return (
<>
Expand All @@ -110,7 +111,7 @@ const HostRiskTabBodyComponent: React.FC<
queryId={QUERY_ID}
toggleStatus={contributorsToggleStatus}
toggleQuery={toggleContributorsQuery}
rules={rules}
rules={lastHostRiskItem ? lastHostRiskItem.host.risk.rule_risks : []}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Loading

0 comments on commit 8ce4748

Please sign in to comment.