Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECS audit events for alerting #84113

Merged
merged 19 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
51a784a
ECS audit events for alerts plugin
thomheymann Nov 16, 2020
3652cf0
added api changes
thomheymann Nov 24, 2020
ac215a0
fixed linting and testing errors
thomheymann Nov 24, 2020
7abc2b0
Merge remote-tracking branch 'origin/master' into alerting/audit-logging
thomheymann Nov 24, 2020
6c3cb47
fix test
thomheymann Nov 24, 2020
5f10ab5
Merge remote-tracking branch 'origin/master' into alerting/audit-logging
thomheymann Nov 24, 2020
4e3d1a1
Merge remote-tracking branch 'origin/master' into alerting/audit-logging
thomheymann Nov 25, 2020
337a902
Fixed linting errors after prettier update
thomheymann Nov 25, 2020
5f598d1
Revert "Allow predefined ids for encrypted saved objects (#83482)"
thomheymann Nov 25, 2020
a2dd90f
Added suggestions from code review
thomheymann Nov 27, 2020
c9082be
Merge remote-tracking branch 'origin/master' into alerting/audit-logging
thomheymann Nov 30, 2020
d11ffc2
Fixed unit tests
thomheymann Nov 30, 2020
6e473a9
Added suggestions from code review
thomheymann Nov 30, 2020
fa5215a
Merge remote-tracking branch 'origin/master' into alerting/audit-logging
thomheymann Dec 1, 2020
9014744
Changed names of alert events
thomheymann Dec 1, 2020
2873fe7
Changed naming as suggested in code review
thomheymann Dec 2, 2020
5b91bb8
Merge branch 'master' into alerting/audit-logging
kibanamachine Dec 3, 2020
459e0c4
Added suggestions from PR
thomheymann Dec 4, 2020
0ff3dfe
Merge remote-tracking branch 'origin/master' into alerting/audit-logging
thomheymann Dec 4, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Given a saved object type and id, generates the compound id that is stored in th
<b>Signature:</b>

```typescript
generateRawId(namespace: string | undefined, type: string, id?: string): string;
generateRawId(namespace: string | undefined, type: string, id: string): string;
```

## Parameters
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsUtils](./kibana-plugin-core-server.savedobjectsutils.md) &gt; [generateId](./kibana-plugin-core-server.savedobjectsutils.generateid.md)

## SavedObjectsUtils.generateId() method

Generates a random ID for a saved objects.

<b>Signature:</b>

```typescript
static generateId(): string;
```
<b>Returns:</b>

`string`

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsUtils](./kibana-plugin-core-server.savedobjectsutils.md) &gt; [isRandomId](./kibana-plugin-core-server.savedobjectsutils.israndomid.md)

## SavedObjectsUtils.isRandomId() method

Validates that a saved object ID matches UUID format.

<b>Signature:</b>

