kibana/x-pack/test/security_solution_endpoint_api_int/apis/package.ts
Spencer f466ebf1a3
[esArchiver] drop support for --dir, use repo-relative paths instead (#101345)
Co-authored-by: spalger <spalger@users.noreply.github.com>
2021-06-08 17:37:42 -04:00

252 lines
8.8 KiB
TypeScript

/*
* 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 expect from '@kbn/expect';
import {
ResolverPaginatedEvents,
SafeEndpointEvent,
} from '../../../plugins/security_solution/common/endpoint/types';
import { eventsIndexPattern } from '../../../plugins/security_solution/common/endpoint/constants';
import {
EndpointDocGenerator,
Event,
} from '../../../plugins/security_solution/common/endpoint/generate_data';
import { FtrProviderContext } from '../ftr_provider_context';
import { InsertedEvents, processEventsIndex } from '../services/resolver';
import { deleteEventsStream } from './data_stream_helper';
interface EventIngested {
event: {
ingested: number;
};
}
interface NetworkEvent {
source: {
geo?: {
country_name: string;
};
};
destination: {
geo?: {
country_name: string;
};
};
}
const networkIndex = 'logs-endpoint.events.network-default';
export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');
const resolver = getService('resolverGenerator');
const es = getService('es');
const generator = new EndpointDocGenerator('data');
const searchForID = async <T>(id: string) => {
return es.search<T>({
index: eventsIndexPattern,
body: {
query: {
bool: {
filter: [
{
ids: {
values: [id],
},
},
],
},
},
},
});
};
describe('Endpoint package', () => {
describe('network processors', () => {
let networkIndexData: InsertedEvents;
after(async () => {
await resolver.deleteData(networkIndexData);
});
it('handles events without the `network.protocol` field being defined', async () => {
const eventWithoutNetworkObject = generator.generateEvent({
eventsDataStream: EndpointDocGenerator.createDataStreamFromIndex(networkIndex),
});
// ensure that `network.protocol` does not exist in the event to test that the pipeline handles those type of events
delete eventWithoutNetworkObject.network;
// this call will fail if the pipeline fails
networkIndexData = await resolver.insertEvents([eventWithoutNetworkObject], networkIndex);
const eventWithBothIPs = await searchForID<SafeEndpointEvent>(
networkIndexData.eventsInfo[0]._id
);
// ensure that the event was inserted into ES
expect(eventWithBothIPs.body.hits.hits[0]._source?.event?.id).to.be(
eventWithoutNetworkObject.event?.id
);
});
});
describe('dns processor', () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/endpoint/pipeline/dns', {
useCreate: true,
});
});
after(async () => {
await deleteEventsStream(getService);
});
it('does not set dns.question.type if it is already populated', async () => {
// this id comes from the es archive file endpoint/pipeline/dns
const id = 'LrLSOVHVsFY94TAi++++++eF';
const { body }: { body: ResolverPaginatedEvents } = await supertest
.post(`/api/endpoint/resolver/events`)
.query({ limit: 1 })
.set('kbn-xsrf', 'xxx')
.send({
filter: JSON.stringify({
bool: {
filter: [{ term: { 'event.id': id } }],
},
}),
indexPatterns: [eventsIndexPattern],
// these times are taken from the es archiver data endpoint/pipeline/dns for this specific event
timeRange: {
from: '2020-10-01T13:50:15.14364600Z',
to: '2020-10-01T13:50:15.14364600Z',
},
})
.expect(200);
expect(body.events.length).to.eql(1);
expect((body.events[0] as SafeEndpointEvent).dns?.question?.name).to.eql('www.google.com');
expect((body.events[0] as SafeEndpointEvent).dns?.question?.type).to.eql('INVALID_VALUE');
});
it('sets dns.question.type if it is not populated', async () => {
// this id comes from the es archive file endpoint/pipeline/dns
const id = 'LrLSOVHVsFY94TAi++++++eP';
const { body }: { body: ResolverPaginatedEvents } = await supertest
.post(`/api/endpoint/resolver/events`)
.query({ limit: 1 })
.set('kbn-xsrf', 'xxx')
.send({
filter: JSON.stringify({
bool: {
filter: [{ term: { 'event.id': id } }],
},
}),
indexPatterns: [eventsIndexPattern],
// these times are taken from the es archiver data endpoint/pipeline/dns for this specific event
timeRange: {
from: '2020-10-01T13:50:15.44516300Z',
to: '2020-10-01T13:50:15.44516300Z',
},
})
.expect(200);
expect(body.events.length).to.eql(1);
expect((body.events[0] as SafeEndpointEvent).dns?.question?.name).to.eql('www.aol.com');
// This value is parsed out of the message field in the event. type 28 = AAAA
expect((body.events[0] as SafeEndpointEvent).dns?.question?.type).to.eql('AAAA');
});
});
describe('ingested processor', () => {
let event: Event;
let genData: InsertedEvents;
before(async () => {
event = generator.generateEvent({
eventsDataStream: EndpointDocGenerator.createDataStreamFromIndex(processEventsIndex),
});
genData = await resolver.insertEvents([event], processEventsIndex);
});
after(async () => {
await resolver.deleteData(genData);
});
it('sets the event.ingested field', async () => {
const resp = await searchForID<EventIngested>(genData.eventsInfo[0]._id);
expect(resp.body.hits.hits[0]._source?.event.ingested).to.not.be(undefined);
});
});
describe('geoip processor', () => {
let processIndexData: InsertedEvents;
let networkIndexData: InsertedEvents;
before(async () => {
// 46.239.193.5 should be in Iceland
// 8.8.8.8 should be in the US
const eventWithBothIPsNetwork = generator.generateEvent({
extensions: { source: { ip: '8.8.8.8' }, destination: { ip: '46.239.193.5' } },
eventsDataStream: EndpointDocGenerator.createDataStreamFromIndex(networkIndex),
});
const eventWithSourceOnlyNetwork = generator.generateEvent({
extensions: { source: { ip: '8.8.8.8' } },
eventsDataStream: EndpointDocGenerator.createDataStreamFromIndex(networkIndex),
});
networkIndexData = await resolver.insertEvents(
[eventWithBothIPsNetwork, eventWithSourceOnlyNetwork],
networkIndex
);
const eventWithBothIPsProcess = generator.generateEvent({
extensions: { source: { ip: '8.8.8.8' }, destination: { ip: '46.239.193.5' } },
eventsDataStream: EndpointDocGenerator.createDataStreamFromIndex(processEventsIndex),
});
processIndexData = await resolver.insertEvents(
[eventWithBothIPsProcess],
processEventsIndex
);
});
after(async () => {
await resolver.deleteData(networkIndexData);
await resolver.deleteData(processIndexData);
});
it('sets the geoip fields', async () => {
const eventWithBothIPs = await searchForID<NetworkEvent>(
networkIndexData.eventsInfo[0]._id
);
// Should be 'United States'
expect(eventWithBothIPs.body.hits.hits[0]._source?.source.geo?.country_name).to.not.be(
undefined
);
// should be 'Iceland'
expect(eventWithBothIPs.body.hits.hits[0]._source?.destination.geo?.country_name).to.not.be(
undefined
);
const eventWithSourceOnly = await searchForID<NetworkEvent>(
networkIndexData.eventsInfo[1]._id
);
// Should be 'United States'
expect(eventWithBothIPs.body.hits.hits[0]._source?.source.geo?.country_name).to.not.be(
undefined
);
expect(eventWithSourceOnly.body.hits.hits[0]._source?.destination?.geo).to.be(undefined);
});
it('does not set geoip fields for events in indices other than the network index', async () => {
const eventWithBothIPs = await searchForID<NetworkEvent>(
processIndexData.eventsInfo[0]._id
);
expect(eventWithBothIPs.body.hits.hits[0]._source?.source.geo).to.be(undefined);
expect(eventWithBothIPs.body.hits.hits[0]._source?.destination.geo).to.be(undefined);
});
});
});
}