Skip to content

Commit

Permalink
[Security Solution] Generate host isolation exceptions artifact (#115160
Browse files Browse the repository at this point in the history
) (#115512)

Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Esteban Beltran <[email protected]>
  • Loading branch information
kibanamachine and academo authored Oct 19, 2021
1 parent 4317d06 commit de80e69
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export const ArtifactConstants = {

SUPPORTED_EVENT_FILTERS_OPERATING_SYSTEMS: ['macos', 'windows', 'linux'],
GLOBAL_EVENT_FILTERS_NAME: 'endpoint-eventfilterlist',

SUPPORTED_HOST_ISOLATION_EXCEPTIONS_OPERATING_SYSTEMS: ['macos', 'windows', 'linux'],
GLOBAL_HOST_ISOLATION_EXCEPTIONS_NAME: 'endpoint-hostisolationexceptionlist',
};

export const ManifestConstants = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { validate } from '@kbn/securitysolution-io-ts-utils';

import {
ENDPOINT_EVENT_FILTERS_LIST_ID,
ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID,
ENDPOINT_LIST_ID,
ENDPOINT_TRUSTED_APPS_LIST_ID,
} from '@kbn/securitysolution-list-constants';
Expand Down Expand Up @@ -65,6 +66,7 @@ export async function getFilteredEndpointExceptionList(
| typeof ENDPOINT_LIST_ID
| typeof ENDPOINT_TRUSTED_APPS_LIST_ID
| typeof ENDPOINT_EVENT_FILTERS_LIST_ID
| typeof ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID
): Promise<WrappedTranslatedExceptionList> {
const exceptions: WrappedTranslatedExceptionList = { entries: [] };
let page = 1;
Expand Down Expand Up @@ -148,6 +150,24 @@ export async function getEndpointEventFiltersList(
);
}

export async function getHostIsolationExceptionsList(
eClient: ExceptionListClient,
schemaVersion: string,
os: string,
policyId?: string
): Promise<WrappedTranslatedExceptionList> {
const osFilter = `exception-list-agnostic.attributes.os_types:\"${os}\"`;
const policyFilter = `(exception-list-agnostic.attributes.tags:\"policy:all\"${
policyId ? ` or exception-list-agnostic.attributes.tags:\"policy:${policyId}\"` : ''
})`;

return getFilteredEndpointExceptionList(
eClient,
schemaVersion,
`${osFilter} and ${policyFilter}`,
ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID
);
}
/**
* Translates Exception list items to Exceptions the endpoint can understand
* @param exceptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { savedObjectsClientMock } from 'src/core/server/mocks';
import {
ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID,
ENDPOINT_LIST_ID,
ENDPOINT_TRUSTED_APPS_LIST_ID,
} from '@kbn/securitysolution-list-constants';
Expand Down Expand Up @@ -66,6 +67,12 @@ describe('ManifestManager', () => {
const ARTIFACT_NAME_EVENT_FILTERS_MACOS = 'endpoint-eventfilterlist-macos-v1';
const ARTIFACT_NAME_EVENT_FILTERS_WINDOWS = 'endpoint-eventfilterlist-windows-v1';
const ARTIFACT_NAME_EVENT_FILTERS_LINUX = 'endpoint-eventfilterlist-linux-v1';
const ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_MACOS =
'endpoint-hostisolationexceptionlist-macos-v1';
const ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_WINDOWS =
'endpoint-hostisolationexceptionlist-windows-v1';
const ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_LINUX =
'endpoint-hostisolationexceptionlist-linux-v1';

let ARTIFACTS: InternalArtifactCompleteSchema[] = [];
let ARTIFACTS_BY_ID: { [K: string]: InternalArtifactCompleteSchema } = {};
Expand Down Expand Up @@ -157,31 +164,29 @@ describe('ManifestManager', () => {
const manifestManagerContext = buildManifestManagerContextMock({ savedObjectsClient });
const manifestManager = new ManifestManager(manifestManagerContext);

savedObjectsClient.get = jest
.fn()
.mockImplementation(async (objectType: string, id: string) => {
if (objectType === ManifestConstants.SAVED_OBJECT_TYPE) {
return {
attributes: {
created: '20-01-2020 10:00:00.000Z',
schemaVersion: 'v2',
semanticVersion: '1.0.0',
artifacts: [
{ artifactId: ARTIFACT_ID_EXCEPTIONS_MACOS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_LINUX, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_MACOS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_2 },
],
},
version: '2.0.0',
};
} else {
return null;
}
});
savedObjectsClient.get = jest.fn().mockImplementation(async (objectType: string) => {
if (objectType === ManifestConstants.SAVED_OBJECT_TYPE) {
return {
attributes: {
created: '20-01-2020 10:00:00.000Z',
schemaVersion: 'v2',
semanticVersion: '1.0.0',
artifacts: [
{ artifactId: ARTIFACT_ID_EXCEPTIONS_MACOS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_LINUX, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_MACOS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_2 },
],
},
version: '2.0.0',
};
} else {
return null;
}
});

(
manifestManagerContext.artifactClient as jest.Mocked<EndpointArtifactClientInterface>
Expand Down Expand Up @@ -218,31 +223,29 @@ describe('ManifestManager', () => {
const manifestManagerContext = buildManifestManagerContextMock({ savedObjectsClient });
const manifestManager = new ManifestManager(manifestManagerContext);

savedObjectsClient.get = jest
.fn()
.mockImplementation(async (objectType: string, id: string) => {
if (objectType === ManifestConstants.SAVED_OBJECT_TYPE) {
return {
attributes: {
created: '20-01-2020 10:00:00.000Z',
schemaVersion: 'v2',
semanticVersion: '1.0.0',
artifacts: [
{ artifactId: ARTIFACT_ID_EXCEPTIONS_MACOS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_LINUX, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_MACOS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_2 },
],
},
version: '2.0.0',
};
} else {
return null;
}
});
savedObjectsClient.get = jest.fn().mockImplementation(async (objectType: string) => {
if (objectType === ManifestConstants.SAVED_OBJECT_TYPE) {
return {
attributes: {
created: '20-01-2020 10:00:00.000Z',
schemaVersion: 'v2',
semanticVersion: '1.0.0',
artifacts: [
{ artifactId: ARTIFACT_ID_EXCEPTIONS_MACOS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_LINUX, policyId: undefined },
{ artifactId: ARTIFACT_ID_EXCEPTIONS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_MACOS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_1 },
{ artifactId: ARTIFACT_ID_TRUSTED_APPS_WINDOWS, policyId: TEST_POLICY_ID_2 },
],
},
version: '2.0.0',
};
} else {
return null;
}
});

(
manifestManagerContext.artifactClient as jest.Mocked<EndpointArtifactClientInterface>
Expand Down Expand Up @@ -278,6 +281,9 @@ describe('ManifestManager', () => {
ARTIFACT_NAME_EVENT_FILTERS_MACOS,
ARTIFACT_NAME_EVENT_FILTERS_WINDOWS,
ARTIFACT_NAME_EVENT_FILTERS_LINUX,
ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_MACOS,
ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_WINDOWS,
ARTIFACT_NAME_HOST_ISOLATION_EXCEPTIONS_LINUX,
];

const getArtifactIds = (artifacts: InternalArtifactSchema[]) => [
Expand Down Expand Up @@ -310,7 +316,7 @@ describe('ManifestManager', () => {

context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => ({
.mockImplementation((_type: string, object: InternalManifestSchema) => ({
attributes: object,
}));
const manifest = await manifestManager.buildNewManifest();
Expand All @@ -321,7 +327,7 @@ describe('ManifestManager', () => {

const artifacts = manifest.getAllArtifacts();

expect(artifacts.length).toBe(9);
expect(artifacts.length).toBe(12);
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);

for (const artifact of artifacts) {
Expand All @@ -336,16 +342,18 @@ describe('ManifestManager', () => {
test('Builds fully new manifest if no baseline parameter passed and present exception list items', async () => {
const exceptionListItem = getExceptionListItemSchemaMock({ os_types: ['macos'] });
const trustedAppListItem = getExceptionListItemSchemaMock({ os_types: ['linux'] });
const hostIsolationExceptionsItem = getExceptionListItemSchemaMock({ os_types: ['linux'] });
const context = buildManifestManagerContextMock({});
const manifestManager = new ManifestManager(context);

context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({
[ENDPOINT_LIST_ID]: { macos: [exceptionListItem] },
[ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] },
[ENDPOINT_HOST_ISOLATION_EXCEPTIONS_LIST_ID]: { linux: [hostIsolationExceptionsItem] },
});
context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => ({
.mockImplementation((_type: string, object: InternalManifestSchema) => ({
attributes: object,
}));
context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]);
Expand All @@ -358,7 +366,7 @@ describe('ManifestManager', () => {

const artifacts = manifest.getAllArtifacts();

expect(artifacts.length).toBe(9);
expect(artifacts.length).toBe(12);
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);

expect(getArtifactObject(artifacts[0])).toStrictEqual({
Expand All @@ -374,6 +382,11 @@ describe('ManifestManager', () => {
expect(getArtifactObject(artifacts[6])).toStrictEqual({ entries: [] });
expect(getArtifactObject(artifacts[7])).toStrictEqual({ entries: [] });
expect(getArtifactObject(artifacts[8])).toStrictEqual({ entries: [] });
expect(getArtifactObject(artifacts[9])).toStrictEqual({ entries: [] });
expect(getArtifactObject(artifacts[10])).toStrictEqual({ entries: [] });
expect(getArtifactObject(artifacts[11])).toStrictEqual({
entries: translateToEndpointExceptions([hostIsolationExceptionsItem], 'v1'),
});

for (const artifact of artifacts) {
expect(manifest.isDefaultArtifact(artifact)).toBe(true);
Expand All @@ -395,7 +408,7 @@ describe('ManifestManager', () => {
context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]);
context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => ({
.mockImplementation((_type: string, object: InternalManifestSchema) => ({
attributes: object,
}));
const oldManifest = await manifestManager.buildNewManifest();
Expand All @@ -413,7 +426,7 @@ describe('ManifestManager', () => {

const artifacts = manifest.getAllArtifacts();

expect(artifacts.length).toBe(9);
expect(artifacts.length).toBe(12);
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);

expect(artifacts[0]).toStrictEqual(oldManifest.getAllArtifacts()[0]);
Expand Down Expand Up @@ -462,7 +475,7 @@ describe('ManifestManager', () => {

context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => ({
.mockImplementation((_type: string, object: InternalManifestSchema) => ({
attributes: object,
}));

Expand All @@ -474,7 +487,7 @@ describe('ManifestManager', () => {

const artifacts = manifest.getAllArtifacts();

expect(artifacts.length).toBe(10);
expect(artifacts.length).toBe(13);
expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES);

expect(getArtifactObject(artifacts[0])).toStrictEqual({
Expand Down Expand Up @@ -653,7 +666,7 @@ describe('ManifestManager', () => {

context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => object);
.mockImplementation((_type: string, object: InternalManifestSchema) => object);

await expect(manifestManager.commit(manifest)).resolves.toBeUndefined();

Expand Down Expand Up @@ -690,7 +703,7 @@ describe('ManifestManager', () => {

context.savedObjectsClient.update = jest
.fn()
.mockImplementation((type: string, id: string, object: InternalManifestSchema) => object);
.mockImplementation((_type: string, _id: string, object: InternalManifestSchema) => object);

await expect(manifestManager.commit(manifest)).resolves.toBeUndefined();

Expand Down Expand Up @@ -1023,7 +1036,7 @@ describe('ManifestManager', () => {

context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => ({
.mockImplementation((_type: string, object: InternalManifestSchema) => ({
attributes: object,
}));
const manifest = await manifestManager.buildNewManifest();
Expand All @@ -1046,7 +1059,7 @@ describe('ManifestManager', () => {

context.savedObjectsClient.create = jest
.fn()
.mockImplementation((type: string, object: InternalManifestSchema) => ({
.mockImplementation((_type: string, object: InternalManifestSchema) => ({
attributes: object,
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
getEndpointEventFiltersList,
getEndpointExceptionList,
getEndpointTrustedAppsList,
getHostIsolationExceptionsList,
Manifest,
} from '../../../lib/artifacts';
import {
Expand Down Expand Up @@ -237,6 +238,46 @@ export class ManifestManager {
);
}

protected async buildHostIsolationExceptionsArtifacts(): Promise<ArtifactsBuildResult> {
const defaultArtifacts: InternalArtifactCompleteSchema[] = [];
const policySpecificArtifacts: Record<string, InternalArtifactCompleteSchema[]> = {};

for (const os of ArtifactConstants.SUPPORTED_HOST_ISOLATION_EXCEPTIONS_OPERATING_SYSTEMS) {
defaultArtifacts.push(await this.buildHostIsolationExceptionForOs(os));
}

await iterateAllListItems(
(page) => this.listEndpointPolicyIds(page),
async (policyId) => {
for (const os of ArtifactConstants.SUPPORTED_HOST_ISOLATION_EXCEPTIONS_OPERATING_SYSTEMS) {
policySpecificArtifacts[policyId] = policySpecificArtifacts[policyId] || [];
policySpecificArtifacts[policyId].push(
await this.buildHostIsolationExceptionForOs(os, policyId)
);
}
}
);

return { defaultArtifacts, policySpecificArtifacts };
}

protected async buildHostIsolationExceptionForOs(
os: string,
policyId?: string
): Promise<InternalArtifactCompleteSchema> {
return buildArtifact(
await getHostIsolationExceptionsList(
this.exceptionListClient,
this.schemaVersion,
os,
policyId
),
this.schemaVersion,
os,
ArtifactConstants.GLOBAL_HOST_ISOLATION_EXCEPTIONS_NAME
);
}

/**
* Writes new artifact SO.
*
Expand Down Expand Up @@ -381,6 +422,7 @@ export class ManifestManager {
this.buildExceptionListArtifacts(),
this.buildTrustedAppsArtifacts(),
this.buildEventFiltersArtifacts(),
this.buildHostIsolationExceptionsArtifacts(),
]);

const manifest = new Manifest({
Expand Down

0 comments on commit de80e69

Please sign in to comment.