```typescript
static isRandomId(id: string | undefined): boolean;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| id | <code>string &#124; undefined</code> | |

<b>Returns:</b>

`boolean`

Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ export declare class SavedObjectsUtils
| [namespaceIdToString](./kibana-plugin-core-server.savedobjectsutils.namespaceidtostring.md) | <code>static</code> | <code>(namespace?: string &#124; undefined) =&gt; string</code> | Converts a given saved object namespace ID to its string representation. All namespace IDs have an identical string representation, with the exception of the <code>undefined</code> namespace ID (which has a namespace string of <code>'default'</code>). |
| [namespaceStringToId](./kibana-plugin-core-server.savedobjectsutils.namespacestringtoid.md) | <code>static</code> | <code>(namespace: string) =&gt; string &#124; undefined</code> | Converts a given saved object namespace string to its ID representation. All namespace strings have an identical ID representation, with the exception of the <code>'default'</code> namespace string (which has a namespace ID of <code>undefined</code>). |

## Methods

| Method | Modifiers | Description |
| --- | --- | --- |
| [generateId()](./kibana-plugin-core-server.savedobjectsutils.generateid.md) | <code>static</code> | Generates a random ID for a saved objects. |
| [isRandomId(id)](./kibana-plugin-core-server.savedobjectsutils.israndomid.md) | <code>static</code> | Validates that a saved object ID matches UUID format. |

68 changes: 68 additions & 0 deletions docs/user/security/audit-logging.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ Refer to the corresponding {es} logs for potential write errors.
| `unknown` | User is creating a saved object.
| `failure` | User is not authorized to create a saved object.

.2+| `connector_create`
| `unknown` | User is creating a connector.
| `failure` | User is not authorized to create a connector.

.2+| `alert_create`
| `unknown` | User is creating an alert rule.
| `failure` | User is not authorized to create an alert rule.


3+a|
====== Type: change
Expand All @@ -108,6 +116,42 @@ Refer to the corresponding {es} logs for potential write errors.
| `unknown` | User is removing references to a saved object.
| `failure` | User is not authorized to remove references to a saved object.

.2+| `connector_update`
| `unknown` | User is updating a connector.
| `failure` | User is not authorized to update a connector.

.2+| `alert_update`
| `unknown` | User is updating an alert rule.
| `failure` | User is not authorized to update an alert rule.

.2+| `alert_update_api_key`
| `unknown` | User is updating the API key of an alert rule.
| `failure` | User is not authorized to update the API key of an alert rule.

.2+| `alert_enable`
| `unknown` | User is enabling an alert rule.
| `failure` | User is not authorized to enable an alert rule.

.2+| `alert_disable`
| `unknown` | User is disabling an alert rule.
| `failure` | User is not authorized to disable an alert rule.

.2+| `alert_mute`
| `unknown` | User is muting an alert rule.
| `failure` | User is not authorized to mute an alert rule.

.2+| `alert_unmute`
| `unknown` | User is unmuting an alert rule.
| `failure` | User is not authorized to unmute an alert rule.

.2+| `alert_instance_mute`
| `unknown` | User is muting an alert instance.
| `failure` | User is not authorized to mute an alert instance.

.2+| `alert_instance_unmute`
| `unknown` | User is unmuting an alert instance.
| `failure` | User is not authorized to unmute an alert instance.


3+a|
====== Type: deletion
Expand All @@ -120,6 +164,14 @@ Refer to the corresponding {es} logs for potential write errors.
| `unknown` | User is deleting a saved object.
| `failure` | User is not authorized to delete a saved object.

.2+| `connector_delete`
| `unknown` | User is deleting a connector.
| `failure` | User is not authorized to delete a connector.

.2+| `alert_delete`
| `unknown` | User is deleting an alert rule.
| `failure` | User is not authorized to delete an alert rule.

3+a|
====== Type: access

Expand All @@ -135,6 +187,22 @@ Refer to the corresponding {es} logs for potential write errors.
| `success` | User has accessed a saved object as part of a search operation.
| `failure` | User is not authorized to search for saved objects.

.2+| `connector_get`
| `success` | User has accessed a connector.
| `failure` | User is not authorized to access a connector.

.2+| `connector_find`
| `success` | User has accessed a connector as part of a search operation.
| `failure` | User is not authorized to search for connectors.

.2+| `alert_get`
| `success` | User has accessed an alert rule.
| `failure` | User is not authorized to access an alert rule.

.2+| `alert_find`
| `success` | User has accessed an alert rule as part of a search operation.
| `failure` | User is not authorized to search for alert rules.


3+a|
===== Category: web
Expand Down
133 changes: 1 addition & 132 deletions src/core/server/saved_objects/serialization/serializer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,24 +573,10 @@ describe('#savedObjectToRaw', () => {
});

describe('single-namespace type without a namespace', () => {
test('generates an id prefixed with type, if no id is specified', () => {
const v1 = singleNamespaceSerializer.savedObjectToRaw({
type: 'foo',
attributes: { bar: true },
} as any);

const v2 = singleNamespaceSerializer.savedObjectToRaw({
type: 'foo',
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`doesn't specify _source.namespace`, () => {
const actual = singleNamespaceSerializer.savedObjectToRaw({
type: '',
id: 'mock-saved-object-id',
attributes: {},
} as any);

Expand All @@ -599,23 +585,6 @@ describe('#savedObjectToRaw', () => {
});

