Skip to content

Commit

Permalink
D3 Security Sub Actions Connector (#158569)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic committed Jun 5, 2023
1 parent 6638184 commit f5e79f7
Show file tree
Hide file tree
Showing 36 changed files with 1,570 additions and 2 deletions.
4 changes: 4 additions & 0 deletions docs/management/action-types.asciidoc
Expand Up @@ -83,6 +83,10 @@ a| <<gen-ai-action-type,Generative AI>>

| Send a request to OpenAI.

a| <<d3security-action-type,D3 Security>>

| Send a request to D3 Security.

|===

[NOTE]
Expand Down
91 changes: 91 additions & 0 deletions docs/management/connectors/action-types/d3security.asciidoc
@@ -0,0 +1,91 @@
[[d3security-action-type]]
== D3 Security connector and action
++++
<titleabbrev>D3 Security</titleabbrev>
++++

The D3 Security connector uses https://github.com/axios/axios[axios] to send a POST request to a D3 Security endpoint. The connector uses the <<execute-connector-api,run connector API>> to send the request. You can use the connector for rule actions.

[float]
[[d3security-connector-prerequisites]]
=== Prerequisites

To use a D3 Security connector, you must first configure a webhook key in your D3 SOAR environment. To generate an API URL and a token in D3 Security:
1. Log in to your D3 SOAR environment.
2. Navigate to Configuration.
3. Navigate to Integration > Search for “Kibana”. Click “Fetch Event”.
4. Select the "Enable Webhook" checkbox.
5. Click Set up Webhook Keys.
6. Under Event Ingestion, Click +. Select the site for the webhook integration, then click Generate.
7. Copy the Request URL and Request Header Value to configure the Kibana connector

[float]
[[define-d3security-ui]]
=== Create connectors in {kib}

You can create connectors in *{stack-manage-app} > {connectors-ui}*. For example:

[role="screenshot"]
image::management/connectors/images/d3security-connector.png[D3 Security connector]

[float]
[[d3security-connector-configuration]]
==== Connector configuration

D3 Security connectors have the following configuration properties:

Name:: The name of the connector.
URL:: The D3 Security API request URL.
Token:: The D3 Security token

[float]
[[preconfigured-d3security-configuration]]
=== Create preconfigured connectors

If you are running {kib} on-prem, you can define connectors by
adding `xpack.actions.preconfigured` settings to your `kibana.yml` file.
For example:

[source,text]
--
xpack.actions.preconfigured:
my-d3security:
name: preconfigured-d3security-connector-type
actionTypeId: .d3security
config:
url: https://testurl.com/elasticsearch/VSOC/api/Data/Kibana/Security%20Operations/CreateEvents
secrets:
token: superlongtoken
--

Config defines information for the connector type.

`url`:: A URL string that corresponds to the *D3 Security API URL*.

Secrets defines sensitive information for the connector type.

`token`:: A string that corresponds to *D3 Security API Token*.

[float]
[[d3security-action-configuration]]
=== Test connectors

You can test connectors with the <<execute-connector-api,run connector API>> or
as you're creating or editing the connector in {kib}. For example:

[role="screenshot"]
image::management/connectors/images/d3security-params-test.png[D3 Security params test]

The D3 Security actions have the following configuration properties.

Body:: A typeless payload sent to the D3 Security API URL. For example:
+
[source,text]
--
this can be any type, it is not validated
--
[float]
[[d3security-connector-networking-configuration]]
=== Connector networking configuration

Use the <<action-settings, Action configuration settings>> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/management/connectors/index.asciidoc
Expand Up @@ -17,4 +17,5 @@ include::action-types/webhook.asciidoc[leveloffset=+1]
include::action-types/cases-webhook.asciidoc[leveloffset=+1]
include::action-types/xmatters.asciidoc[leveloffset=+1]
include::action-types/gen-ai.asciidoc[leveloffset=+1]
include::action-types/d3security.asciidoc[leveloffset=+1]
include::pre-configured-connectors.asciidoc[leveloffset=+1]
2 changes: 1 addition & 1 deletion docs/settings/alert-action-settings.asciidoc
Expand Up @@ -138,7 +138,7 @@ WARNING: This feature is available in {kib} 7.17.4 and 8.3.0 onwards but is not
A boolean value indicating that a footer with a relevant link should be added to emails sent as alerting actions. Default: true.

`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`, `.opsgenie`, `.pagerduty`, `.resilient`, `.server-log`, `.servicenow`, .`servicenow-itom`, `.servicenow-sir`, `.slack`, `.swimlane`, `.teams`, `.tines`, `.torq`, `.xmatters`, `.gen-ai`, and `.webhook`. An empty list `[]` will disable all action types.
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`, `.opsgenie`, `.pagerduty`, `.resilient`, `.server-log`, `.servicenow`, .`servicenow-itom`, `.servicenow-sir`, `.slack`, `.swimlane`, `.teams`, `.tines`, `.torq`, `.xmatters`, `.gen-ai`, `.d3security`, and `.webhook`. An empty list `[]` will disable all action types.
+
Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function.

Expand Down
26 changes: 26 additions & 0 deletions x-pack/plugins/stack_connectors/common/d3security/constants.ts
@@ -0,0 +1,26 @@
/*
* 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 { i18n } from '@kbn/i18n';

export const D3_SECURITY_TITLE = i18n.translate(
'xpack.stackConnectors.components.d3Security.connectorTypeTitle',
{
defaultMessage: 'D3 Security',
}
);
export const D3_SECURITY_CONNECTOR_ID = '.d3security';
export enum SUB_ACTION {
RUN = 'run',
TEST = 'test',
}
export enum D3SecuritySeverity {
EMPTY = '',
HIGH = 'high',
MEDIUM = 'medium',
LOW = 'low',
}
30 changes: 30 additions & 0 deletions x-pack/plugins/stack_connectors/common/d3security/schema.ts
@@ -0,0 +1,30 @@
/*
* 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 { schema } from '@kbn/config-schema';
import { D3SecuritySeverity } from './constants';

// Connector schema
export const D3SecurityConfigSchema = schema.object({
url: schema.string(),
});

export const D3SecuritySecretsSchema = schema.object({ token: schema.string() });

// Run action schema
export const D3SecurityRunActionParamsSchema = schema.object({
body: schema.maybe(schema.string()),
severity: schema.maybe(schema.string({ defaultValue: D3SecuritySeverity.EMPTY })),
eventType: schema.maybe(schema.string({ defaultValue: '' })),
});

export const D3SecurityRunActionResponseSchema = schema.object(
{
refid: schema.string(),
},
{ unknowns: 'ignore' }
);
19 changes: 19 additions & 0 deletions x-pack/plugins/stack_connectors/common/d3security/types.ts
@@ -0,0 +1,19 @@
/*
* 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 { TypeOf } from '@kbn/config-schema';
import {
D3SecurityConfigSchema,
D3SecuritySecretsSchema,
D3SecurityRunActionParamsSchema,
D3SecurityRunActionResponseSchema,
} from './schema';

export type D3SecurityConfig = TypeOf<typeof D3SecurityConfigSchema>;
export type D3SecuritySecrets = TypeOf<typeof D3SecuritySecretsSchema>;
export type D3SecurityRunActionParams = TypeOf<typeof D3SecurityRunActionParamsSchema>;
export type D3SecurityRunActionResponse = TypeOf<typeof D3SecurityRunActionResponseSchema>;
@@ -0,0 +1,138 @@
/*
* 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 React from 'react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import D3SecurityConnectorFields from './connector';
import { ConnectorFormTestProvider } from '../lib/test_utils';
import { act, render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana');

describe('D3ActionConnectorFields renders', () => {
test('D3Security connector fields are rendered', () => {
const actionConnector = {
actionTypeId: '.d3security',
name: 'd3security',
config: {
url: 'https://test.com',
},
secrets: {
Token: 'token',
},
isDeprecated: false,
};

const wrapper = mountWithIntl(
<ConnectorFormTestProvider connector={actionConnector}>
<D3SecurityConnectorFields
readOnly={false}
isEdit={false}
registerPreSubmitValidator={() => {}}
/>
</ConnectorFormTestProvider>
);

expect(wrapper.find('[data-test-subj="config.url-input"]').length > 0).toBeTruthy();
expect(wrapper.find('[data-test-subj="secrets.token-input"]').length > 0).toBeTruthy();
});

describe('Validation', () => {
const onSubmit = jest.fn();

beforeEach(() => {
jest.clearAllMocks();
});

const tests: Array<[string, string]> = [
['config.url-input', 'not-valid'],
['secrets.token-input', ''],
];

it('connector validation succeeds when connector config is valid', async () => {
const actionConnector = {
actionTypeId: '.d3security',
name: 'd3security',
config: {
url: 'https://test.com',
},
secrets: {
token: 'token',
},
isDeprecated: false,
};

const { getByTestId } = render(
<ConnectorFormTestProvider connector={actionConnector} onSubmit={onSubmit}>
<D3SecurityConnectorFields
readOnly={false}
isEdit={false}
registerPreSubmitValidator={() => {}}
/>
</ConnectorFormTestProvider>
);

await act(async () => {
userEvent.click(getByTestId('form-test-provide-submit'));
});

waitFor(() => {
expect(onSubmit).toBeCalledWith({
data: {
actionTypeId: '.d3security',
name: 'd3security',
config: {
url: 'https://test.com',
},
secrets: {
token: 'token',
},
isDeprecated: false,
},
isValid: true,
});
});
});

it.each(tests)('validates correctly %p', async (field, value) => {
const actionConnector = {
actionTypeId: '.d3security',
name: 'd3security',
config: {
url: 'https://test.com',
},
secrets: {
token: 'token',
},
isDeprecated: false,
};

const res = render(
<ConnectorFormTestProvider connector={actionConnector} onSubmit={onSubmit}>
<D3SecurityConnectorFields
readOnly={false}
isEdit={false}
registerPreSubmitValidator={() => {}}
/>
</ConnectorFormTestProvider>
);

await act(async () => {
await userEvent.type(res.getByTestId(field), `{selectall}{backspace}${value}`, {
delay: 10,
});
});

await act(async () => {
userEvent.click(res.getByTestId('form-test-provide-submit'));
});

expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false });
});
});
});
@@ -0,0 +1,39 @@
/*
* 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 React from 'react';
import { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import {
ConfigFieldSchema,
SimpleConnectorForm,
SecretsFieldSchema,
} from '@kbn/triggers-actions-ui-plugin/public';
import * as i18n from './translations';

const configFormSchema: ConfigFieldSchema[] = [
{ id: 'url', label: i18n.D3_URL_LABEL, isUrlField: true },
];

const secretsFormSchema: SecretsFieldSchema[] = [
{ id: 'token', label: i18n.D3_TOKEN_LABEL, isPasswordField: true },
];

const D3SecurityConnectorFields: React.FC<ActionConnectorFieldsProps> = ({ readOnly, isEdit }) => {
return (
<>
<SimpleConnectorForm
isEdit={isEdit}
readOnly={readOnly}
configFormSchema={configFormSchema}
secretsFormSchema={secretsFormSchema}
/>
</>
);
};

// eslint-disable-next-line import/no-default-export
export { D3SecurityConnectorFields as default };

0 comments on commit f5e79f7

Please sign in to comment.