Skip to content

Commit

Permalink
[ResponseOps][actions] add config for allow-listing email address dom…
Browse files Browse the repository at this point in the history
…ains (elastic#129001)

resolves elastic#126944

Adds a new configuration setting for the actions plugin,
xpack.actions.email.domain_allowlist, which is an array of domain name
strings which are allowed to be sent emails by the email connector.
  • Loading branch information
pmuellr authored Apr 26, 2022
1 parent dad4963 commit 6ad418b
Show file tree
Hide file tree
Showing 58 changed files with 1,299 additions and 427 deletions.
2 changes: 2 additions & 0 deletions docs/management/connectors/action-types/email.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ The email connector uses the SMTP protocol to send mail messages, using an integ

NOTE: For emails to have a footer with a link back to {kib}, set the <<server-publicBaseUrl, `server.publicBaseUrl`>> configuration setting.

NOTE: When the <<action-config-email-domain-allowlist, `xpack.actions.email.domain_allowlist`>> configuration setting is used, the email addresses used for all of the Sender (from), To, CC, and BCC properties must have email domains specified in the configuration setting.

[float]
[[email-connector-configuration]]
==== Connector configuration
Expand Down
5 changes: 5 additions & 0 deletions docs/settings/alert-action-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ The contents of a PEM-encoded certificate file, or multiple files appended
into a single string. This configuration can be used for environments where
the files cannot be made available.

[[action-config-email-domain-allowlist]] `xpack.actions.email.domain_allowlist` {ess-icon}::
A list of allowed email domains which can be used with the email connector. When this setting is not used, all email domains are allowed. When this setting is used, if any email is attempted to be sent that includes an addressee with an email domain that is not in the allowlist, or the from address domain is not in the allowlist, the run of the connector will fail with a message indicating the emails not allowed.

WARNING: This feature is available in {kib} 7.17.4 and 8.3.0 onwards but is not supported in {kib} 8.0, 8.1 or 8.2. As such this settings should be removed before upgrading from 7.17 to 8.0, 8.1 or 8.2. It is possible to configure the settings in 7.17.4 and then upgrade to 8.3.0 directly.

`xpack.actions.enabledActionTypes` {ess-icon}::
A list of action types that are enabled. It defaults to `[*]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.email`, `.index`, `.jira`, `.pagerduty`, `.resilient`, `.server-log`, `.servicenow`, .`servicenow-itom`, `.servicenow-sir`, `.slack`, `.swimlane`, `.teams`, `.xmatters`, and `.webhook`. An empty list `[]` will disable all action types.
+
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
"deepmerge": "^4.2.2",
"del": "^5.1.0",
"elastic-apm-node": "^3.31.0",
"email-addresses": "^5.0.0",
"execa": "^4.0.2",
"exit-hook": "^2.2.0",
"expiry-js": "0.1.7",
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pageLoadAssetSize:
advancedSettings: 27596
actions: 20000
alerting: 106936
apm: 64385
canvas: 1066647
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ kibana_vars=(
vis_type_vega.enableExternalUrls
xpack.actions.allowedHosts
xpack.actions.customHostSettings
xpack.actions.email.domain_allowlist
xpack.actions.enabledActionTypes
xpack.actions.maxResponseContentLength
xpack.actions.preconfigured
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'usageCollection.uiCounters.debug (boolean)',
'usageCollection.uiCounters.enabled (boolean)',
'vis_type_vega.enableExternalUrls (boolean)',
'xpack.actions.email.domain_allowlist (array)',
'xpack.apm.profilingEnabled (boolean)',
'xpack.apm.serviceMapEnabled (boolean)',
'xpack.apm.ui.enabled (boolean)',
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/actions/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
export * from './types';
export * from './alert_history_schema';
export * from './rewrite_request_case';
export * from './mustache_template';
export * from './validate_email_addresses';
export * from './servicenow_config';

export const BASE_ACTION_API_PATH = '/api/actions';
export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions';
Expand Down
33 changes: 33 additions & 0 deletions x-pack/plugins/actions/common/mustache_template.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { hasMustacheTemplate, withoutMustacheTemplate } from './mustache_template';

const nonMustacheEmails = ['', '[email protected]', '}}{{'];
const mustacheEmails = ['{{}}', '"bob" {{}}@elastic.co', 'sneaky{{\n}}pete'];

describe('mustache_template', () => {
it('hasMustacheTemplate', () => {
for (const email of nonMustacheEmails) {
expect(hasMustacheTemplate(email)).toBe(false);
}
for (const email of mustacheEmails) {
expect(hasMustacheTemplate(email)).toBe(true);
}
});

it('withoutMustacheTemplate', () => {
let result = withoutMustacheTemplate(nonMustacheEmails);
expect(result).toEqual(nonMustacheEmails);

result = withoutMustacheTemplate(mustacheEmails);
expect(result).toEqual([]);

result = withoutMustacheTemplate(mustacheEmails.concat(nonMustacheEmails));
expect(result).toEqual(nonMustacheEmails);
});
});
18 changes: 18 additions & 0 deletions x-pack/plugins/actions/common/mustache_template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const MustacheInEmailRegExp = /\{\{((.|\n)*)\}\}/;

/** does the string contain `{{.*}}`? */
export function hasMustacheTemplate(string: string): boolean {
return !!string.match(MustacheInEmailRegExp);
}

/** filter strings that do not contain `{{.*}}` */
export function withoutMustacheTemplate(strings: string[]): string[] {
return strings.filter((string) => !hasMustacheTemplate(string));
}
56 changes: 56 additions & 0 deletions x-pack/plugins/actions/common/servicenow_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const serviceNowITSMTable = 'incident';
export const serviceNowSIRTable = 'sn_si_incident';

export const ServiceNowITSMActionTypeId = '.servicenow';
export const ServiceNowSIRActionTypeId = '.servicenow-sir';
export const ServiceNowITOMActionTypeId = '.servicenow-itom';

const SN_ITSM_APP_ID = '7148dbc91bf1f450ced060a7234bcb88';
const SN_SIR_APP_ID = '2f0746801baeb01019ae54e4604bcb0f';

export interface SNProductsConfigValue {
table: string;
appScope: string;
useImportAPI: boolean;
importSetTable: string;
commentFieldKey: string;
appId?: string;
}

export type SNProductsConfig = Record<string, SNProductsConfigValue>;

export const snExternalServiceConfig: SNProductsConfig = {
'.servicenow': {
importSetTable: 'x_elas2_inc_int_elastic_incident',
appScope: 'x_elas2_inc_int',
table: 'incident',
useImportAPI: true,
commentFieldKey: 'work_notes',
appId: SN_ITSM_APP_ID,
},
'.servicenow-sir': {
importSetTable: 'x_elas2_sir_int_elastic_si_incident',
appScope: 'x_elas2_sir_int',
table: 'sn_si_incident',
useImportAPI: true,
commentFieldKey: 'work_notes',
appId: SN_SIR_APP_ID,
},
'.servicenow-itom': {
importSetTable: 'x_elas2_inc_int_elastic_incident',
appScope: 'x_elas2_inc_int',
table: 'em_event',
useImportAPI: false,
commentFieldKey: 'work_notes',
},
};

export const FIELD_PREFIX = 'u_';
export const DEFAULT_ALERTS_GROUPING_KEY = '{{rule.id}}:{{alert.id}}';
15 changes: 15 additions & 0 deletions x-pack/plugins/actions/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ export interface ActionType {
minimumLicenseRequired: LicenseType;
}

export enum InvalidEmailReason {
invalid = 'invalid',
notAllowed = 'notAllowed',
}

export interface ValidatedEmail {
address: string;
valid: boolean;
reason?: InvalidEmailReason;
}

export interface ActionResult {
id: string;
actionTypeId: string;
Expand Down Expand Up @@ -49,3 +60,7 @@ export function isActionTypeExecutorResult(
ActionTypeExecutorResultStatusValues.includes(unsafeResult?.status)
);
}

export interface ActionsPublicConfigType {
allowedEmailDomains: string[];
}
Loading

0 comments on commit 6ad418b

Please sign in to comment.