Skip to content

Commit

Permalink
Merge branch '7.x' into backport/7.x/pr-72215
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine authored Jul 17, 2020
2 parents 6a2bc92 + 1bd3477 commit 0189486
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 15 deletions.
2 changes: 1 addition & 1 deletion docs/maps/connect-to-ems.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Maps makes requests directly from the browser to EMS.
To connect to EMS when your Kibana server and browser are in an internal network:

. Set `map.proxyElasticMapsServiceInMaps` to `true` in your <<settings, kibana.yml>> file to proxy EMS requests through the Kibana server.
. Update your firewall rules to whitelist connections from your Kibana server to the EMS domains.
. Update your firewall rules to allow connections from your Kibana server to the EMS domains.

NOTE: Coordinate map and region map visualizations do not support `map.proxyElasticMapsServiceInMaps` and will not proxy EMS requests through the Kibana server.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,18 +204,20 @@ export class ExplorerSwimlane extends React.Component<ExplorerSwimlaneProps> {
});

this.renderSwimlane();

this.dragSelect.stop();
}

componentDidUpdate() {
this.renderSwimlane();
}

componentWillUnmount() {
if (this.dragSelectSubscriber !== null) {
this.dragSelectSubscriber.unsubscribe();
}
const element = d3.select(this.rootNode.current!);
element.html('');
this.dragSelectSubscriber!.unsubscribe();
// Remove selector element from DOM
this.dragSelect.selector.remove();
// removes all mousedown event handlers
this.dragSelect.stop(true);
}

selectCell(cellsToSelect: any[], { laneLabels, bucketScore, times }: SelectedData) {
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/monitoring/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"kibanaLegacy",
"triggers_actions_ui",
"alerts",
"actions"
"actions",
"encryptedSavedObjects"
],
"optionalPlugins": ["infra", "telemetryCollectionManager", "usageCollection", "home", "cloud"],
"server": true,
Expand Down
137 changes: 137 additions & 0 deletions x-pack/plugins/monitoring/public/alerts/lib/security_toasts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSpacer, EuiLink, EuiCode, EuiText } from '@elastic/eui';
import { Legacy } from '../../legacy_shims';
import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public';

export interface AlertingFrameworkHealth {
isSufficientlySecure: boolean;
hasPermanentEncryptionKey: boolean;
}

const showTlsAndEncryptionError = () => {
const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks;

Legacy.shims.toastNotifications.addWarning({
title: toMountPoint(
<FormattedMessage
id="xpack.monitoring.healthCheck.tlsAndEncryptionErrorTitle"
defaultMessage="Additional setup required"
/>
),
text: toMountPoint(
<div>
<p>
{i18n.translate('xpack.monitoring.healthCheck.tlsAndEncryptionError', {
defaultMessage: `You must enable Transport Layer Security between Kibana and Elasticsearch
and configure an encryption key in your kibana.yml file to use the Alerting feature.`,
})}
</p>
<EuiSpacer />
<EuiLink
href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-action-settings-kb.html#general-alert-action-settings`}
external
target="_blank"
>
{i18n.translate('xpack.monitoring.healthCheck.encryptionErrorAction', {
defaultMessage: 'Learn how.',
})}
</EuiLink>
</div>
),
});
};

const showEncryptionError = () => {
const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks;

Legacy.shims.toastNotifications.addWarning(
{
title: toMountPoint(
<FormattedMessage
id="xpack.monitoring.healthCheck.encryptionErrorTitle"
defaultMessage="You must set an encryption key"
/>
),
text: toMountPoint(
<div role="banner">
{i18n.translate('xpack.monitoring.healthCheck.encryptionErrorBeforeKey', {
defaultMessage: 'To create an alert, set a value for ',
})}
<EuiText size="xs">
<EuiCode>{'xpack.encryptedSavedObjects.encryptionKey'}</EuiCode>
</EuiText>
{i18n.translate('xpack.monitoring.healthCheck.encryptionErrorAfterKey', {
defaultMessage: ' in your kibana.yml file. ',
})}
<EuiLink
href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/alert-action-settings-kb.html#general-alert-action-settings`}
external
target="_blank"
>
{i18n.translate('xpack.monitoring.healthCheck.encryptionErrorAction', {
defaultMessage: 'Learn how.',
})}
</EuiLink>
</div>
),
},
{}
);
};

