[Defend Workflows] Remove SO.attributes spread from Osquery (#160356)

This commit is contained in:
Tomasz Ciecierski 2023-06-28 07:55:42 +02:00 committed by GitHub
parent 8acbc43d8c
commit 036a736088
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 301 additions and 40 deletions

View file

@ -44,11 +44,13 @@ export interface SavedQuerySavedObject {
snapshot?: boolean;
removed?: boolean;
platform: string;
ecs_mapping?: Array<Record<string, unknown>>;
ecs_mapping?: Array<{ key: string; value: Record<string, object> }>;
created_at: string;
created_by: string | undefined;
updated_at: string;
updated_by: string | undefined;
prebuilt?: boolean;
version: number;
}
export interface HTTPError extends Error {

View file

@ -28,6 +28,7 @@ import {
} from './utils';
import { convertShardsToArray, getInternalSavedObjectsClient } from '../utils';
import type { PackSavedObject } from '../../common/types';
import type { PackResponseData } from './types';
type PackSavedObjectLimited = Omit<PackSavedObject, 'saved_object_id' | 'references'>;
@ -174,9 +175,26 @@ export const createPackRoute = (router: IRouter, osqueryContext: OsqueryAppConte
set(packSO, 'attributes.queries', queries);
const { attributes } = packSO;
const data: PackResponseData = {
name: attributes.name,
description: attributes.description,
queries: attributes.queries,
version: attributes.version,
enabled: attributes.enabled,
created_at: attributes.created_at,
created_by: attributes.created_by,
updated_at: attributes.updated_at,
updated_by: attributes.updated_by,
policy_ids: attributes.policy_ids,
shards: attributes.shards,
saved_object_id: packSO.id,
};
return response.ok({
body: {
data: { ...packSO.attributes, saved_object_id: packSO.id },
data,
},
});
}

View file

@ -13,6 +13,7 @@ import type { IRouter } from '@kbn/core/server';
import { packSavedObjectType } from '../../../common/types';
import { PLUGIN_ID } from '../../../common';
import type { PackSavedObject } from '../../common/types';
import type { PackResponseData } from './types';
export const findPackRoute = (router: IRouter) => {
router.get(
@ -43,14 +44,24 @@ export const findPackRoute = (router: IRouter) => {
sortOrder: request.query.sortOrder ?? 'desc',
});
const packSavedObjects = map(soClientResponse.saved_objects, (pack) => {
const packSavedObjects: PackResponseData[] = map(soClientResponse.saved_objects, (pack) => {
const policyIds = map(
filter(pack.references, ['type', AGENT_POLICY_SAVED_OBJECT_TYPE]),
'id'
);
const { attributes } = pack;
return {
...pack.attributes,
name: attributes.name,
description: attributes.description,
queries: attributes.queries,
version: attributes.version,
enabled: attributes.enabled,
created_at: attributes.created_at,
created_by: attributes.created_by,
updated_at: attributes.updated_at,
updated_by: attributes.updated_by,
saved_object_id: pack.id,
policy_ids: policyIds,
};

View file

@ -15,6 +15,7 @@ import { PLUGIN_ID } from '../../../common';
import { packSavedObjectType } from '../../../common/types';
import { convertSOQueriesToPack } from './utils';
import { convertShardsToObject } from '../utils';
import type { ReadPackResponseData } from './types';
export const readPackRoute = (router: IRouter) => {
router.get(
@ -39,17 +40,30 @@ export const readPackRoute = (router: IRouter) => {
const policyIds = map(filter(references, ['type', AGENT_POLICY_SAVED_OBJECT_TYPE]), 'id');
const osqueryPackAssetReference = !!filter(references, ['type', 'osquery-pack-asset']);
const data: ReadPackResponseData = {
type: rest.type,
namespaces: rest.namespaces,
migrationVersion: rest.migrationVersion,
managed: rest.managed,
coreMigrationVersion: rest.coreMigrationVersion,
name: attributes.name,
description: attributes.description,
version: attributes.version,
enabled: attributes.enabled,
created_at: attributes.created_at,
created_by: attributes.created_by,
updated_at: attributes.updated_at,
updated_by: attributes.updated_by,
saved_object_id: id,
queries: convertSOQueriesToPack(attributes.queries),
shards: convertShardsToObject(attributes.shards),
policy_ids: policyIds,
read_only: attributes.version !== undefined && osqueryPackAssetReference,
};
return response.ok({
body: {
data: {
...rest,
...attributes,
saved_object_id: id,
queries: convertSOQueriesToPack(attributes.queries),
shards: convertShardsToObject(attributes.shards),
policy_ids: policyIds,
read_only: attributes.version !== undefined && osqueryPackAssetReference,
},
data,
},
});
}

View file

@ -0,0 +1,53 @@
/*
* 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 type { SOShard } from '../../common/types';
interface PackQuery {
id: string;
name: string;
query: string;
interval: number;
snapshot?: boolean;
removed?: boolean;
ecs_mapping?: Record<string, unknown>;
}
export interface PackResponseData {
saved_object_id: string;
name: string;
description: string | undefined;
queries: PackQuery[];
version?: number;
enabled: boolean | undefined;
created_at: string;
created_by: string | undefined;
updated_at: string;
updated_by: string | undefined;
policy_ids?: string[];
shards?: SOShard;
}
export interface ReadPackResponseData {
saved_object_id: string;
name: string;
description: string | undefined;
queries: Record<string, PackQuery>;
version?: number;
enabled: boolean | undefined;
created_at: string;
created_by: string | undefined;
updated_at: string;
updated_by: string | undefined;
policy_ids?: string[];
shards: Record<string, number>;
read_only?: boolean;
type: string;
namespaces?: string[];
migrationVersion?: Record<string, string>;
managed?: boolean;
coreMigrationVersion?: string;
}

View file

@ -31,6 +31,7 @@ import {
import { convertShardsToArray, getInternalSavedObjectsClient } from '../utils';
import type { PackSavedObject } from '../../common/types';
import type { PackResponseData } from './types';
export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => {
router.put(
@ -181,12 +182,12 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte
filter(currentPackSO.references, ['type', AGENT_POLICY_SAVED_OBJECT_TYPE]),
'id'
);
const updatedPackSO = await savedObjectsClient.get<{
name: string;
enabled: boolean;
queries: Record<string, unknown>;
}>(packSavedObjectType, request.params.id);
const updatedPackSO = await savedObjectsClient.get<PackSavedObject>(
packSavedObjectType,
request.params.id
);
// @ts-expect-error update types
updatedPackSO.attributes.queries = convertSOQueriesToPack(updatedPackSO.attributes.queries);
if (enabled == null && !currentPackSO.attributes.enabled) {
@ -349,8 +350,25 @@ export const updatePackRoute = (router: IRouter, osqueryContext: OsqueryAppConte
);
}
const { attributes } = updatedPackSO;
const data: PackResponseData = {
name: attributes.name,
description: attributes.description,
queries: attributes.queries,
version: attributes.version,
enabled: attributes.enabled,
created_at: attributes.created_at,
created_by: attributes.created_by,
updated_at: attributes.updated_at,
updated_by: attributes.updated_by,
policy_ids: attributes.policy_ids,
shards: attributes.shards,
saved_object_id: updatedPackSO.id,
};
return response.ok({
body: { data: { ...updatedPackSO.attributes, saved_object_id: updatedPackSO.id } },
body: { data },
});
}
);

View file

@ -7,6 +7,8 @@
import { isEmpty, pickBy, some, isBoolean } from 'lodash';
import type { IRouter } from '@kbn/core/server';
import type { SavedQueryResponse } from './types';
import type { SavedQuerySavedObject } from '../../common/types';
import { PLUGIN_ID } from '../../../common';
import type { CreateSavedQueryRequestSchemaDecoded } from '../../../common/schemas/routes/saved_query/create_saved_query_request_schema';
import { createSavedQueryRequestSchema } from '../../../common/schemas/routes/saved_query/create_saved_query_request_schema';
@ -46,7 +48,7 @@ export const createSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAp
const currentUser = await osqueryContext.security.authc.getCurrentUser(request)?.username;
const conflictingEntries = await savedObjectsClient.find({
const conflictingEntries = await savedObjectsClient.find<SavedQuerySavedObject>({
type: savedQuerySavedObjectType,
filter: `${savedQuerySavedObjectType}.attributes.id: "${id}"`,
});
@ -80,16 +82,31 @@ export const createSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAp
)
);
const { attributes } = savedQuerySO;
const data: Partial<SavedQueryResponse> = pickBy(
{
created_at: attributes.created_at,
created_by: attributes.created_by,
description: attributes.description,
id: attributes.id,
removed: attributes.removed,
snapshot: attributes.snapshot,
version: attributes.version,
interval: attributes.interval,
platform: attributes.platform,
query: attributes.query,
updated_at: attributes.updated_at,
updated_by: attributes.updated_by,
saved_object_id: savedQuerySO.id,
ecs_mapping,
},
(value) => !isEmpty(value)
);
return response.ok({
body: {
data: pickBy(
{
...savedQuerySO.attributes,
saved_object_id: savedQuerySO.id,
ecs_mapping,
},
(value) => !isEmpty(value)
),
data,
},
});
}

View file

@ -9,6 +9,8 @@ import { schema } from '@kbn/config-schema';
import type { IRouter } from '@kbn/core/server';
import { omit } from 'lodash';
import type { SavedQueryResponse } from './types';
import type { SavedQuerySavedObject } from '../../common/types';
import type { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import { PLUGIN_ID } from '../../../common';
import { savedQuerySavedObjectType } from '../../../common/types';
@ -36,10 +38,7 @@ export const findSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppC
const savedObjectsClient = coreContext.savedObjects.client;
try {
const savedQueries = await savedObjectsClient.find<{
ecs_mapping: Array<{ field: string; value: string }>;
prebuilt: boolean;
}>({
const savedQueries = await savedObjectsClient.find<SavedQuerySavedObject>({
type: savedQuerySavedObjectType,
page: request.query.page,
perPage: request.query.pageSize,
@ -50,7 +49,7 @@ export const findSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppC
const prebuiltSavedQueriesMap = await getInstalledSavedQueriesMap(
osqueryContext.service.getPackageService()?.asInternalUser
);
const savedObjects = savedQueries.saved_objects.map((savedObject) => {
const savedObjects: SavedQueryResponse[] = savedQueries.saved_objects.map((savedObject) => {
// eslint-disable-next-line @typescript-eslint/naming-convention
const ecs_mapping = savedObject.attributes.ecs_mapping;
@ -61,8 +60,38 @@ export const findSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppC
savedObject.attributes.ecs_mapping = convertECSMappingToObject(ecs_mapping);
}
const {
created_at: createdAt,
created_by: createdBy,
description,
id,
interval,
platform,
query,
removed,
snapshot,
version,
ecs_mapping: ecsMapping,
updated_at: updatedAt,
updated_by: updatedBy,
prebuilt,
} = savedObject.attributes;
return {
...savedObject.attributes,
created_at: createdAt,
created_by: createdBy,
description,
id,
removed,
snapshot,
version,
ecs_mapping: ecsMapping,
interval,
platform,
query,
updated_at: updatedAt,
updated_by: updatedBy,
prebuilt,
saved_object_id: savedObject.id,
};
});

View file

@ -7,6 +7,8 @@
import { schema } from '@kbn/config-schema';
import type { IRouter } from '@kbn/core/server';
import type { SavedQueryResponse } from './types';
import type { SavedQuerySavedObject } from '../../common/types';
import { isSavedQueryPrebuilt } from './utils';
import type { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import { PLUGIN_ID } from '../../../common';
@ -28,10 +30,10 @@ export const readSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppC
const coreContext = await context.core;
const savedObjectsClient = coreContext.savedObjects.client;
const savedQuery = await savedObjectsClient.get<{
ecs_mapping: Array<{ key: string; value: Record<string, object> }>;
prebuilt: boolean;
}>(savedQuerySavedObjectType, request.params.id);
const savedQuery = await savedObjectsClient.get<SavedQuerySavedObject>(
savedQuerySavedObjectType,
request.params.id
);
if (savedQuery.attributes.ecs_mapping) {
// @ts-expect-error update types
@ -45,8 +47,45 @@ export const readSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppC
savedQuery.id
);
const {
created_at: createdAt,
created_by: createdBy,
description,
id,
interval,
platform,
query,
removed,
snapshot,
version,
ecs_mapping: ecsMapping,
updated_at: updatedAt,
updated_by: updatedBy,
prebuilt,
} = savedQuery.attributes;
const data: SavedQueryResponse = {
created_at: createdAt,
created_by: createdBy,
description,
id,
removed,
snapshot,
version,
ecs_mapping: ecsMapping,
interval,
platform,
query,
updated_at: updatedAt,
updated_by: updatedBy,
prebuilt,
saved_object_id: savedQuery.id,
};
return response.ok({
body: { data: { ...savedQuery.attributes, saved_object_id: savedQuery.id } },
body: {
data,
},
});
}
);

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
export interface SavedQueryResponse {
saved_object_id: string;
id: string;
description: string | undefined;
query: string;
interval: number | string;
snapshot?: boolean;
removed?: boolean;
platform?: string;
ecs_mapping?: Array<{ key: string; value: Record<string, object> }>;
created_at: string;
created_by: string | undefined;
updated_at: string;
updated_by: string | undefined;
prebuilt?: boolean;
version: number | string;
}
export interface UpdateSavedQueryResponse {
saved_object_id: string;
id: string;
description: string | undefined;
query: string;
interval: number | string;
snapshot?: boolean;
removed?: boolean;
platform?: string;
ecs_mapping?: Array<{ key: string; value: object }>;
created_at: string;
created_by: string | undefined;
updated_at: string;
updated_by: string | undefined;
prebuilt?: boolean;
version: string;
}

View file

@ -14,6 +14,7 @@ import { PLUGIN_ID } from '../../../common';
import { savedQuerySavedObjectType } from '../../../common/types';
import type { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import { convertECSMappingToArray, convertECSMappingToObject } from '../utils';
import type { UpdateSavedQueryResponse } from './types';
export const updateSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAppContext) => {
router.put(
@ -122,9 +123,26 @@ export const updateSavedQueryRoute = (router: IRouter, osqueryContext: OsqueryAp
{};
}
const { attributes } = updatedSavedQuerySO;
const data: Partial<UpdateSavedQueryResponse> = {
description: attributes.description,
id: attributes.id,
removed: attributes.removed,
snapshot: attributes.snapshot,
version: attributes.version,
ecs_mapping: attributes.ecs_mapping,
interval: attributes.interval,
platform: attributes.platform,
query: attributes.query,
updated_at: attributes.updated_at,
updated_by: attributes.updated_by,
saved_object_id: updatedSavedQuerySO.id,
};
return response.ok({
body: {
data: { ...updatedSavedQuerySO.attributes, saved_object_id: updatedSavedQuerySO.id },
data,
},
});
}