Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .buildkite/ftr_platform_stateful_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ enabled:
- x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/config.ts
- x-pack/test/functional_with_es_ssl/apps/embeddable_alerts_table/config.ts
- x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/config.ts
- x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/config.ts
- x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts
- x-pack/test/functional/apps/advanced_settings/config.ts
- x-pack/test/functional/apps/aiops/config.ts
Expand Down
8 changes: 8 additions & 0 deletions docs/settings/alert-action-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ A list of allowed email domains which can be used with the email connector. When
+
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 setting 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.

[[actions-config-email-services-ses-host]] `xpack.actions.email.services.ses.host` {ess-icon}::
The SMTP endpoint for an Amazon Simple Email Service (SES) service provider that can be used by email connectors.
+
WARNING: This setting alone is insufficient for overriding system defaults for the SES SMTP endpoint. You must also configure the `xpack.actions.email.services.ses.port` setting.

[[actions-config-email-services-ses-port]] `xpack.actions.email.services.ses.port` {ess-icon}::
The port number for an Amazon Simple Email Service (SES) service provider that can be used by email connectors.

`xpack.actions.enableFooterInEmail` {ess-icon}::
A boolean value indicating that a footer with a relevant link should be added to emails sent as alerting actions. Default: true.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ kibana_vars=(
xpack.actions.allowedHosts
xpack.actions.customHostSettings
xpack.actions.email.domain_allowlist
xpack.actions.email.services.ses.host
xpack.actions.email.services.ses.port
xpack.actions.enableFooterInEmail
xpack.actions.enabledActionTypes
xpack.actions.maxResponseContentLength
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'vis_type_vislib.readOnly (boolean?|never)',
'vis_type_xy.readOnly (boolean?|never)',
'vis_type_vega.enableExternalUrls (boolean?)',
'xpack.actions.email.domain_allowlist (array)',
'xpack.actions.email.domain_allowlist (array?)',
'xpack.apm.serviceMapEnabled (boolean?)',
'xpack.apm.ui.enabled (boolean?)',
'xpack.apm.ui.maxTraceItems (number?)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const createActionsConfigMock = () => {
getMaxAttempts: jest.fn().mockReturnValue(3),
enableFooterInEmail: jest.fn().mockReturnValue(true),
getMaxQueued: jest.fn().mockReturnValue(1000),
getAwsSesConfig: jest.fn().mockReturnValue(null),
};
return mocked;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,34 @@ describe('getMaxQueued()', () => {
expect(max).toEqual(1000000);
});
});

describe('getAwsSesConfig()', () => {
test('returns null when no email config set', () => {
const acu = getActionsConfigurationUtilities(defaultActionsConfig);
expect(acu.getAwsSesConfig()).toEqual(null);
});

test('returns null when no email.services config set', () => {
const acu = getActionsConfigurationUtilities({ ...defaultActionsConfig, email: {} });
expect(acu.getAwsSesConfig()).toEqual(null);
});

test('returns config if set', () => {
const acu = getActionsConfigurationUtilities({
...defaultActionsConfig,
email: {
services: {
ses: {
host: 'https://email.us-east-1.amazonaws.com',
port: 1234,
},
},
},
});
expect(acu.getAwsSesConfig()).toEqual({
host: 'https://email.us-east-1.amazonaws.com',
port: 1234,
secure: true,
});
});
});
16 changes: 14 additions & 2 deletions x-pack/platform/plugins/shared/actions/server/actions_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type { ActionsConfig, CustomHostSettings } from './config';
import { AllowedHosts, EnabledActionTypes, DEFAULT_QUEUED_MAX } from './config';
import { getCanonicalCustomHostUrl } from './lib/custom_host_settings';
import { ActionTypeDisabledError } from './lib';
import type { ProxySettings, ResponseSettings, SSLSettings } from './types';
import type { AwsSesConfig, ProxySettings, ResponseSettings, SSLSettings } from './types';
import { getSSLSettingsFromConfig } from './lib/get_node_ssl_options';
import type { ValidateEmailAddressesOptions } from '../common';
import { validateEmailAddresses, invalidEmailsAsMessage } from '../common';
Expand Down Expand Up @@ -55,6 +55,7 @@ export interface ActionsConfigurationUtilities {
): string | undefined;
enableFooterInEmail: () => boolean;
getMaxQueued: () => number;
getAwsSesConfig: () => AwsSesConfig;
}

