[Cloud Posture] add route handler context (#134774)

This commit is contained in:
Or Ouziel 2022-07-20 17:21:13 +03:00 committed by GitHub
parent a0df571b2c
commit f8bc451984
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 233 additions and 380 deletions

View file

@ -1,36 +0,0 @@
/*
* 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 {
AgentService,
PackageService,
AgentPolicyServiceInterface,
PackagePolicyServiceInterface,
} from '@kbn/fleet-plugin/server';
export interface CspAppServiceDependencies {
packageService: PackageService;
agentService: AgentService;
packagePolicyService: PackagePolicyServiceInterface;
agentPolicyService: AgentPolicyServiceInterface;
}
export class CspAppService {
public agentService: AgentService | undefined;
public packageService: PackageService | undefined;
public packagePolicyService: PackagePolicyServiceInterface | undefined;
public agentPolicyService: AgentPolicyServiceInterface | undefined;
public start(dependencies: CspAppServiceDependencies) {
this.agentService = dependencies.agentService;
this.packageService = dependencies.packageService;
this.packagePolicyService = dependencies.packagePolicyService;
this.agentPolicyService = dependencies.agentPolicyService;
}
public stop() {}
}

View file

@ -5,13 +5,12 @@
* 2.0.
*/
import { ElasticsearchClient } from '@kbn/core/server';
import { CspAppContext } from '../plugin';
import { ElasticsearchClient, type Logger } from '@kbn/core/server';
import { LATEST_FINDINGS_INDEX_DEFAULT_NS } from '../../common/constants';
export const isLatestFindingsIndexExists = async (
esClient: ElasticsearchClient,
logger: CspAppContext['logger']
logger: Logger
): Promise<boolean> => {
try {
const queryResult = await esClient.search({

View file

@ -0,0 +1,36 @@
/*
* 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 { loggingSystemMock } from '@kbn/core-logging-server-mocks';
import { coreMock } from '@kbn/core/server/mocks';
import {
createFleetRequestHandlerContextMock,
createMockAgentService,
createMockAgentPolicyService,
createPackagePolicyServiceMock,
createMockPackageService,
} from '@kbn/fleet-plugin/server/mocks';
import { mockAuthenticatedUser } from '@kbn/security-plugin/common/model/authenticated_user.mock';
export const createCspRequestHandlerContextMock = () => {
const coreMockRequestContext = coreMock.createRequestHandlerContext();
return {
core: coreMockRequestContext,
fleet: createFleetRequestHandlerContextMock(),
csp: {
user: mockAuthenticatedUser(),
logger: loggingSystemMock.createLogger(),
esClient: coreMockRequestContext.elasticsearch.client,
soClient: coreMockRequestContext.savedObjects.client,
agentPolicyService: createMockAgentPolicyService(),
agentService: createMockAgentService(),
packagePolicyService: createPackagePolicyServiceMock(),
packageService: createMockPackageService(),
},
};
};

View file

@ -20,17 +20,14 @@ import {
TaskManagerSetupContract,
TaskManagerStartContract,
} from '@kbn/task-manager-plugin/server';
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
import { CspAppService } from './lib/csp_app_services';
import type {
CspServerPluginSetup,
CspServerPluginStart,
CspServerPluginSetupDeps,
CspServerPluginStartDeps,
CspRequestHandlerContext,
CspServerPluginStartServices,
} from './types';
import { defineRoutes } from './routes';
import { setupRoutes } from './routes/setup_routes';
import { setupSavedObjects } from './saved_objects';
import { initializeCspIndices } from './create_indices/create_indices';
import { initializeCspTransforms } from './create_transforms/create_transforms';
@ -48,12 +45,6 @@ import {
setupFindingsStatsTask,
} from './tasks/findings_stats_task';
export interface CspAppContext {
logger: Logger;
service: CspAppService;
security: SecurityPluginSetup;
}
export class CspPlugin
implements
Plugin<
@ -69,24 +60,16 @@ export class CspPlugin
this.logger = initializerContext.logger.get();
}
private readonly CspAppService = new CspAppService();
public setup(
core: CoreSetup<CspServerPluginStartDeps, CspServerPluginStart>,
plugins: CspServerPluginSetupDeps
): CspServerPluginSetup {
const cspAppContext: CspAppContext = {
logger: this.logger,
service: this.CspAppService,
security: plugins.security,
};
setupSavedObjects(core.savedObjects);
const router = core.http.createRouter<CspRequestHandlerContext>();
// Register server side APIs
defineRoutes(router, cspAppContext);
setupRoutes({
core,
logger: this.logger,
});
const coreStartServices = core.getStartServices();
this.setupCspTasks(plugins.taskManager, coreStartServices, this.logger);
@ -95,10 +78,6 @@ export class CspPlugin
}
public start(core: CoreStart, plugins: CspServerPluginStartDeps): CspServerPluginStart {
this.CspAppService.start({
...plugins.fleet,
});
plugins.fleet.fleetSetupCompleted().then(async () => {
const packageInfo = await plugins.fleet.packageService.asInternalUser.getInstallation(
CLOUD_SECURITY_POSTURE_PACKAGE_NAME

View file

@ -4,14 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
httpServerMock,
httpServiceMock,
loggingSystemMock,
savedObjectsClientMock,
} from '@kbn/core/server/mocks';
import type { ElasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
import type { KibanaRequest } from '@kbn/core/server';
import { httpServerMock, httpServiceMock, savedObjectsClientMock } from '@kbn/core/server/mocks';
import {
benchmarksQueryParamsSchema,
DEFAULT_BENCHMARKS_PER_PAGE,
@ -34,21 +27,7 @@ import {
} from '@kbn/fleet-plugin/server/mocks';
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
import { AgentPolicy } from '@kbn/fleet-plugin/common';
import { CspAppService } from '../../lib/csp_app_services';
import { CspAppContext } from '../../plugin';
import { securityMock } from '@kbn/security-plugin/server/mocks';
export const getMockCspContext = (mockEsClient: ElasticsearchClientMock): KibanaRequest => {
return {
core: {
elasticsearch: {
client: { asCurrentUser: mockEsClient },
},
},
fleet: { authz: { fleet: { all: false } } },
} as unknown as KibanaRequest;
};
import { createCspRequestHandlerContextMock } from '../../mocks';
function createMockAgentPolicy(props: Partial<AgentPolicy> = {}): AgentPolicy {
return {
@ -70,23 +49,14 @@ function createMockAgentPolicy(props: Partial<AgentPolicy> = {}): AgentPolicy {
}
describe('benchmarks API', () => {
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
beforeEach(() => {
logger = loggingSystemMock.createLogger();
jest.clearAllMocks();
});
it('validate the API route path', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineGetBenchmarksRoute(router, cspContext);
defineGetBenchmarksRoute(router);
const [config] = router.get.mock.calls[0];
@ -95,20 +65,12 @@ describe('benchmarks API', () => {
it('should accept to a user with fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineGetBenchmarksRoute(router, cspContext);
defineGetBenchmarksRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
} as unknown as KibanaRequest;
const mockContext = createCspRequestHandlerContextMock();
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
const [context, req, res] = [mockContext, mockRequest, mockResponse];
@ -120,19 +82,13 @@ describe('benchmarks API', () => {
it('should reject to a user without fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineGetBenchmarksRoute(router, cspContext);
defineGetBenchmarksRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockContext = {
fleet: { authz: { fleet: { all: false } } },
} as unknown as KibanaRequest;
const mockContext = createCspRequestHandlerContextMock();
mockContext.fleet.authz.fleet.all = false;
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();

View file

@ -13,7 +13,6 @@ import {
CSP_RULE_SAVED_OBJECT_TYPE,
} from '../../../common/constants';
import { benchmarksQueryParamsSchema } from '../../../common/schemas/benchmark';
import { CspAppContext } from '../../plugin';
import type { Benchmark, CspRulesStatus } from '../../../common/types';
import type { CspRule } from '../../../common/schemas';
import {
@ -130,7 +129,7 @@ const createBenchmarks = (
);
};
export const defineGetBenchmarksRoute = (router: CspRouter, cspContext: CspAppContext): void =>
export const defineGetBenchmarksRoute = (router: CspRouter): void =>
router.get(
{
path: BENCHMARKS_ROUTE_PATH,
@ -144,34 +143,29 @@ export const defineGetBenchmarksRoute = (router: CspRouter, cspContext: CspAppCo
return response.forbidden();
}
const cspContext = await context.csp;
try {
const soClient = (await context.core).savedObjects.client;
const { query } = request;
const agentService = cspContext.service.agentService;
const agentPolicyService = cspContext.service.agentPolicyService;
const packagePolicyService = cspContext.service.packagePolicyService;
if (!agentPolicyService || !agentService || !packagePolicyService) {
throw new Error(`Failed to get Fleet services`);
}
const cspPackagePolicies = await getCspPackagePolicies(
soClient,
packagePolicyService,
cspContext.soClient,
cspContext.packagePolicyService,
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
query
request.query
);
const agentPolicies = await getCspAgentPolicies(
soClient,
cspContext.soClient,
cspPackagePolicies.items,
agentPolicyService
cspContext.agentPolicyService
);
const enrichAgentPolicies = await addRunningAgentToAgentPolicy(
cspContext.agentService,
agentPolicies
);
const enrichAgentPolicies = await addRunningAgentToAgentPolicy(agentService, agentPolicies);
const benchmarks = await createBenchmarks(
soClient,
cspContext.soClient,
enrichAgentPolicies,
cspPackagePolicies.items
);

View file

@ -4,38 +4,22 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { httpServerMock, httpServiceMock, loggingSystemMock } from '@kbn/core/server/mocks';
import type { KibanaRequest } from '@kbn/core/server';
import { httpServerMock, httpServiceMock } from '@kbn/core/server/mocks';
import { defineGetComplianceDashboardRoute } from './compliance_dashboard';
import { CspAppService } from '../../lib/csp_app_services';
import { CspAppContext } from '../../plugin';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import { createCspRequestHandlerContextMock } from '../../mocks';
describe('compliance dashboard permissions API', () => {
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
beforeEach(() => {
logger = loggingSystemMock.createLogger();
jest.clearAllMocks();
});
it('should accept to a user with fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineGetComplianceDashboardRoute(router, cspContext);
defineGetComplianceDashboardRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
} as unknown as KibanaRequest;
const mockContext = createCspRequestHandlerContextMock();
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
const [context, req, res] = [mockContext, mockRequest, mockResponse];
@ -47,20 +31,11 @@ describe('compliance dashboard permissions API', () => {
it('should reject to a user without fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineGetComplianceDashboardRoute(router, cspContext);
defineGetComplianceDashboardRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
} as unknown as KibanaRequest;
const mockContext = createCspRequestHandlerContextMock();
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
const [context, req, res] = [mockContext, mockRequest, mockResponse];

View file

@ -9,7 +9,6 @@ import { transformError } from '@kbn/securitysolution-es-utils';
import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import type { ComplianceDashboardData } from '../../../common/types';
import { LATEST_FINDINGS_INDEX_DEFAULT_NS, STATS_ROUTE_PATH } from '../../../common/constants';
import { CspAppContext } from '../../plugin';
import { getGroupedFindingsEvaluation } from './get_grouped_findings_evaluation';
import { ClusterWithoutTrend, getClusters } from './get_clusters';
import { getStats } from './get_stats';
@ -33,10 +32,7 @@ const getClustersTrends = (clustersWithoutTrends: ClusterWithoutTrend[], trends:
const getSummaryTrend = (trends: Trends) =>
trends.map(({ timestamp, summary }) => ({ timestamp, ...summary }));
export const defineGetComplianceDashboardRoute = (
router: CspRouter,
cspContext: CspAppContext
): void =>
export const defineGetComplianceDashboardRoute = (router: CspRouter): void =>
router.get(
{
path: STATS_ROUTE_PATH,
@ -46,8 +42,10 @@ export const defineGetComplianceDashboardRoute = (
},
},
async (context, _, response) => {
const cspContext = await context.csp;
try {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const esClient = cspContext.esClient.asCurrentUser;
const { id: pitId } = await esClient.openPointInTime({
index: LATEST_FINDINGS_INDEX_DEFAULT_NS,

View file

@ -5,12 +5,7 @@
* 2.0.
*/
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
import {
savedObjectsClientMock,
httpServiceMock,
loggingSystemMock,
httpServerMock,
} from '@kbn/core/server/mocks';
import { savedObjectsClientMock, httpServiceMock, httpServerMock } from '@kbn/core/server/mocks';
import {
createRulesConfig,
defineUpdateRulesConfigRoute,
@ -19,8 +14,6 @@ import {
updateAgentConfiguration,
} from './update_rules_configuration';
import { CspAppService } from '../../lib/csp_app_services';
import { CspAppContext } from '../../plugin';
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
import { createPackagePolicyServiceMock } from '@kbn/fleet-plugin/server/mocks';
@ -29,37 +22,28 @@ import type { CspRule } from '../../../common/schemas';
import {
ElasticsearchClient,
KibanaRequest,
SavedObjectsClientContract,
SavedObjectsFindResponse,
} from '@kbn/core/server';
import { Chance } from 'chance';
import { PackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import { mockAuthenticatedUser } from '@kbn/security-plugin/common/model/authenticated_user.mock';
import { DeepPartial } from 'utility-types';
import { createCspRequestHandlerContextMock } from '../../mocks';
describe('Update rules configuration API', () => {
let logger: ReturnType<typeof loggingSystemMock.createLogger>;
let mockEsClient: jest.Mocked<ElasticsearchClient>;
let mockSoClient: jest.Mocked<SavedObjectsClientContract>;
const chance = new Chance();
beforeEach(() => {
logger = loggingSystemMock.createLogger();
jest.clearAllMocks();
});
it('validate the API route path', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineUpdateRulesConfigRoute(router, cspContext);
defineUpdateRulesConfigRoute(router);
const [config, _] = router.post.mock.calls[0];
@ -68,20 +52,12 @@ describe('Update rules configuration API', () => {
it('should accept to a user with fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineUpdateRulesConfigRoute(router, cspContext);
defineUpdateRulesConfigRoute(router);
const [_, handler] = router.post.mock.calls[0];
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
} as unknown as KibanaRequest;
const mockContext = createCspRequestHandlerContextMock();
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
const [context, req, res] = [mockContext, mockRequest, mockResponse];
@ -93,20 +69,11 @@ describe('Update rules configuration API', () => {
it('should reject to a user without fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspAppContextService = new CspAppService();
const cspContext: CspAppContext = {
logger,
service: cspAppContextService,
security: securityMock.createSetup(),
};
defineUpdateRulesConfigRoute(router, cspContext);
defineUpdateRulesConfigRoute(router);
const [_, handler] = router.post.mock.calls[0];
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
} as unknown as KibanaRequest;
const mockContext = createCspRequestHandlerContextMock();
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
const [context, req, res] = [mockContext, mockRequest, mockResponse];

View file

@ -20,7 +20,7 @@ import { PackagePolicy, PackagePolicyConfigRecord } from '@kbn/fleet-plugin/comm
import { PackagePolicyServiceInterface } from '@kbn/fleet-plugin/server';
import { AuthenticatedUser } from '@kbn/security-plugin/common';
import { createCspRuleSearchFilterByPackagePolicy } from '../../../common/utils/helpers';
import { CspAppContext } from '../../plugin';
import type { CspRule, CspRulesConfiguration } from '../../../common/schemas';
import {
CLOUD_SECURITY_POSTURE_PACKAGE_NAME,
@ -129,7 +129,7 @@ export const updateAgentConfiguration = async (
);
};
export const defineUpdateRulesConfigRoute = (router: CspRouter, cspContext: CspAppContext): void =>
export const defineUpdateRulesConfigRoute = (router: CspRouter): void =>
router.post(
{
path: UPDATE_RULES_CONFIG_ROUTE_PATH,
@ -139,33 +139,25 @@ export const defineUpdateRulesConfigRoute = (router: CspRouter, cspContext: CspA
},
},
async (context, request, response) => {
const cspContext = await context.csp;
if (!(await context.fleet).authz.fleet.all) {
return response.forbidden();
}
try {
const coreContext = await context.core;
const esClient = coreContext.elasticsearch.client.asCurrentUser;
const soClient = coreContext.savedObjects.client;
const user = await cspContext.security.authc.getCurrentUser(request);
const packagePolicyService = cspContext.service.packagePolicyService;
const packagePolicyId = request.body.package_policy_id;
if (!packagePolicyService) {
throw new Error(`Failed to get Fleet services`);
}
const packagePolicy = await getPackagePolicy(
soClient,
packagePolicyService,
packagePolicyId
cspContext.soClient,
cspContext.packagePolicyService,
request.body.package_policy_id
);
const updatedPackagePolicy = await updateAgentConfiguration(
packagePolicyService,
cspContext.packagePolicyService,
packagePolicy,
esClient,
soClient,
user
cspContext.esClient.asCurrentUser,
cspContext.soClient,
cspContext.user
);
return response.ok({ body: updatedPackagePolicy });

View file

@ -5,13 +5,14 @@
* 2.0.
*/
import { Chance } from 'chance';
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
import {
elasticsearchClientMock,
ElasticsearchClientMock,
} from '@kbn/core-elasticsearch-client-server-mocks';
import type { ElasticsearchClient } from '@kbn/core/server';
import { httpServerMock, httpServiceMock, loggingSystemMock } from '@kbn/core/server/mocks';
import { httpServerMock, httpServiceMock } from '@kbn/core/server/mocks';
import { DEFAULT_PIT_KEEP_ALIVE, defineEsPitRoute, esPitInputSchema } from './es_pit';
import { CspAppService } from '../../lib/csp_app_services';
import { CspAppContext } from '../../plugin';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import { createCspRequestHandlerContextMock } from '../../mocks';
describe('ES Point in time API endpoint', () => {
const chance = new Chance();
@ -23,13 +24,8 @@ describe('ES Point in time API endpoint', () => {
it('validate the API route path', () => {
const router = httpServiceMock.createRouter();
const cspContext: CspAppContext = {
logger: loggingSystemMock.createLogger(),
service: new CspAppService(),
security: securityMock.createSetup(),
};
defineEsPitRoute(router, cspContext);
defineEsPitRoute(router);
const [config] = router.post.mock.calls[0];
expect(config.path).toEqual('/internal/cloud_security_posture/es_pit');
@ -37,18 +33,10 @@ describe('ES Point in time API endpoint', () => {
it('should accept to a user with fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspContext: CspAppContext = {
logger: loggingSystemMock.createLogger(),
service: new CspAppService(),
security: securityMock.createSetup(),
};
defineEsPitRoute(router, cspContext);
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
};
defineEsPitRoute(router);
const mockContext = createCspRequestHandlerContextMock();
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
const [context, req, res] = [mockContext, mockRequest, mockResponse];
@ -61,17 +49,11 @@ describe('ES Point in time API endpoint', () => {
it('should reject to a user without fleet.all privilege', async () => {
const router = httpServiceMock.createRouter();
const cspContext: CspAppContext = {
logger: loggingSystemMock.createLogger(),
service: new CspAppService(),
security: securityMock.createSetup(),
};
defineEsPitRoute(router, cspContext);
defineEsPitRoute(router);
const mockContext = {
fleet: { authz: { fleet: { all: false } } },
};
const mockContext = createCspRequestHandlerContextMock();
mockContext.fleet.authz.fleet.all = false;
const mockResponse = httpServerMock.createResponseFactory();
const mockRequest = httpServerMock.createKibanaRequest();
@ -85,22 +67,15 @@ describe('ES Point in time API endpoint', () => {
it('should return the newly created PIT ID from ES', async () => {
const router = httpServiceMock.createRouter();
const cspContext: CspAppContext = {
logger: loggingSystemMock.createLogger(),
service: new CspAppService(),
security: securityMock.createSetup(),
};
defineEsPitRoute(router, cspContext);
defineEsPitRoute(router);
const pitId = chance.string();
mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser;
mockEsClient.openPointInTime.mockImplementation(() => Promise.resolve({ id: pitId }));
const mockContext = {
fleet: { authz: { fleet: { all: true } } },
core: { elasticsearch: { client: { asCurrentUser: mockEsClient } } },
};
const mockContext = createCspRequestHandlerContextMock();
mockContext.core.elasticsearch.client.asCurrentUser = mockEsClient as ElasticsearchClientMock;
const indexName = chance.string();
const keepAlive = chance.string();

View file

@ -8,7 +8,6 @@
import { schema } from '@kbn/config-schema';
import { transformError } from '@kbn/securitysolution-es-utils';
import { ES_PIT_ROUTE_PATH } from '../../../common/constants';
import type { CspAppContext } from '../../plugin';
import type { CspRouter } from '../../types';
export const DEFAULT_PIT_KEEP_ALIVE = '1m';
@ -18,7 +17,7 @@ export const esPitInputSchema = schema.object({
keep_alive: schema.string({ defaultValue: DEFAULT_PIT_KEEP_ALIVE }),
});
export const defineEsPitRoute = (router: CspRouter, cspContext: CspAppContext): void =>
export const defineEsPitRoute = (router: CspRouter): void =>
router.post(
{
path: ES_PIT_ROUTE_PATH,
@ -28,13 +27,14 @@ export const defineEsPitRoute = (router: CspRouter, cspContext: CspAppContext):
},
},
async (context, request, response) => {
const cspContext = await context.csp;
if (!(await context.fleet).authz.fleet.all) {
return response.forbidden();
}
try {
const coreContext = await context.core;
const esClient = coreContext.elasticsearch.client.asCurrentUser;
const esClient = cspContext.esClient.asCurrentUser;
const { id } = await esClient.openPointInTime({
index: request.query.index_name,
keep_alive: request.query.keep_alive,

View file

@ -1,22 +0,0 @@
/*
* 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 { defineGetComplianceDashboardRoute } from './compliance_dashboard/compliance_dashboard';
import { defineGetBenchmarksRoute } from './benchmarks/benchmarks';
import { defineUpdateRulesConfigRoute } from './configuration/update_rules_configuration';
import { defineGetCspSetupStatusRoute } from './status/status';
import { defineEsPitRoute } from './es_pit/es_pit';
import { CspAppContext } from '../plugin';
import { CspRouter } from '../types';
export function defineRoutes(router: CspRouter, cspContext: CspAppContext) {
defineGetComplianceDashboardRoute(router, cspContext);
defineGetBenchmarksRoute(router, cspContext);
defineUpdateRulesConfigRoute(router, cspContext);
defineGetCspSetupStatusRoute(router, cspContext);
defineEsPitRoute(router, cspContext);
}

View file

@ -0,0 +1,67 @@
/*
* 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 { CoreSetup, Logger } from '@kbn/core/server';
import type { AuthenticatedUser } from '@kbn/security-plugin/common';
import type {
CspRequestHandlerContext,
CspServerPluginStart,
CspServerPluginStartDeps,
} from '../types';
import { PLUGIN_ID } from '../../common';
import { defineGetComplianceDashboardRoute } from './compliance_dashboard/compliance_dashboard';
import { defineGetBenchmarksRoute } from './benchmarks/benchmarks';
import { defineUpdateRulesConfigRoute } from './configuration/update_rules_configuration';
import { defineGetCspSetupStatusRoute } from './status/status';
import { defineEsPitRoute } from './es_pit/es_pit';
/**
* 1. Registers routes
* 2. Registers routes handler context
*/
export function setupRoutes({
core,
logger,
}: {
core: CoreSetup<CspServerPluginStartDeps, CspServerPluginStart>;
logger: Logger;
}) {
const router = core.http.createRouter<CspRequestHandlerContext>();
defineGetComplianceDashboardRoute(router);
defineGetBenchmarksRoute(router);
defineUpdateRulesConfigRoute(router);
defineGetCspSetupStatusRoute(router);
defineEsPitRoute(router);
core.http.registerRouteHandlerContext<CspRequestHandlerContext, typeof PLUGIN_ID>(
PLUGIN_ID,
async (context, request) => {
const [, { security, fleet }] = await core.getStartServices();
const coreContext = await context.core;
await fleet.fleetSetupCompleted();
let user: AuthenticatedUser | null = null;
return {
get user() {
// We want to call getCurrentUser only when needed and only once
if (!user) {
user = security.authc.getCurrentUser(request);
}
return user;
},
logger,
esClient: coreContext.elasticsearch.client,
soClient: coreContext.savedObjects.client,
agentPolicyService: fleet.agentPolicyService,
agentService: fleet.agentService,
packagePolicyService: fleet.packagePolicyService,
packageService: fleet.packageService,
};
}
);
}

View file

@ -5,18 +5,9 @@
* 2.0.
*/
import { CspAppContext } from '../../plugin';
import { defineGetCspSetupStatusRoute, INDEX_TIMEOUT_IN_MINUTES } from './status';
import { httpServerMock, httpServiceMock, loggingSystemMock } from '@kbn/core/server/mocks';
import { httpServerMock, httpServiceMock } from '@kbn/core/server/mocks';
import type { ESSearchResponse } from '@kbn/core/types/elasticsearch';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import {
createMockAgentPolicyService,
createMockAgentService,
createMockPackageService,
createPackagePolicyServiceMock,
xpackMocks,
} from '@kbn/fleet-plugin/server/mocks';
import {
AgentClient,
AgentPolicyServiceInterface,
@ -32,6 +23,7 @@ import {
RegistryPackage,
} from '@kbn/fleet-plugin/common';
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
import { createCspRequestHandlerContextMock } from '../../mocks';
const mockCspPackageInfo: Installation = {
verification_status: 'verified',
@ -65,43 +57,29 @@ const mockLatestCspPackageInfo: RegistryPackage = {
describe('CspSetupStatus route', () => {
const router = httpServiceMock.createRouter();
const logger: ReturnType<typeof loggingSystemMock.createLogger> =
loggingSystemMock.createLogger();
let mockContext: ReturnType<typeof xpackMocks.createRequestHandlerContext>;
let mockContext: ReturnType<typeof createCspRequestHandlerContextMock>;
let mockPackagePolicyService: jest.Mocked<PackagePolicyServiceInterface>;
let mockAgentPolicyService: jest.Mocked<AgentPolicyServiceInterface>;
let mockAgentService: jest.Mocked<AgentService>;
let mockAgentClient: jest.Mocked<AgentClient>;
let mockPackageService: PackageService;
let mockPackageClient: jest.Mocked<PackageClient>;
let cspContext: CspAppContext;
beforeEach(() => {
jest.clearAllMocks();
mockContext = xpackMocks.createRequestHandlerContext();
mockPackagePolicyService = createPackagePolicyServiceMock();
mockAgentPolicyService = createMockAgentPolicyService();
mockAgentService = createMockAgentService();
mockPackageService = createMockPackageService();
mockContext = createCspRequestHandlerContextMock();
mockPackagePolicyService = mockContext.csp.packagePolicyService;
mockAgentPolicyService = mockContext.csp.agentPolicyService;
mockAgentService = mockContext.csp.agentService;
mockPackageService = mockContext.csp.packageService;
mockAgentClient = mockAgentService.asInternalUser as jest.Mocked<AgentClient>;
mockPackageClient = mockPackageService.asInternalUser as jest.Mocked<PackageClient>;
cspContext = {
logger,
service: {
agentService: mockAgentService,
agentPolicyService: mockAgentPolicyService,
packagePolicyService: mockPackagePolicyService,
packageService: mockPackageService,
},
security: securityMock.createSetup(),
} as unknown as CspAppContext;
});
it('validate the API route path', async () => {
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [config, _] = router.get.mock.calls[0];
expect(config.path).toEqual('/internal/cloud_security_posture/status');
@ -123,7 +101,7 @@ describe('CspSetupStatus route', () => {
});
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockResponse = httpServerMock.createResponseFactory();
@ -162,7 +140,7 @@ describe('CspSetupStatus route', () => {
});
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockResponse = httpServerMock.createResponseFactory();
@ -210,7 +188,7 @@ describe('CspSetupStatus route', () => {
} as unknown as GetAgentStatusResponse['results']);
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockResponse = httpServerMock.createResponseFactory();
@ -248,7 +226,7 @@ describe('CspSetupStatus route', () => {
});
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];
const mockResponse = httpServerMock.createResponseFactory();
@ -295,7 +273,7 @@ describe('CspSetupStatus route', () => {
} as unknown as GetAgentStatusResponse['results']);
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];
@ -349,7 +327,7 @@ describe('CspSetupStatus route', () => {
} as unknown as GetAgentStatusResponse['results']);
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];
@ -405,7 +383,7 @@ describe('CspSetupStatus route', () => {
} as unknown as GetAgentStatusResponse['results']);
// Act
defineGetCspSetupStatusRoute(router, cspContext);
defineGetCspSetupStatusRoute(router);
const [_, handler] = router.get.mock.calls[0];

View file

@ -6,7 +6,7 @@
*/
import { transformError } from '@kbn/securitysolution-es-utils';
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import type { Logger, ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import type {
AgentPolicyServiceInterface,
AgentService,
@ -16,7 +16,6 @@ import type {
import moment, { MomentInput } from 'moment';
import { PackagePolicy } from '@kbn/fleet-plugin/common';
import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME, STATUS_ROUTE_PATH } from '../../../common/constants';
import type { CspAppContext } from '../../plugin';
import type { CspRouter } from '../../types';
import type { CspSetupStatus, Status } from '../../../common/types';
import {
@ -71,7 +70,7 @@ const getStatus = (
};
const getCspSetupStatus = async (
logger: CspAppContext['logger'],
logger: Logger,
esClient: ElasticsearchClient,
soClient: SavedObjectsClientContract,
packageService: PackageService,
@ -123,7 +122,7 @@ const getCspSetupStatus = async (
};
};
export const defineGetCspSetupStatusRoute = (router: CspRouter, cspContext: CspAppContext): void =>
export const defineGetCspSetupStatusRoute = (router: CspRouter): void =>
router.get(
{
path: STATUS_ROUTE_PATH,
@ -133,27 +132,16 @@ export const defineGetCspSetupStatusRoute = (router: CspRouter, cspContext: CspA
},
},
async (context, _, response) => {
const cspContext = await context.csp;
try {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const soClient = (await context.core).savedObjects.client;
const packageService = cspContext.service.packageService;
const agentService = cspContext.service.agentService;
const agentPolicyService = cspContext.service.agentPolicyService;
const packagePolicyService = cspContext.service.packagePolicyService;
if (!agentPolicyService || !agentService || !packagePolicyService || !packageService) {
throw new Error(`Failed to get Fleet services`);
}
const cspSetupStatus = await getCspSetupStatus(
cspContext.logger,
esClient,
soClient,
packageService,
packagePolicyService,
agentPolicyService,
agentService
cspContext.esClient.asCurrentUser,
cspContext.soClient,
cspContext.packageService,
cspContext.packagePolicyService,
cspContext.agentPolicyService,
cspContext.agentService
);
const body: CspSetupStatus = cspSetupStatus;

View file

@ -4,7 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type {
PluginSetup as DataPluginSetup,
PluginStart as DataPluginStart,
@ -13,15 +12,20 @@ import {
TaskManagerSetupContract,
TaskManagerStartContract,
} from '@kbn/task-manager-plugin/server';
import type {
RouteMethod,
KibanaResponseFactory,
RequestHandler,
IRouter,
CoreStart,
CustomRequestHandlerContext,
Logger,
SavedObjectsClientContract,
IScopedClusterClient,
} from '@kbn/core/server';
import type {
AgentService,
PackageService,
AgentPolicyServiceInterface,
PackagePolicyServiceInterface,
} from '@kbn/fleet-plugin/server';
import type { FleetStartContract, FleetRequestHandlerContext } from '@kbn/fleet-plugin/server';
import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server';
@ -49,19 +53,22 @@ export interface CspServerPluginStartDeps {
export type CspServerPluginStartServices = Promise<
[CoreStart, CspServerPluginStartDeps, CspServerPluginStart]
>;
export type CspRequestHandlerContext = FleetRequestHandlerContext;
/**
* Convenience type for request handlers in CSP that includes the CspRequestHandlerContext type
* @internal
*/
export type CspRequestHandler<
P = unknown,
Q = unknown,
B = unknown,
Method extends RouteMethod = any,
ResponseFactory extends KibanaResponseFactory = KibanaResponseFactory
> = RequestHandler<P, Q, B, CspRequestHandlerContext, Method, ResponseFactory>;
interface CspApiRequestHandlerContext {
user: ReturnType<SecurityPluginStart['authc']['getCurrentUser']>;
logger: Logger;
esClient: IScopedClusterClient;
soClient: SavedObjectsClientContract;
agentPolicyService: AgentPolicyServiceInterface;
agentService: AgentService;
packagePolicyService: PackagePolicyServiceInterface;
packageService: PackageService;
}
export type CspRequestHandlerContext = CustomRequestHandlerContext<{
csp: CspApiRequestHandlerContext;
fleet: FleetRequestHandlerContext['fleet'];
}>;
/**
* Convenience type for routers in Csp that includes the CspRequestHandlerContext type