const showTlsError = () => {
const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks;

Legacy.shims.toastNotifications.addWarning({
title: toMountPoint(
<FormattedMessage
id="xpack.monitoring.healthCheck.tlsErrorTitle"
defaultMessage="You must enable Transport Layer Security"
/>
),
text: toMountPoint(
<div role="banner">
{i18n.translate('xpack.monitoring.healthCheck.tlsError', {
defaultMessage:
'Alerting relies on API keys, which require TLS between Elasticsearch and Kibana. ',
})}
<EuiLink
href={`${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/configuring-tls.html`}
external
target="_blank"
>
{i18n.translate('xpack.monitoring.healthCheck.tlsErrorAction', {
defaultMessage: 'Learn how to enable TLS.',
})}
</EuiLink>
</div>
),
});
};

export const showSecurityToast = (alertingHealth: AlertingFrameworkHealth) => {
const { isSufficientlySecure, hasPermanentEncryptionKey } = alertingHealth;
if (
Array.isArray(alertingHealth) ||
(!alertingHealth.hasOwnProperty('isSufficientlySecure') &&
!alertingHealth.hasOwnProperty('hasPermanentEncryptionKey'))
) {
return;
}

if (!isSufficientlySecure && !hasPermanentEncryptionKey) {
showTlsAndEncryptionError();
} else if (!isSufficientlySecure) {
showTlsError();
} else if (!hasPermanentEncryptionKey) {
showEncryptionError();
}
};
4 changes: 3 additions & 1 deletion x-pack/plugins/monitoring/public/services/clusters.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { ajaxErrorHandlersProvider } from '../lib/ajax_error_handler';
import { Legacy } from '../legacy_shims';
import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../common/constants';
import { showSecurityToast } from '../alerts/lib/security_toasts';

