Skip to content

Commit

Permalink
A redesigned SIEM Overview page that includes Recent timelines, a `…
Browse files Browse the repository at this point in the history
…Security news` feed, visualizations, and rolled-up event counts

![overview-day](https://user-images.githubusercontent.com/4459398/72394573-f7c42080-36f3-11ea-93a1-57c52152cfdd.png)

![overview-night](https://user-images.githubusercontent.com/4459398/72394575-fb57a780-36f3-11ea-868e-8fcd2c5c4543.png)

- Added the global Search bar and Date picker to the Overview page
- New `Recent timelines` widget affords quick access to favorite and recently modified timelines
- New `Security news` widget
- New Kibana advanced settings (toggle switch) for enabling or disabling the news widget and configuring the news URL
![news-settings](https://user-images.githubusercontent.com/4459398/72362776-fd4c4700-36b0-11ea-805b-3c7353f2c1cd.png)
- New `Events count by dataset` widget
- Updated the `Host Events` and `Network Events` widgets to integrate with the Search bar and date picker input
- Enhanced the `Host Events` and `Network Events` widgets to use an accordion paradigm that summarizes stats by source (e.g. `Auditbeat`, `Endgame`)
- Enhanced the `Host Events` and `Network Events` widgets to visualize relative percentages of events collected as progress bars
- New `Alerts count by category` widget
- New `Signals count by MITRE ATT&CK™ category` widget
- New `View events`, `View alerts`, and `View signals` navigation buttons for their respective visualizations

- FTUE "no data" view design refresh
![ftue](https://user-images.githubusercontent.com/4459398/72361771-43a0a680-36af-11ea-969f-5872ac4a01a1.png)
- When the FTUE "no data" page is displayed, hide all global navigation links (i.e. `Hosts`, `Network`, `Detection engine`), such that only `Overview` appears in the global nav
- App Help popover design refresh
![help](https://user-images.githubusercontent.com/4459398/72362132-d80b0900-36af-11ea-9b58-1fd3b923b7c8.png)
- Removed the `Beta` badge and `Security Information & Event Management with the Elastic Stack` from the Overview header

- Tested in Chrome `79.0.3945.117`, Firefox `72.0.1`, and Safari `13.0.4`

- The `siem:newsFeedUrl` advanced setting is defaulted to `https://feeds.elastic.co/kibana`
- The `Signals count by MITRE ATT&CK™ category` visualization does not display all categories
- The `Signals count by MITRE ATT&CK™ category` visualization may require a different index pattern
- `EuiButtonGroup` throwing a `Can't perform a React state update on an unmounted component` warning when switching from the Overview tab

elastic/siem-team#484
  • Loading branch information
andrew-goldstein committed Jan 15, 2020
1 parent 6cac02e commit c36fd66
Show file tree
Hide file tree
Showing 74 changed files with 3,435 additions and 928 deletions.
2 changes: 2 additions & 0 deletions docs/management/advanced-options.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ might increase the search time. This setting is off by default. Users must opt-i
[horizontal]
`siem:defaultAnomalyScore`:: The threshold above which Machine Learning job anomalies are displayed in the SIEM app.
`siem:defaultIndex`:: A comma-delimited list of Elasticsearch indices from which the SIEM app collects events.
`siem:enableNewsFeed`:: Enables the News feed
`siem:newsFeedUrl`:: News feed content will be retrieved from this URL
`siem:refreshIntervalDefaults`:: The default refresh interval for the SIEM time filter, in milliseconds.
`siem:timeDefaults`:: The default period of time in the SIEM time filter.

Expand Down
10 changes: 8 additions & 2 deletions src/core/public/doc_links/doc_links_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,10 @@ export class DocLinksService {
introduction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index-patterns.html`,
},
kibana: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index.html`,
siem: `${ELASTIC_WEBSITE_URL}guide/en/siem/guide/${DOC_LINK_VERSION}/index.html`,
siem: {
guide: `${ELASTIC_WEBSITE_URL}guide/en/siem/guide/${DOC_LINK_VERSION}/index.html`,
gettingStarted: `${ELASTIC_WEBSITE_URL}guide/en/siem/guide/${DOC_LINK_VERSION}/install-siem.html`,
},
query: {
luceneQuerySyntax: `${ELASTICSEARCH_DOCS}query-dsl-query-string-query.html#query-string-syntax`,
queryDsl: `${ELASTICSEARCH_DOCS}query-dsl.html`,
Expand Down Expand Up @@ -199,7 +202,10 @@ export interface DocLinksStart {
readonly introduction: string;
};
readonly kibana: string;
readonly siem: string;
readonly siem: {
readonly guide: string;
readonly gettingStarted: string;
};
readonly query: {
readonly luceneQuerySyntax: string;
readonly queryDsl: string;
Expand Down
9 changes: 9 additions & 0 deletions x-pack/legacy/plugins/siem/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ export const DEFAULT_INTERVAL_TYPE = 'manual';
export const DEFAULT_INTERVAL_VALUE = 300000; // ms
export const DEFAULT_TIMEPICKER_QUICK_RANGES = 'timepicker:quickRanges';

/** This Kibana Advanced Setting enables the `Security news` feed widget */
export const ENABLE_NEWS_FEED_SETTING = 'siem:enableNewsFeed';

/** This Kibana Advanced Setting specifies the URL of the News feed widget */
export const NEWS_FEED_URL_SETTING = 'siem:newsFeedUrl';

/** The default value for News feed widget */
export const NEWS_FEED_URL_SETTING_DEFAULT = 'https://feeds.elastic.co/kibana'; // TODO: replace this with the real feed URL

/**
* Id for the signals alerting type
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,7 @@ export const NETWORK_STATS = [
STAT_FLOW,
STAT_TLS,
];

export const OVERVIEW_HOST_STATS = '[data-test-subj="overview-hosts-stats"]';

export const OVERVIEW_NETWORK_STATS = '[data-test-subj="overview-network-stats"]';
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@

import { OVERVIEW_PAGE } from '../../lib/urls';
import { clearFetch, stubApi } from '../../lib/fixtures/helpers';
import { HOST_STATS, NETWORK_STATS, STAT_AUDITD } from '../../lib/overview/selectors';
import {
HOST_STATS,
NETWORK_STATS,
OVERVIEW_HOST_STATS,
OVERVIEW_NETWORK_STATS,
STAT_AUDITD,
} from '../../lib/overview/selectors';
import { loginAndWaitForPage } from '../../lib/util/helpers';

describe('Overview Page', () => {
Expand All @@ -17,6 +23,14 @@ describe('Overview Page', () => {
});

it('Host and Network stats render with correct values', () => {
cy.get(OVERVIEW_HOST_STATS)
.find('button')
.invoke('click');

cy.get(OVERVIEW_NETWORK_STATS)
.find('button')
.invoke('click');

cy.get(STAT_AUDITD.domId);

HOST_STATS.forEach(stat => {
Expand Down
26 changes: 26 additions & 0 deletions x-pack/legacy/plugins/siem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import {
DEFAULT_FROM,
DEFAULT_TO,
DEFAULT_SIGNALS_INDEX,
ENABLE_NEWS_FEED_SETTING,
NEWS_FEED_URL_SETTING,
NEWS_FEED_URL_SETTING_DEFAULT,
SIGNALS_INDEX_KEY,
} from './common/constants';
import { defaultIndexPattern } from './default_index_pattern';
Expand Down Expand Up @@ -118,6 +121,29 @@ export const siem = (kibana: any) => {
category: ['siem'],
requiresPageReload: true,
},
[ENABLE_NEWS_FEED_SETTING]: {
name: i18n.translate('xpack.siem.uiSettings.enableNewsFeedLabel', {
defaultMessage: 'News feed',
}),
value: true,
description: i18n.translate('xpack.siem.uiSettings.enableNewsFeedDescription', {
defaultMessage: '<p>Enables the News feed</p>',
}),
type: 'boolean',
category: ['siem'],
requiresPageReload: true,
},
[NEWS_FEED_URL_SETTING]: {
name: i18n.translate('xpack.siem.uiSettings.newsFeedUrl', {
defaultMessage: 'News feed URL',
}),
value: NEWS_FEED_URL_SETTING_DEFAULT,
description: i18n.translate('xpack.siem.uiSettings.newsFeedUrlDescription', {
defaultMessage: '<p>News feed content will be retrieved from this URL</p>',
}),
category: ['siem'],
requiresPageReload: true,
},
},
mappings: savedObjectMappings,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import { MatrixHistogramOption } from '../matrix_histogram/types';
import { MatrixHistogramContainer } from '../../containers/matrix_histogram';
import { MatrixHistogramGqlQuery } from '../../containers/matrix_histogram/index.gql_query';
const ID = 'alertsOverTimeQuery';
const alertsStackByOptions: MatrixHistogramOption[] = [
export const alertsStackByOptions: MatrixHistogramOption[] = [
{
text: i18n.ALERTS_STACK_BY_MODULE,
text: i18n.CATEGORY,
value: 'event.category',
},
{
text: i18n.MODULE,
value: 'event.module',
},
];
Expand Down Expand Up @@ -51,7 +55,7 @@ export const AlertsView = ({
<MatrixHistogramContainer
dataKey={dataKey}
deleteQuery={deleteQuery}
defaultStackByOption={alertsStackByOptions[0]}
defaultStackByOption={alertsStackByOptions[1]}
endDate={endDate}
errorMessage={i18n.ERROR_FETCHING_ALERTS_DATA}
filterQuery={filterQuery}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,11 @@ export const ERROR_FETCHING_ALERTS_DATA = i18n.translate(
defaultMessage: 'Failed to query alerts data',
}
);

export const CATEGORY = i18n.translate('xpack.siem.alertsView.categoryLabel', {
defaultMessage: 'category',
});

export const MODULE = i18n.translate('xpack.siem.alertsView.moduleLabel', {
defaultMessage: 'module',
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const EmptyPage = React.memo<EmptyPageProps>(
...rest
}) => (
<EmptyPrompt
iconType="securityAnalyticsApp"
title={<h2>{title}</h2>}
body={message && <p>{message}</p>}
actions={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ export const SHOWING = i18n.translate('xpack.siem.eventsViewer.showingLabel', {
defaultMessage: 'Showing',
});

export const ERROR_FETCHING_EVENTS_DATA = i18n.translate(
'xpack.siem.eventsViewer.errorFetchingEventsData',
{
defaultMessage: 'Failed to query events data',
}
);

export const EVENTS = i18n.translate('xpack.siem.eventsViewer.eventsLabel', {
defaultMessage: 'Events',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,60 @@ import { FormattedRelative } from '@kbn/i18n/react';

import { useDateFormat, useTimeZone } from '../../hooks';
import { getOrEmptyTagFromValue } from '../empty_value';
import { useUiSetting$ } from '../../lib/kibana';
import { LocalizedDateTooltip } from '../localized_date_tooltip';
import { getMaybeDate } from './maybe_date';

export const PreferenceFormattedDate = React.memo<{ value: Date }>(({ value }) => {
const dateFormat = useDateFormat();
const timeZone = useTimeZone();
export const PreferenceFormattedDate = React.memo<{ dateFormat?: string; value: Date }>(
({ value, dateFormat = useDateFormat() }) => (
<>{moment.tz(value, useTimeZone()).format(dateFormat)}</>
)
);

PreferenceFormattedDate.displayName = 'PreferenceFormattedDate';

return <>{moment.tz(value, timeZone).format(dateFormat)}</>;
/**
* This function may be passed to `Array.find()` to locate the `P1DT`
* configuration (sub) setting, a string array that contains two entries
* like the following example: `['P1DT', 'YYYY-MM-DD']`.
*/
export const isP1DTFormatterSetting = (formatNameFormatterPair?: string[]) =>
Array.isArray(formatNameFormatterPair) &&
formatNameFormatterPair[0] === 'P1DT' &&
formatNameFormatterPair.length === 2;

/**
* Renders a date in `P1DT` format, e.g. `YYYY-MM-DD`, as specified by
* the `P1DT1` entry in the `dateFormat:scaled` Kibana Advanced setting.
*
* If the `P1DT` format is not specified in the `dateFormat:scaled` setting,
* the fallback format `YYYY-MM-DD` will be applied
*/
export const PreferenceFormattedP1DTDate = React.memo<{ value: Date }>(({ value }) => {
/**
* A fallback "format name / formatter" 2-tuple for the `P1DT` formatter, which is
* one of many such pairs expected to be contained in the `dateFormat:scaled`
* Kibana advanced setting.
*/
const FALLBACK_DATE_FORMAT_SCALED_P1DT = ['P1DT', 'YYYY-MM-DD'];

// Read the 'dateFormat:scaled' Kibana Advanced setting, which contains 2-tuple sub-settings:
const [scaledDateFormatPreference] = useUiSetting$<string[][]>('dateFormat:scaled');

// attempt to find the nested `['P1DT', 'formatString']` setting
const maybeP1DTFormatter = Array.isArray(scaledDateFormatPreference)
? scaledDateFormatPreference.find(isP1DTFormatterSetting)
: null;

const p1dtFormat =
Array.isArray(maybeP1DTFormatter) && maybeP1DTFormatter.length === 2
? maybeP1DTFormatter[1]
: FALLBACK_DATE_FORMAT_SCALED_P1DT[1];

return <PreferenceFormattedDate dateFormat={p1dtFormat} value={value} />;
});

PreferenceFormattedDate.displayName = 'PreferenceFormattedDate';
PreferenceFormattedP1DTDate.displayName = 'PreferenceFormattedP1DTDate';

/**
* Renders the specified date value in a format determined by the user's preferences,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getOverviewUrl } from '../link_to';
import { MlPopover } from '../ml_popover/ml_popover';
import { SiemNavigation } from '../navigation';
import * as i18n from './translations';
import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';

const Wrapper = styled.header`
${({ theme }) => css`
Expand Down Expand Up @@ -47,14 +48,25 @@ export const HeaderGlobal = React.memo<HeaderGlobalProps>(({ hideDetectionEngine
</FlexItem>

<FlexItem component="nav">
<SiemNavigation
display="condensed"
navTabs={
hideDetectionEngine
? pickBy((value, key) => key !== SiemPageName.detectionEngine, navTabs)
: navTabs
<WithSource sourceId="default">
{({ indicesExist }) =>
indicesExistOrDataTemporarilyUnavailable(indicesExist) ? (
<SiemNavigation
display="condensed"
navTabs={
hideDetectionEngine
? pickBy((_, key) => key !== SiemPageName.detectionEngine, navTabs)
: navTabs
}
/>
) : (
<SiemNavigation
display="condensed"
navTabs={pickBy((_, key) => key === SiemPageName.overview, navTabs)}
/>
)
}
/>
</WithSource>
</FlexItem>
</EuiFlexGroup>
</FlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React, { useEffect } from 'react';
import chrome from 'ui/chrome';
import { i18n } from '@kbn/i18n';
import { documentationLinks } from 'ui/documentation_links';

export const HelpMenu = React.memo(() => {
useEffect(() => {
Expand All @@ -15,6 +16,14 @@ export const HelpMenu = React.memo(() => {
defaultMessage: 'SIEM',
}),
links: [
{
content: i18n.translate('xpack.siem.chrome.helpMenu.documentation', {
defaultMessage: 'SIEM documentation',
}),
href: documentationLinks.siem.guide,
iconType: 'documents',
linkType: 'custom',
},
{
linkType: 'discuss',
href: 'https://discuss.elastic.co/c/siem',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export {
RedirectToDetectionEnginePage,
} from './redirect_to_detection_engine';
export { getOverviewUrl, RedirectToOverviewPage } from './redirect_to_overview';
export { getHostsUrl, getHostDetailsUrl } from './redirect_to_hosts';
export { getHostDetailsUrl, getHostsUrl } from './redirect_to_hosts';
export { getNetworkUrl, getIPDetailsUrl, RedirectToNetworkPage } from './redirect_to_network';
export { getTimelinesUrl, RedirectToTimelinesPage } from './redirect_to_timelines';
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ export const LinkToPage = React.memo<LinkToPageProps>(({ match }) => (
/>
<Route
component={RedirectToHostsPage}
path={`${match.url}/:pageName(${SiemPageName.hosts})/:tabName(${HostsTableType.hosts}|${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events})`}
path={`${match.url}/:pageName(${SiemPageName.hosts})/:tabName(${HostsTableType.hosts}|${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events}|${HostsTableType.alerts})`}
/>
<Route
component={RedirectToHostDetailsPage}
path={`${match.url}/:pageName(${SiemPageName.hosts})/:detailName/:tabName(${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events})`}
path={`${match.url}/:pageName(${SiemPageName.hosts})/:detailName/:tabName(${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events}|${HostsTableType.alerts})`}
/>
<Route
component={RedirectToHostDetailsPage}
Expand Down
Loading

0 comments on commit c36fd66

Please sign in to comment.