[Cloud Security] [Agentless] [Serverless] Enable Serverless projects to transition to using Agentless API solution in Kibana (#190371)

This commit is contained in:
seanrathier 2024-08-19 10:22:45 -04:00 committed by GitHub
parent 1e64b9e4b2
commit c2933dee94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 289 additions and 90 deletions

View file

@ -35,6 +35,7 @@ enabled:
- x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts
- x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.essentials.ts
- x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts
- x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless_api.ts
- x-pack/test_serverless/functional/test_suites/security/config.saved_objects_management.ts
- x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts
- x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts

View file

@ -363,8 +363,8 @@ describe('PackagePolicyInputPanel', () => {
isAgentlessPackagePolicy: jest.fn(),
isAgentlessAgentPolicy: jest.fn(),
isAgentlessIntegration: jest.fn(),
isAgentlessCloudEnabled: true,
isAgentlessServerlessEnabled: false,
isAgentlessApiEnabled: true,
isDefaultAgentlessPolicyEnabled: false,
});
});
@ -398,8 +398,8 @@ describe('PackagePolicyInputPanel', () => {
isAgentlessPackagePolicy: jest.fn(),
isAgentlessAgentPolicy: jest.fn(),
isAgentlessIntegration: jest.fn(),
isAgentlessCloudEnabled: true,
isAgentlessServerlessEnabled: false,
isAgentlessApiEnabled: true,
isDefaultAgentlessPolicyEnabled: false,
});
});

View file

