Skip to content

Commit

Permalink
[Security Solution] add package_policy_id to .fleet-policies inputs (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
joeypoon authored Aug 15, 2022
1 parent 64c1d3c commit 2c96643
Show file tree
Hide file tree
Showing 17 changed files with 370 additions and 44 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/types/models/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface NewAgentPolicy {
data_output_id?: string | null;
monitoring_output_id?: string | null;
download_source_id?: string | null;
schema_version?: string;
}

export interface AgentPolicy extends Omit<NewAgentPolicy, 'id'> {
Expand Down Expand Up @@ -60,6 +61,7 @@ export interface FullAgentPolicyInput {
type: string;
data_stream: { namespace: string };
use_output: string;
package_policy_id: string;
meta?: {
package?: Pick<PackagePolicyPackage, 'name' | 'version'>;
[key: string]: unknown;
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/server/constants/fleet_es_assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const meta = getESAssetMetadata();

export const FLEET_INSTALL_FORMAT_VERSION = '1.0.0';

export const FLEET_AGENT_POLICIES_SCHEMA_VERSION = '1.0.0';

export const FLEET_FINAL_PIPELINE_ID = '.fleet_final_pipeline-1';

export const FLEET_GLOBALS_COMPONENT_TEMPLATE_NAME = '.fleet_globals-1';
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,5 @@ export {
FLEET_FINAL_PIPELINE_CONTENT,
FLEET_FINAL_PIPELINE_VERSION,
FLEET_INSTALL_FORMAT_VERSION,
FLEET_AGENT_POLICIES_SCHEMA_VERSION,
} from './fleet_es_assets';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* 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 uuid from 'uuid/v4';

import type {
KibanaRequest,
SavedObjectsClientContract,
ElasticsearchClient,
} from '@kbn/core/server';
import * as kbnTestServer from '@kbn/core/test_helpers/kbn_server';
import type { SearchTotalHits } from '@elastic/elasticsearch/lib/api/types';

import { AGENT_POLICY_SAVED_OBJECT_TYPE, FLEET_AGENT_POLICIES_SCHEMA_VERSION } from '../constants';
import { upgradeAgentPolicySchemaVersion } from '../services/setup/upgrade_agent_policy_schema_version';
import { AGENT_POLICY_INDEX } from '../../common';
import { agentPolicyService } from '../services';

import { useDockerRegistry, waitForFleetSetup } from './helpers';

const fakeRequest = {
headers: {},
getBasePath: () => '',
path: '/',
route: { settings: {} },
url: {
href: '/',
},
raw: {
req: {
url: '/',
},
},
} as unknown as KibanaRequest;

describe('upgrade agent policy schema version', () => {
let esServer: kbnTestServer.TestElasticsearchUtils;
let kbnServer: kbnTestServer.TestKibanaUtils;

const registryUrl = useDockerRegistry();

const startServers = async () => {
const { startES } = kbnTestServer.createTestServers({
adjustTimeout: (t) => jest.setTimeout(t),
settings: {
es: {
license: 'trial',
},
kbn: {},
},
});

esServer = await startES();
const startKibana = async () => {
const root = kbnTestServer.createRootWithCorePlugins(
{
xpack: {
fleet: {
registryUrl,
packages: [
{
name: 'fleet_server',
version: 'latest',
},
{
name: 'system',
version: 'latest',
},
],
},
},
},
{ oss: false }
);

await root.preboot();
const coreSetup = await root.setup();
const coreStart = await root.start();

return {
root,
coreSetup,
coreStart,
stop: async () => await root.shutdown(),
};
};
kbnServer = await startKibana();

await waitForFleetSetup(kbnServer.root);
};

const stopServers = async () => {
if (kbnServer) {
await kbnServer.stop();
}

if (esServer) {
await esServer.stop();
}

await new Promise((res) => setTimeout(res, 10000));
};

// Share the same servers for all the test to make test a lot faster (but test are not isolated anymore)
beforeAll(async () => {
await startServers();
});

afterAll(async () => {
await stopServers();
});

describe('with package installed with outdated schema version', () => {
let soClient: SavedObjectsClientContract;
let esClient: ElasticsearchClient;

beforeAll(async () => {
soClient = kbnServer.coreStart.savedObjects.getScopedClient(fakeRequest, {
excludedWrappers: ['security'],
});
esClient = kbnServer.coreStart.elasticsearch.client.asInternalUser;
});

it('should correctly upgrade schema version', async () => {
await esClient.indices.create({ index: AGENT_POLICY_INDEX });
let esRes = await esClient.search({ index: AGENT_POLICY_INDEX });
expect((esRes.hits.total as SearchTotalHits).value).toBe(0);

await soClient.bulkCreate([
// up-to-date schema_version
{
type: AGENT_POLICY_SAVED_OBJECT_TYPE,
id: uuid(),
attributes: {
schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION,
revision: 1,
},
},
// out-of-date schema_version
{
type: AGENT_POLICY_SAVED_OBJECT_TYPE,
id: uuid(),
attributes: {
schema_version: '0.0.1',
revision: 1,
},
},
// missing schema_version
{
type: AGENT_POLICY_SAVED_OBJECT_TYPE,
id: uuid(),
attributes: {
revision: 1,
},
},
]);

await upgradeAgentPolicySchemaVersion(soClient);

const policies = await agentPolicyService.list(soClient, {
kuery: `${AGENT_POLICY_SAVED_OBJECT_TYPE}.schema_version:${FLEET_AGENT_POLICIES_SCHEMA_VERSION}`,
});
// all 3 should be up-to-date after upgrade
expect(policies.total).toBe(3);

esRes = await esClient.search({
index: AGENT_POLICY_INDEX,
body: { query: { match: { revision_idx: 2 } } },
});
// since only 2 were updated, only 2 should be written
expect((esRes.hits.total as SearchTotalHits).value).toBe(2);
});
});
});
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const getSavedObjectTypes = (
mappings: {
properties: {
name: { type: 'keyword' },
schema_version: { type: 'version' },
description: { type: 'text' },
namespace: { type: 'keyword' },
is_managed: { type: 'boolean' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
{
id: 'test-logs-some-uuid',
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
revision: 1,
type: 'test-logs',
data_stream: { namespace: 'default' },
Expand Down Expand Up @@ -235,6 +236,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
{
id: 'test-logs-some-uuid',
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
revision: 1,
type: 'test-logs',
data_stream: { namespace: 'default' },
Expand All @@ -261,6 +263,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
{
id: 'test-metrics-some-template-some-uuid',
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
revision: 1,
type: 'test-metrics',
data_stream: { namespace: 'default' },
Expand All @@ -283,6 +286,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
{
id: 'some-uuid',
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
revision: 1,
type: 'test-metrics',
data_stream: { namespace: 'default' },
Expand Down Expand Up @@ -330,6 +334,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
{
id: 'test-logs-some-uuid',
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
revision: 1,
type: 'test-logs',
data_stream: { namespace: 'default' },
Expand Down Expand Up @@ -362,6 +367,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
{
id: 'test-logs-some-uuid',
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
revision: 1,
type: 'test-logs',
data_stream: { namespace: 'default' },
Expand Down Expand Up @@ -425,6 +431,7 @@ describe('Fleet - storedPackagePoliciesToAgentInputs', () => {
id: 'test-logs-some-uuid',
revision: 1,
name: 'mock-package-policy',
package_policy_id: 'some-uuid',
type: 'test-logs',
data_stream: { namespace: 'default' },
use_output: 'default',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const storedPackagePolicyToAgentInputs = (
namespace: packagePolicy.namespace || 'default',
},
use_output: outputId,
package_policy_id: packagePolicy.id,
...(input.compiled_input || {}),
...(input.streams.length
? {
Expand Down
41 changes: 29 additions & 12 deletions x-pack/plugins/fleet/server/services/agent_policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import type {

import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../constants';

import { AGENT_POLICY_INDEX } from '../../common';

import { agentPolicyService } from './agent_policy';
import { agentPolicyUpdateEventHandler } from './agent_policy_update';

Expand Down Expand Up @@ -67,7 +69,6 @@ jest.mock('./agents');
jest.mock('./package_policy');
jest.mock('./app_context');
jest.mock('./agent_policies/full_agent_policy');
jest.mock('uuid/v5');

const mockedAppContextService = appContextService as jest.Mocked<typeof appContextService>;
const mockedOutputService = outputService as jest.Mocked<typeof outputService>;
Expand Down Expand Up @@ -383,11 +384,15 @@ describe('agent policy', () => {
mockedOutputService.getDefaultDataOutputId.mockResolvedValue('default-output');
mockedGetFullAgentPolicy.mockResolvedValue(null);

soClient.get.mockResolvedValue({
const mockSo = {
attributes: {},
id: 'policy123',
type: 'mocked',
references: [],
};
soClient.get.mockResolvedValue(mockSo);
soClient.bulkGet.mockResolvedValue({
saved_objects: [mockSo],
});
await agentPolicyService.deployPolicy(soClient, 'policy123');

Expand All @@ -409,24 +414,36 @@ describe('agent policy', () => {
],
} as FullAgentPolicy);

soClient.get.mockResolvedValue({
const mockSo = {
attributes: {},
id: 'policy123',
type: 'mocked',
references: [],
};
soClient.get.mockResolvedValue(mockSo);
soClient.bulkGet.mockResolvedValue({
saved_objects: [mockSo],
});
await agentPolicyService.deployPolicy(soClient, 'policy123');

expect(esClient.create).toBeCalledWith(
expect(esClient.bulk).toBeCalledWith(
expect.objectContaining({
index: '.fleet-policies',
body: expect.objectContaining({
'@timestamp': expect.anything(),
data: { id: 'policy123', inputs: [{ id: 'input-123' }], revision: 1 },
default_fleet_server: false,
policy_id: 'policy123',
revision_idx: 1,
}),
index: AGENT_POLICY_INDEX,
body: [
expect.objectContaining({
index: {
_id: expect.anything(),
},
}),
expect.objectContaining({
'@timestamp': expect.anything(),
data: { id: 'policy123', inputs: [{ id: 'input-123' }], revision: 1 },
default_fleet_server: false,
policy_id: 'policy123',
revision_idx: 1,
}),
],
refresh: 'wait_for',
})
);
});
Expand Down
Loading

0 comments on commit 2c96643

Please sign in to comment.