Skip to content

Commit

Permalink
[Security Solution][Artifacts] implemented policy specific trusted ap…
Browse files Browse the repository at this point in the history
…ps support in the manifest manager (#90991)

* Implemented policy specific trusted apps support in the manifest manager.
  • Loading branch information
efreeti authored Feb 16, 2021
1 parent 312351c commit e81b5c1
Show file tree
Hide file tree
Showing 17 changed files with 1,084 additions and 635 deletions.
7 changes: 7 additions & 0 deletions x-pack/plugins/fleet/common/types/rest_spec/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@ export interface ListWithKuery extends HttpFetchQuery {
sortOrder?: 'desc' | 'asc';
kuery?: string;
}

export interface ListResult<T> {
items: T[];
total: number;
page: number;
perPage: number;
}
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const createPackagePolicyServiceMock = () => {
get: jest.fn(),
getByIDs: jest.fn(),
list: jest.fn(),
listIds: jest.fn(),
update: jest.fn(),
runExternalCallbacks: jest.fn(),
} as jest.Mocked<PackagePolicyServiceInterface>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jest.mock('../../services/package_policy', (): {
get: jest.fn(),
getByIDs: jest.fn(),
list: jest.fn(),
listIds: jest.fn(),
update: jest.fn(),
runExternalCallbacks: jest.fn((callbackType, newPackagePolicy, context, request) =>
Promise.resolve(newPackagePolicy)
Expand Down
27 changes: 26 additions & 1 deletion x-pack/plugins/fleet/server/services/package_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
PackagePolicyInputStream,
PackageInfo,
ListWithKuery,
ListResult,
packageToPackagePolicy,
isPackageLimited,
doesAgentPolicyAlreadyIncludePackage,
Expand Down Expand Up @@ -248,7 +249,7 @@ class PackagePolicyService {
public async list(
soClient: SavedObjectsClientContract,
options: ListWithKuery
): Promise<{ items: PackagePolicy[]; total: number; page: number; perPage: number }> {
): Promise<ListResult<PackagePolicy>> {
const { page = 1, perPage = 20, sortField = 'updated_at', sortOrder = 'desc', kuery } = options;

const packagePolicies = await soClient.find<PackagePolicySOAttributes>({
Expand All @@ -272,6 +273,30 @@ class PackagePolicyService {
};
}

public async listIds(
soClient: SavedObjectsClientContract,
options: ListWithKuery
): Promise<ListResult<string>> {
const { page = 1, perPage = 20, sortField = 'updated_at', sortOrder = 'desc', kuery } = options;

const packagePolicies = await soClient.find<{}>({
type: SAVED_OBJECT_TYPE,
sortField,
sortOrder,
page,
perPage,
fields: [],
filter: kuery ? normalizeKuery(SAVED_OBJECT_TYPE, kuery) : undefined,
});

return {
items: packagePolicies.saved_objects.map((packagePolicySO) => packagePolicySO.id),
total: packagePolicies.total,
page,
perPage,
};
}

public async update(
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/lists/common/shared_exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ export {
OsTypeArray,
} from './schemas';

export { ENDPOINT_LIST_ID } from './constants';
export { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from './constants';
249 changes: 174 additions & 75 deletions x-pack/plugins/lists/server/saved_objects/migrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,102 @@
*/

import { SavedObjectUnsanitizedDoc } from 'kibana/server';
import uuid from 'uuid';

import { ENDPOINT_LIST_ID } from '../../common/constants';
import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../common/constants';
import { ExceptionListSoSchema } from '../../common/schemas/saved_objects';

import { OldExceptionListSoSchema, migrations } from './migrations';

const DEFAULT_EXCEPTION_LIST_SO: ExceptionListSoSchema = {
comments: undefined,
created_at: '2020-06-09T20:18:20.349Z',
created_by: 'user',
description: 'description',
entries: undefined,
immutable: false,
item_id: undefined,
list_id: 'some_list',
list_type: 'list',
meta: undefined,
name: 'name',
os_types: [],
tags: [],
tie_breaker_id: uuid.v4(),
type: 'endpoint',
updated_by: 'user',
version: undefined,
};

const DEFAULT_OLD_EXCEPTION_LIST_SO: OldExceptionListSoSchema = {
...DEFAULT_EXCEPTION_LIST_SO,
_tags: [],
};

const createOldExceptionListSoSchemaSavedObject = (
attributes: Partial<OldExceptionListSoSchema>
): SavedObjectUnsanitizedDoc<OldExceptionListSoSchema> => ({
attributes: { ...DEFAULT_OLD_EXCEPTION_LIST_SO, ...attributes },
id: 'abcd',
migrationVersion: {},
references: [],
type: 'so-type',
updated_at: '2020-06-09T20:18:20.349Z',
});

const createExceptionListSoSchemaSavedObject = (
attributes: Partial<ExceptionListSoSchema>
): SavedObjectUnsanitizedDoc<ExceptionListSoSchema> => ({
attributes: { ...DEFAULT_EXCEPTION_LIST_SO, ...attributes },
id: 'abcd',
migrationVersion: {},
references: [],
type: 'so-type',
updated_at: '2020-06-09T20:18:20.349Z',
});

describe('7.10.0 lists migrations', () => {
const migration = migrations['7.10.0'];

test('properly converts .text fields to .caseless', () => {
const doc = {
attributes: {
entries: [
{
field: 'file.path.text',
operator: 'included',
type: 'match',
value: 'C:\\Windows\\explorer.exe',
},
{
field: 'host.os.name',
operator: 'included',
type: 'match',
value: 'my-host',
},
{
entries: [
{
field: 'process.command_line.text',
operator: 'included',
type: 'match',
value: '/usr/bin/bash',
},
{
field: 'process.parent.command_line.text',
operator: 'included',
type: 'match',
value: '/usr/bin/bash',
},
],
field: 'nested.field',
type: 'nested',
},
],
list_id: ENDPOINT_LIST_ID,
},
id: 'abcd',
migrationVersion: {},
references: [],
type: 'so-type',
updated_at: '2020-06-09T20:18:20.349Z',
};
expect(
migration((doc as unknown) as SavedObjectUnsanitizedDoc<OldExceptionListSoSchema>)
).toEqual({
attributes: {
const doc = createOldExceptionListSoSchemaSavedObject({
entries: [
{
field: 'file.path.text',
operator: 'included',
type: 'match',
value: 'C:\\Windows\\explorer.exe',
},
{
field: 'host.os.name',
operator: 'included',
type: 'match',
value: 'my-host',
},
{
entries: [
{
field: 'process.command_line.text',
operator: 'included',
type: 'match',
value: '/usr/bin/bash',
},
{
field: 'process.parent.command_line.text',
operator: 'included',
type: 'match',
value: '/usr/bin/bash',
},
],
field: 'nested.field',
type: 'nested',
},
],
list_id: ENDPOINT_LIST_ID,
});

expect(migration(doc)).toEqual(
createOldExceptionListSoSchemaSavedObject({
entries: [
{
field: 'file.path.caseless',
Expand Down Expand Up @@ -94,40 +135,98 @@ describe('7.10.0 lists migrations', () => {
},
],
list_id: ENDPOINT_LIST_ID,
},
id: 'abcd',
migrationVersion: {},
references: [],
type: 'so-type',
updated_at: '2020-06-09T20:18:20.349Z',
});
})
);
});

test('properly copies os tags to os_types', () => {
const doc = {
attributes: {
_tags: ['1234', 'os:windows'],
comments: [],
},
id: 'abcd',
migrationVersion: {},
references: [],
type: 'so-type',
updated_at: '2020-06-09T20:18:20.349Z',
};
expect(
migration((doc as unknown) as SavedObjectUnsanitizedDoc<OldExceptionListSoSchema>)
).toEqual({
attributes: {
const doc = createOldExceptionListSoSchemaSavedObject({
_tags: ['1234', 'os:windows'],
comments: [],
});

expect(migration(doc)).toEqual(
createOldExceptionListSoSchemaSavedObject({
_tags: ['1234', 'os:windows'],
comments: [],
os_types: ['windows'],
},
id: 'abcd',
migrationVersion: {},
references: [],
type: 'so-type',
updated_at: '2020-06-09T20:18:20.349Z',
})
);
});
});

describe('7.12.0 lists migrations', () => {
const migration = migrations['7.12.0'];

test('should not convert non trusted apps lists', () => {
const doc = createExceptionListSoSchemaSavedObject({ list_id: ENDPOINT_LIST_ID, tags: [] });

expect(migration(doc)).toEqual(
createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_LIST_ID,
tags: [],
tie_breaker_id: expect.anything(),
})
);
});

test('converts empty tags to contain list containing "policy:all" tag', () => {
const doc = createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: [],
});

expect(migration(doc)).toEqual(
createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['policy:all'],
tie_breaker_id: expect.anything(),
})
);
});

test('preserves existing non policy related tags', () => {
const doc = createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['tag1', 'tag2'],
});

expect(migration(doc)).toEqual(
createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['tag1', 'tag2', 'policy:all'],
tie_breaker_id: expect.anything(),
})
);
});

test('preserves existing "policy:all" tag and does not add another one', () => {
const doc = createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['policy:all', 'tag1', 'tag2'],
});

expect(migration(doc)).toEqual(
createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['policy:all', 'tag1', 'tag2'],
tie_breaker_id: expect.anything(),
})
);
});

test('preserves existing policy reference tag and does not add "policy:all" tag', () => {
const doc = createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['policy:056d2d4645421fb92e5cd39f33d70856', 'tag1', 'tag2'],
});

expect(migration(doc)).toEqual(
createExceptionListSoSchemaSavedObject({
list_id: ENDPOINT_TRUSTED_APPS_LIST_ID,
tags: ['policy:056d2d4645421fb92e5cd39f33d70856', 'tag1', 'tag2'],
tie_breaker_id: expect.anything(),
})
);
});
});
24 changes: 24 additions & 0 deletions x-pack/plugins/lists/server/saved_objects/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ const reduceOsTypes = (acc: string[], tag: string): string[] => {
return [...acc];
};

const containsPolicyTags = (tags: string[]): boolean =>
tags.some((tag) => tag.startsWith('policy:'));

export type OldExceptionListSoSchema = ExceptionListSoSchema & {
_tags: string[];
};
Expand All @@ -64,4 +67,25 @@ export const migrations = {
},
references: doc.references || [],
}),
'7.12.0': (
doc: SavedObjectUnsanitizedDoc<ExceptionListSoSchema>
): SavedObjectSanitizedDoc<ExceptionListSoSchema> => {
if (doc.attributes.list_id === ENDPOINT_TRUSTED_APPS_LIST_ID) {
return {
...doc,
...{
attributes: {
...doc.attributes,
tags: [
...(doc.attributes.tags || []),
...(containsPolicyTags(doc.attributes.tags) ? [] : ['policy:all']),
],
},
},
references: doc.references || [],
};
} else {
return { ...doc, references: doc.references || [] };
}
},
};
Loading

0 comments on commit e81b5c1

Please sign in to comment.