@ -49,37 +49,18 @@ describe('useAgentless', () => {
jest.clearAllMocks();
});
it('should should not return return isAgentless when agentless is not enabled', () => {
it('should not return isAgentless when agentless is not enabled', () => {
const { result } = renderHook(() => useAgentless());
expect(result.current.isAgentlessEnabled).toBeFalsy();
expect(result.current.isAgentlessCloudEnabled).toBeFalsy();
expect(result.current.isAgentlessServerlessEnabled).toBeFalsy();
});
it('should should return agentlessAPIUrl when agentless config is set', () => {
const agentlessAPIUrl = 'https://agentless.api.url';
(useConfig as MockFn).mockReturnValue({
agentless: {
api: {
url: agentlessAPIUrl,
},
},
} as any);
const { result } = renderHook(() => useAgentless());
expect(result.current.isAgentlessEnabled).toBeFalsy();
expect(result.current.isAgentlessCloudEnabled).toBeFalsy();
expect(result.current.isAgentlessServerlessEnabled).toBeFalsy();
expect(result.current.isAgentlessApiEnabled).toBeFalsy();
expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy();
});
it('should return isAgentlessEnabled as falsy if agentlessAPIUrl and experimental feature agentless is truthy without cloud or serverless', () => {
const agentlessAPIUrl = 'https://agentless.api.url';
it('should return isAgentlessEnabled as falsy if agentless.enabled is true and experimental feature agentless is truthy without cloud or serverless', () => {
(useConfig as MockFn).mockReturnValue({
agentless: {
api: {
url: agentlessAPIUrl,
},
enabled: true,
},
} as any);
@ -90,18 +71,14 @@ describe('useAgentless', () => {
const { result } = renderHook(() => useAgentless());
expect(result.current.isAgentlessEnabled).toBeFalsy();
expect(result.current.isAgentlessCloudEnabled).toBeFalsy();
expect(result.current.isAgentlessServerlessEnabled).toBeFalsy();
expect(result.current.isAgentlessApiEnabled).toBeFalsy();
expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy();
});
it('should return isAgentlessEnabled and isAgentlessCloudEnabled as truthy with isCloudEnabled', () => {
const agentlessAPIUrl = 'https://agentless.api.url';
it('should return isAgentlessEnabled and isAgentlessApiEnabled as truthy with isCloudEnabled', () => {
(useConfig as MockFn).mockReturnValue({
agentless: {
enabled: true,
api: {
url: agentlessAPIUrl,
},
},
} as any);
@ -115,19 +92,10 @@ describe('useAgentless', () => {
const { result } = renderHook(() => useAgentless());
expect(result.current.isAgentlessEnabled).toBeTruthy();
expect(result.current.isAgentlessCloudEnabled).toBeTruthy();
expect(result.current.isAgentlessServerlessEnabled).toBeFalsy();
expect(result.current.isAgentlessApiEnabled).toBeTruthy();
expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy();
});
it('should return isAgentlessEnabled and isAgentlessServerlessEnabled as truthy with isServerlessEnabled', () => {
const agentlessAPIUrl = 'https://agentless.api.url';
(useConfig as MockFn).mockReturnValue({
agentless: {
api: {
url: agentlessAPIUrl,
},
},
} as any);
it('should return isAgentlessEnabled and isDefaultAgentlessPolicyEnabled as truthy with isServerlessEnabled and experimental feature agentless is truthy', () => {
mockedExperimentalFeaturesService.get.mockReturnValue({
agentless: true,
} as any);
@ -142,8 +110,27 @@ describe('useAgentless', () => {
const { result } = renderHook(() => useAgentless());
expect(result.current.isAgentlessEnabled).toBeTruthy();
expect(result.current.isAgentlessCloudEnabled).toBeFalsy();
expect(result.current.isAgentlessServerlessEnabled).toBeTruthy();
expect(result.current.isAgentlessApiEnabled).toBeFalsy();
expect(result.current.isDefaultAgentlessPolicyEnabled).toBeTruthy();
});
it('should return isAgentlessEnabled as falsy and isDefaultAgentlessPolicyEnabled as falsy with isServerlessEnabled and experimental feature agentless is falsy', () => {
mockedExperimentalFeaturesService.get.mockReturnValue({
agentless: false,
} as any);
(useStartServices as MockFn).mockReturnValue({
cloud: {
isServerlessEnabled: true,
isCloudEnabled: false,
},
});
const { result } = renderHook(() => useAgentless());
expect(result.current.isAgentlessEnabled).toBeFalsy();
expect(result.current.isAgentlessApiEnabled).toBeFalsy();
expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy();
});
});
@ -224,6 +211,7 @@ describe('useSetupTechnology', () => {
it('should set agentless setup technology if agent policy supports agentless in edit page', async () => {
(useConfig as MockFn).mockReturnValue({
agentless: {
enabled: true,
api: {
url: 'https://agentless.api.url',
},

View file

@ -29,10 +29,11 @@ export const useAgentless = () => {
const isServerless = !!cloud?.isServerlessEnabled;
const isCloud = !!cloud?.isCloudEnabled;
const isAgentlessCloudEnabled = isCloud && !!config.agentless?.enabled;
const isAgentlessServerlessEnabled = isServerless && agentlessExperimentalFeatureEnabled;
const isAgentlessApiEnabled = (isCloud || isServerless) && config.agentless?.enabled;
const isDefaultAgentlessPolicyEnabled =
!isAgentlessApiEnabled && isServerless && agentlessExperimentalFeatureEnabled;
const isAgentlessEnabled = isAgentlessCloudEnabled || isAgentlessServerlessEnabled;
const isAgentlessEnabled = isAgentlessApiEnabled || isDefaultAgentlessPolicyEnabled;
const isAgentlessAgentPolicy = (agentPolicy: AgentPolicy | undefined) => {
if (!agentPolicy) return false;
@ -62,8 +63,8 @@ export const useAgentless = () => {
return isAgentlessEnabled && packagePolicy.policy_ids.includes(AGENTLESS_POLICY_ID);
};
return {
isAgentlessCloudEnabled,
isAgentlessServerlessEnabled,
isAgentlessApiEnabled,
isDefaultAgentlessPolicyEnabled,
isAgentlessEnabled,
isAgentlessAgentPolicy,
isAgentlessIntegration,
@ -90,7 +91,7 @@ export function useSetupTechnology({
isEditPage?: boolean;
agentPolicies?: AgentPolicy[];
}) {
const { isAgentlessEnabled, isAgentlessCloudEnabled, isAgentlessServerlessEnabled } =
const { isAgentlessEnabled, isAgentlessApiEnabled, isDefaultAgentlessPolicyEnabled } =
useAgentless();
// this is a placeholder for the new agent-BASED policy that will be used when the user switches from agentless to agent-based and back
@ -110,7 +111,7 @@ export function useSetupTechnology({
setSelectedSetupTechnology(SetupTechnology.AGENTLESS);
return;
}
if (isAgentlessCloudEnabled && selectedSetupTechnology === SetupTechnology.AGENTLESS) {
if (isAgentlessApiEnabled && selectedSetupTechnology === SetupTechnology.AGENTLESS) {
const nextNewAgentlessPolicy = {
...newAgentlessPolicy,
name: getAgentlessAgentPolicyNameFromPackagePolicyName(packagePolicy.name),
@ -122,7 +123,7 @@ export function useSetupTechnology({
}
}
}, [
isAgentlessCloudEnabled,
isAgentlessApiEnabled,
isEditPage,
newAgentlessPolicy,
packagePolicy.name,
@ -145,10 +146,10 @@ export function useSetupTechnology({
}
};
if (isAgentlessServerlessEnabled) {
if (isDefaultAgentlessPolicyEnabled) {
fetchAgentlessPolicy();
}
}, [isAgentlessServerlessEnabled]);
}, [isDefaultAgentlessPolicyEnabled]);
const handleSetupTechnologyChange = useCallback(
(setupTechnology: SetupTechnology) => {
@ -157,14 +158,14 @@ export function useSetupTechnology({
}
if (setupTechnology === SetupTechnology.AGENTLESS) {
if (isAgentlessCloudEnabled) {
if (isAgentlessApiEnabled) {
setNewAgentPolicy(newAgentlessPolicy as NewAgentPolicy);
setSelectedPolicyTab(SelectedPolicyTab.NEW);
updateAgentPolicies([newAgentlessPolicy] as AgentPolicy[]);
}
// tech debt: remove this when Serverless uses the Agentless API
// https://github.com/elastic/security-team/issues/9781
if (isAgentlessServerlessEnabled) {
if (isDefaultAgentlessPolicyEnabled) {
setNewAgentPolicy(newAgentlessPolicy as AgentPolicy);
updateAgentPolicies([newAgentlessPolicy] as AgentPolicy[]);
setSelectedPolicyTab(SelectedPolicyTab.EXISTING);
@ -183,8 +184,8 @@ export function useSetupTechnology({
[
isAgentlessEnabled,
selectedSetupTechnology,
isAgentlessCloudEnabled,
isAgentlessServerlessEnabled,
isAgentlessApiEnabled,
isDefaultAgentlessPolicyEnabled,
setNewAgentPolicy,
newAgentlessPolicy,
setSelectedPolicyTab,

View file

@ -11,7 +11,7 @@ import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-ser
import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server';
import { isAgentlessCloudEnabled } from '../../../services/utils/agentless';
import { isAgentlessApiEnabled } from '../../../services/utils/agentless';
import { getAgentlessAgentPolicyNameFromPackagePolicyName } from '../../../../common/services/agentless_policy_helper';
@ -65,7 +65,7 @@ export async function renameAgentlessAgentPolicy(
packagePolicy: PackagePolicy,
name: string
) {
if (!isAgentlessCloudEnabled()) {
if (!isAgentlessApiEnabled()) {
return;
}
// If agentless is enabled for cloud, we need to rename the agent policy

View file

@ -111,7 +111,7 @@ describe('Agentless Agent service', () => {
namespace: 'default',
supports_agentless: true,
} as AgentPolicy)
).rejects.toThrowError(new AgentlessAgentCreateError('Agentless agent not supported'));
).rejects.toThrowError(new AgentlessAgentCreateError('missing agentless configuration'));
});
it('should throw AgentlessAgentCreateError if agentless configuration is not found', async () => {

View file

@ -22,7 +22,7 @@ import { appContextService } from '../app_context';
import { listEnrollmentApiKeys } from '../api_keys';
import { listFleetServerHosts } from '../fleet_server_host';
import { prependAgentlessApiBasePathToEndpoint } from '../utils/agentless';
import { prependAgentlessApiBasePathToEndpoint, isAgentlessApiEnabled } from '../utils/agentless';
class AgentlessAgentService {
public async createAgentlessAgent(
@ -33,8 +33,10 @@ class AgentlessAgentService {
const logger = appContextService.getLogger();
logger.debug(`Creating agentless agent ${agentlessAgentPolicy.id}`);
if (!appContextService.getCloud()?.isCloudEnabled) {
logger.error('Creating agentless agent not supported in non-cloud environments');
if (!isAgentlessApiEnabled) {
logger.error(
'Creating agentless agent not supported in non-cloud or non-serverless environments'
);
throw new AgentlessAgentCreateError('Agentless agent not supported');
}
if (!agentlessAgentPolicy.supports_agentless) {

View file

@ -309,6 +309,7 @@ jest.mock('./app_context', () => ({
getExperimentalFeatures: jest.fn().mockReturnValue({
agentless: false,
}),
getConfig: jest.fn(),
getInternalUserSOClientForSpaceId: jest.fn(),
},
}));

View file

@ -43,7 +43,7 @@ import { type InputsOverride, packagePolicyService } from './package_policy';
import { preconfigurePackageInputs } from './package_policy';
import { appContextService } from './app_context';
import type { UpgradeManagedPackagePoliciesResult } from './managed_package_policies';
import { isAgentlessServerlessEnabled } from './utils/agentless';
import { isDefaultAgentlessPolicyEnabled } from './utils/agentless';
interface PreconfigurationResult {
policies: Array<{ id: string; updated_at: string }>;
@ -164,7 +164,7 @@ export async function ensurePreconfiguredPackagesAndPolicies(
}
if (
!isAgentlessServerlessEnabled() &&
!isDefaultAgentlessPolicyEnabled() &&
preconfiguredAgentPolicy?.supports_agentless !== undefined
) {
throw new FleetError(

View file

@ -10,9 +10,9 @@ import { securityMock } from '@kbn/security-plugin/server/mocks';
import { appContextService } from '../app_context';
import {
isAgentlessCloudEnabled,
isAgentlessApiEnabled,
isAgentlessEnabled,
isAgentlessServerlessEnabled,
isDefaultAgentlessPolicyEnabled,
prependAgentlessApiBasePathToEndpoint,
} from './agentless';
@ -23,9 +23,10 @@ mockedAppContextService.getSecuritySetup.mockImplementation(() => ({
...securityMock.createSetup(),
}));
describe('isAgentlessCloudEnabled', () => {
describe('isAgentlessApiEnabled', () => {
afterEach(() => {
jest.clearAllMocks();
mockedAppContextService.getConfig.mockReset();
});
it('should return false if cloud is not enabled', () => {
jest.spyOn(appContextService, 'getConfig').mockReturnValue({
@ -35,7 +36,7 @@ describe('isAgentlessCloudEnabled', () => {
} as any);
jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: false } as any);
expect(isAgentlessCloudEnabled()).toBe(false);
expect(isAgentlessApiEnabled()).toBe(false);
});
it('should return false if cloud is enabled but agentless is not', () => {
@ -46,7 +47,7 @@ describe('isAgentlessCloudEnabled', () => {
} as any);
jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any);
expect(isAgentlessCloudEnabled()).toBe(false);
expect(isAgentlessApiEnabled()).toBe(false);
});
it('should return true if cloud is enabled and agentless is enabled', () => {
@ -57,13 +58,14 @@ describe('isAgentlessCloudEnabled', () => {
} as any);
jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any);
expect(isAgentlessCloudEnabled()).toBe(true);
expect(isAgentlessApiEnabled()).toBe(true);
});
});
describe('isAgentlessServerlessEnabled', () => {
describe('isDefaultAgentlessPolicyEnabled', () => {
afterEach(() => {
jest.clearAllMocks();
mockedAppContextService.getConfig.mockReset();
});
it('should return false if serverless is not enabled', () => {
@ -74,7 +76,7 @@ describe('isAgentlessServerlessEnabled', () => {
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isServerlessEnabled: false } as any);
expect(isAgentlessServerlessEnabled()).toBe(false);
expect(isDefaultAgentlessPolicyEnabled()).toBe(false);
});
it('should return false if serverless is enabled but agentless is not', () => {
@ -83,7 +85,7 @@ describe('isAgentlessServerlessEnabled', () => {
.mockReturnValue({ agentless: false } as any);
jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isServerlessEnabled: true } as any);
expect(isAgentlessServerlessEnabled()).toBe(false);
expect(isDefaultAgentlessPolicyEnabled()).toBe(false);
});
it('should return true if serverless is enabled and agentless is enabled', () => {
@ -92,13 +94,14 @@ describe('isAgentlessServerlessEnabled', () => {
.mockReturnValue({ agentless: true } as any);
jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isServerlessEnabled: true } as any);
expect(isAgentlessServerlessEnabled()).toBe(true);
expect(isDefaultAgentlessPolicyEnabled()).toBe(true);
});
});
describe('isAgentlessEnabled', () => {
afterEach(() => {
jest.clearAllMocks();
mockedAppContextService.getConfig.mockReset();
});
it('should return false if cloud and serverless are not enabled', () => {
@ -138,8 +141,8 @@ describe('isAgentlessEnabled', () => {
it('should return true if cloud is enabled and agentless is enabled', () => {
jest
.spyOn(appContextService, 'getExperimentalFeatures')
.mockReturnValue({ agentless: true } as any);
.spyOn(appContextService, 'getConfig')
.mockReturnValue({ agentless: { enabled: true } } as any);
jest
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isCloudEnabled: true, isServerlessEnabled: false } as any);
@ -163,7 +166,10 @@ describe('prependAgentlessApiBasePathToEndpoint', () => {
jest.clearAllMocks();
});
it('should prepend the agentless api base path to the endpoint', () => {
it('should prepend the agentless api base path to the endpoint with ess if in cloud', () => {
jest
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isCloudEnabled: true, isServerlessEnabled: false } as any);
const agentlessConfig = {
api: {
url: 'https://agentless-api.com',
@ -176,7 +182,27 @@ describe('prependAgentlessApiBasePathToEndpoint', () => {
);
});
it('should prepend the agentless api base path to the endpoint with serverless if in serverless', () => {
jest
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isCloudEnabled: false, isServerlessEnabled: true } as any);
const agentlessConfig = {
api: {
url: 'https://agentless-api.com',
},
} as any;
const endpoint = '/deployments';
expect(prependAgentlessApiBasePathToEndpoint(agentlessConfig, endpoint)).toBe(
'https://agentless-api.com/api/v1/serverless/deployments'
);
});
it('should prepend the agentless api base path to the endpoint with a dynamic path', () => {
jest
.spyOn(appContextService, 'getCloud')
.mockReturnValue({ isCloudEnabled: true, isServerlessEnabled: false } as any);
const agentlessConfig = {
api: {
url: 'https://agentless-api.com',

View file

@ -8,21 +8,23 @@
import { appContextService } from '..';
import type { FleetConfigType } from '../../config';
export const isAgentlessCloudEnabled = () => {
export const isAgentlessApiEnabled = () => {
const cloudSetup = appContextService.getCloud();
return Boolean(cloudSetup?.isCloudEnabled && appContextService.getConfig()?.agentless?.enabled);
const isHosted = cloudSetup?.isCloudEnabled || cloudSetup?.isServerlessEnabled;
return Boolean(isHosted && appContextService.getConfig()?.agentless?.enabled);
};
export const isAgentlessServerlessEnabled = () => {
export const isDefaultAgentlessPolicyEnabled = () => {
const cloudSetup = appContextService.getCloud();
return Boolean(
cloudSetup?.isServerlessEnabled && appContextService.getExperimentalFeatures().agentless
);
};
export const isAgentlessEnabled = () => {
return isAgentlessCloudEnabled() || isAgentlessServerlessEnabled();
return isAgentlessApiEnabled() || isDefaultAgentlessPolicyEnabled();
};
const AGENTLESS_API_BASE_PATH = '/api/v1/ess';
const AGENTLESS_ESS_API_BASE_PATH = '/api/v1/ess';
const AGENTLESS_SERVERLESS_API_BASE_PATH = '/api/v1/serverless';
type AgentlessApiEndpoints = '/deployments' | `/deployments/${string}`;
@ -30,5 +32,9 @@ export const prependAgentlessApiBasePathToEndpoint = (
agentlessConfig: FleetConfigType['agentless'],
endpoint: AgentlessApiEndpoints
) => {
return `${agentlessConfig.api.url}${AGENTLESS_API_BASE_PATH}${endpoint}`;
const cloudSetup = appContextService.getCloud();
const endpointPrefix = cloudSetup?.isServerlessEnabled
? AGENTLESS_SERVERLESS_API_BASE_PATH
: AGENTLESS_ESS_API_BASE_PATH;
return `${agentlessConfig.api.url}${endpointPrefix}${endpoint}`;
};

View file

@ -0,0 +1,34 @@
/*
* 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 { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants';
import { CA_CERT_PATH, KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils';
import { createTestConfig } from '../../config.base';
export default createTestConfig({
serverlessProject: 'security',
junit: {
reportName: 'Serverless Security Cloud Security Agentless API Onboarding Functional Tests',
},
kbnServerArgs: [
`--xpack.fleet.packages.0.name=cloud_security_posture`,
`--xpack.fleet.packages.0.version=${CLOUD_CREDENTIALS_PACKAGE_VERSION}`,
`--xpack.fleet.agents.fleet_server.hosts=["https://ftr.kibana:8220"]`,
`--xpack.fleet.internal.fleetServerStandalone=true`,
// Agentless Configuration based on Serverless Security Dev Yaml - config/serverless.security.dev.yml
`--xpack.fleet.agentless.enabled=true`,
`--xpack.fleet.agentless.api.url=http://localhost:8089`,
`--xpack.fleet.agentless.api.tls.certificate=${KBN_CERT_PATH}`,
`--xpack.fleet.agentless.api.tls.key=${KBN_KEY_PATH}`,
`--xpack.fleet.agentless.api.tls.ca=${CA_CERT_PATH}`,
`--xpack.cloud.serverless.project_id=some_fake_project_id`,
],
// load tests in the index file
testFiles: [require.resolve('./ftr/cloud_security_posture/agentless_api')],
});

View file

@ -0,0 +1,97 @@
/*
* 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 { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants';
import * as http from 'http';
import expect from '@kbn/expect';
import { setupMockServer } from './mock_agentless_api';
import type { FtrProviderContext } from '../../../../../ftr_provider_context';
export default function ({ getPageObjects, getService }: FtrProviderContext) {
const mockAgentlessApiService = setupMockServer();
const pageObjects = getPageObjects([
'svlCommonPage',
'cspSecurity',
'security',
'header',
'cisAddIntegration',
]);
const CIS_AWS_OPTION_TEST_ID = 'cisAwsTestId';
const AWS_SINGLE_ACCOUNT_TEST_ID = 'awsSingleTestId';
describe('Agentless API Serverless', function () {
let mockApiServer: http.Server;
let cisIntegration: typeof pageObjects.cisAddIntegration;
before(async () => {
mockApiServer = mockAgentlessApiService.listen(8089); // Start the usage api mock server on port 8089
await pageObjects.svlCommonPage.loginAsAdmin();
cisIntegration = pageObjects.cisAddIntegration;
});
after(async () => {
mockApiServer.close();
});
it(`should create agentless-agent`, async () => {
const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`;
await cisIntegration.navigateToAddIntegrationCspmWithVersionPage(
CLOUD_CREDENTIALS_PACKAGE_VERSION
);
await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(AWS_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.inputIntegrationName(integrationPolicyName);
await cisIntegration.selectSetupTechnology('agentless');
await cisIntegration.selectAwsCredentials('direct');
await pageObjects.header.waitUntilLoadingHasFinished();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
await cisIntegration.navigateToIntegrationCspList();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(await cisIntegration.getFirstCspmIntegrationPageIntegration()).to.be(
integrationPolicyName
);
expect(await cisIntegration.getFirstCspmIntegrationPageAgent()).to.be(
`Agentless policy for ${integrationPolicyName}`
);
});
it(`should create default agent-based agent`, async () => {
const integrationPolicyName = `cloud_security_posture-${new Date().toISOString()}`;
await cisIntegration.navigateToAddIntegrationCspmWithVersionPage(
CLOUD_CREDENTIALS_PACKAGE_VERSION
);
await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(AWS_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.inputIntegrationName(integrationPolicyName);
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
const agentPolicyName = await cisIntegration.getAgentBasedPolicyValue();
await cisIntegration.navigateToIntegrationCspList();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(await cisIntegration.getFirstCspmIntegrationPageIntegration()).to.be(
integrationPolicyName
);
expect(await cisIntegration.getFirstCspmIntegrationPageAgent()).to.be(agentPolicyName);
});
});
}

View file

@ -0,0 +1,15 @@
/*
* 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 { FtrProviderContext } from '../../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('cloud_security_posture', function () {
this.tags(['cloud_security_posture_agentless']);
loadTestFile(require.resolve('./create_agent'));
});
}

View file

@ -0,0 +1,28 @@
/*
* 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 { createServer } from '@mswjs/http-middleware';
import { http, HttpResponse, StrictResponse } from 'msw';
export const setupMockServer = () => {
const server = createServer(deploymentHandler);
return server;
};
interface AgentlessApiResponse {
status: number;
}
const deploymentHandler = http.post(
'api/v1/serverless/deployments',
async ({ request }): Promise<StrictResponse<AgentlessApiResponse>> => {
return HttpResponse.json({
status: 200,
});
}
);