describe('single-namespace type with a namespace', () => {
test('generates an id prefixed with namespace and type, if no id is specified', () => {
const v1 = singleNamespaceSerializer.savedObjectToRaw({
type: 'foo',
namespace: 'bar',
attributes: { bar: true },
} as any);

const v2 = singleNamespaceSerializer.savedObjectToRaw({
type: 'foo',
namespace: 'bar',
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^bar\:foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`it copies namespace to _source.namespace`, () => {
const actual = singleNamespaceSerializer.savedObjectToRaw({
type: 'foo',
Expand All @@ -628,23 +597,6 @@ describe('#savedObjectToRaw', () => {
});

describe('single-namespace type with namespaces', () => {
test('generates an id prefixed with type, if no id is specified', () => {
const v1 = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
namespaces: ['bar'],
attributes: { bar: true },
} as any);

const v2 = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
namespaces: ['bar'],
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`doesn't specify _source.namespaces`, () => {
const actual = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
Expand All @@ -657,23 +609,6 @@ describe('#savedObjectToRaw', () => {
});

describe('namespace-agnostic type with a namespace', () => {
test('generates an id prefixed with type, if no id is specified', () => {
const v1 = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
namespace: 'bar',
attributes: { bar: true },
} as any);

const v2 = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
namespace: 'bar',
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`doesn't specify _source.namespace`, () => {
const actual = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
Expand All @@ -686,23 +621,6 @@ describe('#savedObjectToRaw', () => {
});

describe('namespace-agnostic type with namespaces', () => {
test('generates an id prefixed with type, if no id is specified', () => {
const v1 = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
namespaces: ['bar'],
attributes: { bar: true },
} as any);

const v2 = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
namespaces: ['bar'],
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`doesn't specify _source.namespaces`, () => {
const actual = namespaceAgnosticSerializer.savedObjectToRaw({
type: 'foo',
Expand All @@ -715,23 +633,6 @@ describe('#savedObjectToRaw', () => {
});

describe('multi-namespace type with a namespace', () => {
test('generates an id prefixed with type, if no id is specified', () => {
const v1 = multiNamespaceSerializer.savedObjectToRaw({
type: 'foo',
namespace: 'bar',
attributes: { bar: true },
} as any);

const v2 = multiNamespaceSerializer.savedObjectToRaw({
type: 'foo',
namespace: 'bar',
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`doesn't specify _source.namespace`, () => {
const actual = multiNamespaceSerializer.savedObjectToRaw({
type: 'foo',
Expand All @@ -744,23 +645,6 @@ describe('#savedObjectToRaw', () => {
});

describe('multi-namespace type with namespaces', () => {
test('generates an id prefixed with type, if no id is specified', () => {
const v1 = multiNamespaceSerializer.savedObjectToRaw({
type: 'foo',
namespaces: ['bar'],
attributes: { bar: true },
} as any);

const v2 = multiNamespaceSerializer.savedObjectToRaw({
type: 'foo',
namespaces: ['bar'],
attributes: { bar: true },
} as any);

expect(v1._id).toMatch(/^foo\:[\w-]+$/);
expect(v1._id).not.toEqual(v2._id);
});

test(`it copies namespaces to _source.namespaces`, () => {
const actual = multiNamespaceSerializer.savedObjectToRaw({
type: 'foo',
Expand Down Expand Up @@ -1064,35 +948,20 @@ describe('#isRawSavedObject', () => {

describe('#generateRawId', () => {
describe('single-namespace type without a namespace', () => {
test('generates an id if none is specified', () => {
const id = singleNamespaceSerializer.generateRawId('', 'goodbye');
expect(id).toMatch(/^goodbye\:[\w-]+$/);
});

test('uses the id that is specified', () => {
const id = singleNamespaceSerializer.generateRawId('', 'hello', 'world');
expect(id).toEqual('hello:world');
});
});

describe('single-namespace type with a namespace', () => {
test('generates an id if none is specified and prefixes namespace', () => {
const id = singleNamespaceSerializer.generateRawId('foo', 'goodbye');
expect(id).toMatch(/^foo:goodbye\:[\w-]+$/);
});

test('uses the id that is specified and prefixes the namespace', () => {
const id = singleNamespaceSerializer.generateRawId('foo', 'hello', 'world');
expect(id).toEqual('foo:hello:world');
});
});

describe('namespace-agnostic type with a namespace', () => {
test(`generates an id if none is specified and doesn't prefix namespace`, () => {
const id = namespaceAgnosticSerializer.generateRawId('foo', 'goodbye');
expect(id).toMatch(/^goodbye\:[\w-]+$/);
});

test(`uses the id that is specified and doesn't prefix the namespace`, () => {
const id = namespaceAgnosticSerializer.generateRawId('foo', 'hello', 'world');
expect(id).toEqual('hello:world');
Expand Down
5 changes: 2 additions & 3 deletions src/core/server/saved_objects/serialization/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* under the License.
*/

import uuid from 'uuid';
import { decodeVersion, encodeVersion } from '../version';
import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry';
import { SavedObjectsRawDoc, SavedObjectSanitizedDoc } from './types';
Expand Down Expand Up @@ -127,10 +126,10 @@ export class SavedObjectsSerializer {
* @param {string} type - The saved object type
* @param {string} id - The id of the saved object
*/
public generateRawId(namespace: string | undefined, type: string, id?: string) {
public generateRawId(namespace: string | undefined, type: string, id: string) {
const namespacePrefix =
namespace && this.registry.isSingleNamespace(type) ? `${namespace}:` : '';
return `${namespacePrefix}${type}:${id || uuid.v1()}`;
return `${namespacePrefix}${type}:${id}`;
}

private trimIdPrefix(namespace: string | undefined, type: string, id: string) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/saved_objects/serialization/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export interface SavedObjectsRawDocSource {
*/
interface SavedObjectDoc<T = unknown> {
attributes: T;
id?: string; // NOTE: SavedObjectDoc is used for uncreated objects where `id` is optional
id: string;
type: string;
namespace?: string;
namespaces?: string[];
Expand Down
Loading