function formatClusters(clusters) {
return clusters.map(formatCluster);
Expand Down Expand Up @@ -66,7 +67,8 @@ export function monitoringClustersProvider($injector) {
return getClusters().then((clusters) => {
if (clusters.length) {
return ensureAlertsEnabled()
.then(() => {
.then(({ data }) => {
showSecurityToast(data);
once = true;
return clusters;
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { RequestHandlerContext } from 'kibana/server';
import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server';

export interface AlertingFrameworkHealth {
isSufficientlySecure: boolean;
hasPermanentEncryptionKey: boolean;
}

export interface XPackUsageSecurity {
security?: {
enabled?: boolean;
ssl?: {
http?: {
enabled?: boolean;
};
};
};
}

export class AlertingSecurity {
public static readonly getSecurityHealth = async (
context: RequestHandlerContext,
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup
): Promise<AlertingFrameworkHealth> => {
const {
security: {
enabled: isSecurityEnabled = false,
ssl: { http: { enabled: isTLSEnabled = false } = {} } = {},
} = {},
}: XPackUsageSecurity = await context.core.elasticsearch.legacy.client.callAsInternalUser(
'transport.request',
{
method: 'GET',
path: '/_xpack/usage',
}
);

return {
isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled),
hasPermanentEncryptionKey: !encryptedSavedObjects.usingEphemeralEncryptionKey,
};
};
}
1 change: 1 addition & 0 deletions x-pack/plugins/monitoring/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export class Plugin {
requireUIRoutes(this.monitoringCore, {
router,
licenseService: this.licenseService,
encryptedSavedObjects: plugins.encryptedSavedObjects,
});
initInfraSource(config, plugins.infra);
}
Expand Down
25 changes: 21 additions & 4 deletions x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,36 @@ import { AlertsFactory } from '../../../../alerts';
import { RouteDependencies } from '../../../../types';
import { ALERT_ACTION_TYPE_LOG } from '../../../../../common/constants';
import { ActionResult } from '../../../../../../actions/common';
// import { fetchDefaultEmailAddress } from '../../../../lib/alerts/fetch_default_email_address';
import { AlertingSecurity } from '../../../../lib/elasticsearch/verify_alerting_security';

const DEFAULT_SERVER_LOG_NAME = 'Monitoring: Write to Kibana log';

export function enableAlertsRoute(server: any, npRoute: RouteDependencies) {
export function enableAlertsRoute(_server: unknown, npRoute: RouteDependencies) {
npRoute.router.post(
{
path: '/api/monitoring/v1/alerts/enable',
validate: false,
},
async (context, request, response) => {
async (context, _request, response) => {
try {
const alerts = AlertsFactory.getAll().filter((a) => a.isEnabled(npRoute.licenseService));

if (alerts.length) {
const {
isSufficientlySecure,
hasPermanentEncryptionKey,
} = await AlertingSecurity.getSecurityHealth(context, npRoute.encryptedSavedObjects);

if (!isSufficientlySecure || !hasPermanentEncryptionKey) {
return response.ok({
body: {
isSufficientlySecure,
hasPermanentEncryptionKey,
},
});
}
}

const alertsClient = context.alerting?.getAlertsClient();
const actionsClient = context.actions?.getActionsClient();
const types = context.actions?.listTypes();
Expand Down Expand Up @@ -57,7 +75,6 @@ export function enableAlertsRoute(server: any, npRoute: RouteDependencies) {
},
];

const alerts = AlertsFactory.getAll().filter((a) => a.isEnabled(npRoute.licenseService));
const createdAlerts = await Promise.all(
alerts.map(
async (alert) => await alert.createIfDoesNotExist(alertsClient, actionsClient, actions)
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/monitoring/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { InfraPluginSetup } from '../../infra/server';
import { LicensingPluginSetup } from '../../licensing/server';
import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server';
import { EncryptedSavedObjectsPluginSetup } from '../../encrypted_saved_objects/server';

export interface MonitoringLicenseService {
refresh: () => Promise<any>;
Expand All @@ -36,6 +37,7 @@ export interface LegacyAPI {
}

export interface PluginsSetup {
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
telemetryCollectionManager?: TelemetryCollectionManagerPluginSetup;
usageCollection?: UsageCollectionSetup;
licensing: LicensingPluginSetup;
Expand All @@ -56,6 +58,7 @@ export interface MonitoringCoreConfig {
export interface RouteDependencies {
router: IRouter;
licenseService: MonitoringLicenseService;
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
}

export interface MonitoringCore {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const ReadonlySettings: React.FunctionComponent<Props> = ({
case 'ftp':
return (
<FormattedMessage
id="xpack.snapshotRestore.repositoryForm.typeReadonly.urlWhitelistDescription"
id="xpack.snapshotRestore.repositoryForm.typeReadonly.urlAllowedDescription"
defaultMessage="This URL must be registered in the {settingKey} setting."
values={{
settingKey: <EuiCode>repositories.url.allowed_urls</EuiCode>,
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -13551,7 +13551,6 @@
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlLabel": "パス (必須)",
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlSchemeLabel": "スキーム",
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlTitle": "URL",
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlWhitelistDescription": "この URL は {settingKey} 設定で登録する必要があります。",
"xpack.snapshotRestore.repositoryForm.typeS3.basePathDescription": "レポジトリデータへのバケットパスです。",
"xpack.snapshotRestore.repositoryForm.typeS3.basePathLabel": "ベースパス",
"xpack.snapshotRestore.repositoryForm.typeS3.basePathTitle": "ベースパス",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -13556,7 +13556,6 @@
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlLabel": "路径(必填)",
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlSchemeLabel": "方案",
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlTitle": "URL",
"xpack.snapshotRestore.repositoryForm.typeReadonly.urlWhitelistDescription": "必须在 {settingKey} 设置中注册此 URL。",
"xpack.snapshotRestore.repositoryForm.typeS3.basePathDescription": "存储库数据的存储桶路径。",
"xpack.snapshotRestore.repositoryForm.typeS3.basePathLabel": "基路径",
"xpack.snapshotRestore.repositoryForm.typeS3.basePathTitle": "基路径",
Expand Down

0 comments on commit 0189486

Please sign in to comment.