function allowListErrorMessage(field: AllowListingField, value: string) {
Expand Down Expand Up @@ -171,7 +172,7 @@ function validateEmails(
addresses: string[],
options: ValidateEmailAddressesOptions
): string | undefined {
if (config.email == null) {
if (config.email?.domain_allowlist == null) {
return;
}

Expand Down Expand Up @@ -229,5 +230,16 @@ export function getActionsConfigurationUtilities(
},
enableFooterInEmail: () => config.enableFooterInEmail,
getMaxQueued: () => config.queued?.max || DEFAULT_QUEUED_MAX,
getAwsSesConfig: () => {
if (config.email?.services?.ses.host && config.email?.services?.ses.port) {
return {
host: config.email?.services?.ses.host,
port: config.email?.services?.ses.port,
secure: true,
};
}

return null;
},
};
}
50 changes: 49 additions & 1 deletion x-pack/platform/plugins/shared/actions/server/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ describe('config validation', () => {

config.email = {};
expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(
`"[email.domain_allowlist]: expected value of type [array] but got [undefined]"`
`"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"`
);

config.email = { domain_allowlist: [] };
Expand All @@ -257,6 +257,54 @@ describe('config validation', () => {
result = configSchema.validate(config);
expect(result.email?.domain_allowlist).toEqual(['a.com', 'b.c.com', 'd.e.f.com']);
});

describe('email.services.ses', () => {
const config: Record<string, unknown> = {};
test('validates no email config at all', () => {
expect(configSchema.validate(config).email).toBe(undefined);
});

test('validates empty email config', () => {
config.email = {};
expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(
`"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"`
);
});

test('validates email config with empty services', () => {
config.email = { services: {} };
expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(
`"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"`
);
});

test('validates email config with empty ses service', () => {
config.email = { services: { ses: {} } };
expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(
`"[email]: Email configuration requires either domain_allowlist or services.ses to be specified"`
);
});

test('validates ses config with host only', () => {
config.email = { services: { ses: { host: 'ses.host.com' } } };
expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(
`"[email]: Email configuration requires both services.ses.host and services.ses.port to be specified"`
);
});

test('validates ses config with port only', () => {
config.email = { services: { ses: { port: 1 } } };
expect(() => configSchema.validate(config)).toThrowErrorMatchingInlineSnapshot(
`"[email]: Email configuration requires both services.ses.host and services.ses.port to be specified"`
);
});

test('validates ses service', () => {
config.email = { services: { ses: { host: 'ses.host.com', port: 1 } } };
const result = configSchema.validate(config);
expect(result.email?.services?.ses).toEqual({ host: 'ses.host.com', port: 1 });
});
});
});

// object creator that ensures we can create a property named __proto__ on an
Expand Down
27 changes: 24 additions & 3 deletions x-pack/platform/plugins/shared/actions/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,30 @@ export const configSchema = schema.object({
microsoftGraphApiScope: schema.string({ defaultValue: DEFAULT_MICROSOFT_GRAPH_API_SCOPE }),
microsoftExchangeUrl: schema.string({ defaultValue: DEFAULT_MICROSOFT_EXCHANGE_URL }),
email: schema.maybe(
schema.object({
domain_allowlist: schema.arrayOf(schema.string()),
})
schema.object(
{
domain_allowlist: schema.maybe(schema.arrayOf(schema.string())),
services: schema.maybe(
schema.object({
ses: schema.object({
host: schema.maybe(schema.string({ minLength: 1 })),
port: schema.maybe(schema.number({ min: 1, max: 65535 })),
}),
})
),
},
{
validate: (obj) => {
if (!obj.domain_allowlist && !obj.services?.ses.host && !obj.services?.ses.port) {
return 'Email configuration requires either domain_allowlist or services.ses to be specified';
}

if (obj.services?.ses && (!obj.services.ses.host || !obj.services.ses.port)) {
return 'Email configuration requires both services.ses.host and services.ses.port to be specified';
}
},
}
)
),
run: schema.maybe(
schema.object({
Expand Down
4 changes: 3 additions & 1 deletion x-pack/platform/plugins/shared/actions/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ const createSetupMock = () => {
getSubActionConnectorClass: jest.fn(),
getCaseConnectorClass: jest.fn(),
getActionsHealth: jest.fn(),
getActionsConfigurationUtilities: jest.fn(),
getActionsConfigurationUtilities: jest.fn().mockReturnValue({
getAwsSesConfig: jest.fn(),
}),
setEnabledConnectorTypes: jest.fn(),
isActionTypeEnabled: jest.fn(),
};
Expand Down
6 changes: 6 additions & 0 deletions x-pack/platform/plugins/shared/actions/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,9 @@ export interface ConnectorToken extends SavedObjectAttributes {
// This unallowlist should only contain connector types that require a request or API key for
// execution.
export const UNALLOWED_FOR_UNSECURE_EXECUTION_CONNECTOR_TYPE_IDS = ['.index'];

export type AwsSesConfig = {
host: string;
port: number;
secure: boolean;
} | null;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export enum AdditionalEmailServices {
ELASTIC_CLOUD = 'elastic_cloud',
EXCHANGE = 'exchange_server',
OTHER = 'other',
AWS_SES = 'ses',
}

export const INTERNAL_BASE_STACK_CONNECTORS_API_PATH = '/internal/stack_connectors';
Expand Down
10 changes: 0 additions & 10 deletions x-pack/platform/plugins/shared/stack_connectors/common/types.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public';
import type { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public';
import type { ActionsPublicPluginSetup } from '@kbn/actions-plugin/public';
import type { ConfigSchema as StackConnectorsConfigType } from '../server/config';
import { registerConnectorTypes } from './connector_types';
import { ExperimentalFeaturesService } from './common/experimental_features_service';
import type { ExperimentalFeatures } from '../common/experimental_features';
import { parseExperimentalConfigValue } from '../common/experimental_features';
import type { StackConnectorsConfigType } from '../common/types';

export type Setup = void;
export type Start = void;
Expand Down
Loading