mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Telemetry][Security Solution] Enrich endpoint alerts with license info (#188760)
This commit is contained in:
parent
47842f9c43
commit
aa6aa26866
5 changed files with 43 additions and 11 deletions
|
@ -22,8 +22,8 @@ const asyncUnlink = Util.promisify(Fs.unlink);
|
||||||
*/
|
*/
|
||||||
export async function eventually<T>(
|
export async function eventually<T>(
|
||||||
cb: () => Promise<T>,
|
cb: () => Promise<T>,
|
||||||
duration: number = 60000,
|
duration: number = 120000,
|
||||||
interval: number = 1000
|
interval: number = 3000
|
||||||
) {
|
) {
|
||||||
let elapsed = 0;
|
let elapsed = 0;
|
||||||
|
|
||||||
|
|
|
@ -148,8 +148,7 @@ describe('telemetry tasks', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// FLAKY: https://github.com/elastic/kibana/issues/187719
|
describe('detection-rules', () => {
|
||||||
describe.skip('detection-rules', () => {
|
|
||||||
it('should execute when scheduled', async () => {
|
it('should execute when scheduled', async () => {
|
||||||
await mockAndScheduleDetectionRulesTask();
|
await mockAndScheduleDetectionRulesTask();
|
||||||
|
|
||||||
|
@ -263,7 +262,7 @@ describe('telemetry tasks', () => {
|
||||||
// wait until the events are sent to the telemetry server
|
// wait until the events are sent to the telemetry server
|
||||||
const body = await eventually(async () => {
|
const body = await eventually(async () => {
|
||||||
const found = mockedAxiosPost.mock.calls.find(([url]) => {
|
const found = mockedAxiosPost.mock.calls.find(([url]) => {
|
||||||
return url.startsWith(ENDPOINT_STAGING) && url.endsWith('alerts-endpoint');
|
return url.startsWith(ENDPOINT_STAGING) && url.endsWith(TelemetryChannel.ENDPOINT_ALERTS);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(found).not.toBeFalsy();
|
expect(found).not.toBeFalsy();
|
||||||
|
@ -274,6 +273,25 @@ describe('telemetry tasks', () => {
|
||||||
expect(body).not.toBeFalsy();
|
expect(body).not.toBeFalsy();
|
||||||
expect(body.Endpoint).not.toBeFalsy();
|
expect(body.Endpoint).not.toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should enrich with license info', async () => {
|
||||||
|
await mockAndScheduleEndpointDiagnosticsTask();
|
||||||
|
|
||||||
|
// wait until the events are sent to the telemetry server
|
||||||
|
const body = await eventually(async () => {
|
||||||
|
const found = mockedAxiosPost.mock.calls.find(([url]) => {
|
||||||
|
return url.startsWith(ENDPOINT_STAGING) && url.endsWith(TelemetryChannel.ENDPOINT_ALERTS);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(found).not.toBeFalsy();
|
||||||
|
|
||||||
|
return JSON.parse((found ? found[1] : '{}') as string);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(body).not.toBeFalsy();
|
||||||
|
expect(body.license).not.toBeFalsy();
|
||||||
|
expect(body.license.status).not.toBeFalsy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('endpoint-meta-telemetry', () => {
|
describe('endpoint-meta-telemetry', () => {
|
||||||
|
@ -680,8 +698,7 @@ describe('telemetry tasks', () => {
|
||||||
expect(body.file).toStrictEqual(alertsDetectionsRequest.file);
|
expect(body.file).toStrictEqual(alertsDetectionsRequest.file);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Flaky: https://github.com/elastic/kibana/issues/188234
|
it('should manage runtime errors searching endpoint metrics', async () => {
|
||||||
it.skip('should manage runtime errors searching endpoint metrics', async () => {
|
|
||||||
const errorMessage = 'Something went wront';
|
const errorMessage = 'Something went wront';
|
||||||
|
|
||||||
async function* mockedGenerator(
|
async function* mockedGenerator(
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { TelemetryChannel, TelemetryCounter } from './types';
|
||||||
import * as collections from './collections_helpers';
|
import * as collections from './collections_helpers';
|
||||||
import { CachedSubject, retryOnError$ } from './rxjs_helpers';
|
import { CachedSubject, retryOnError$ } from './rxjs_helpers';
|
||||||
import { SenderUtils } from './sender_helpers';
|
import { SenderUtils } from './sender_helpers';
|
||||||
import { newTelemetryLogger } from './helpers';
|
import { copyLicenseFields, newTelemetryLogger } from './helpers';
|
||||||
import { type TelemetryLogger } from './telemetry_logger';
|
import { type TelemetryLogger } from './telemetry_logger';
|
||||||
|
|
||||||
export const DEFAULT_QUEUE_CONFIG: QueueConfig = {
|
export const DEFAULT_QUEUE_CONFIG: QueueConfig = {
|
||||||
|
@ -291,6 +291,14 @@ export class AsyncTelemetryEventsSender implements IAsyncTelemetryEventsSender {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.channel === TelemetryChannel.ENDPOINT_ALERTS) {
|
||||||
|
const licenseInfo = this.telemetryReceiver?.getLicenseInfo();
|
||||||
|
additional = {
|
||||||
|
...additional,
|
||||||
|
...(licenseInfo ? { license: copyLicenseFields(licenseInfo) } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
event.payload = {
|
event.payload = {
|
||||||
...event.payload,
|
...event.payload,
|
||||||
...additional,
|
...additional,
|
||||||
|
|
|
@ -102,6 +102,8 @@ export interface ITelemetryReceiver {
|
||||||
|
|
||||||
fetchClusterInfo(): Promise<ESClusterInfo>;
|
fetchClusterInfo(): Promise<ESClusterInfo>;
|
||||||
|
|
||||||
|
getLicenseInfo(): Nullable<ESLicense>;
|
||||||
|
|
||||||
fetchLicenseInfo(): Promise<Nullable<ESLicense>>;
|
fetchLicenseInfo(): Promise<Nullable<ESLicense>>;
|
||||||
|
|
||||||
closePointInTime(pitId: string): Promise<void>;
|
closePointInTime(pitId: string): Promise<void>;
|
||||||
|
@ -248,6 +250,7 @@ export class TelemetryReceiver implements ITelemetryReceiver {
|
||||||
private getIndexForType?: (type: string) => string;
|
private getIndexForType?: (type: string) => string;
|
||||||
private alertsIndex?: string;
|
private alertsIndex?: string;
|
||||||
private clusterInfo?: ESClusterInfo;
|
private clusterInfo?: ESClusterInfo;
|
||||||
|
private licenseInfo?: Nullable<ESLicense>;
|
||||||
private processTreeFetcher?: Fetcher;
|
private processTreeFetcher?: Fetcher;
|
||||||
private packageService?: PackageService;
|
private packageService?: PackageService;
|
||||||
private experimentalFeatures: ExperimentalFeatures | undefined;
|
private experimentalFeatures: ExperimentalFeatures | undefined;
|
||||||
|
@ -280,6 +283,7 @@ export class TelemetryReceiver implements ITelemetryReceiver {
|
||||||
this.soClient =
|
this.soClient =
|
||||||
core?.savedObjects.createInternalRepository() as unknown as SavedObjectsClientContract;
|
core?.savedObjects.createInternalRepository() as unknown as SavedObjectsClientContract;
|
||||||
this.clusterInfo = await this.fetchClusterInfo();
|
this.clusterInfo = await this.fetchClusterInfo();
|
||||||
|
this.licenseInfo = await this.fetchLicenseInfo();
|
||||||
this.experimentalFeatures = endpointContextService?.experimentalFeatures;
|
this.experimentalFeatures = endpointContextService?.experimentalFeatures;
|
||||||
const elasticsearch = core?.elasticsearch.client as unknown as IScopedClusterClient;
|
const elasticsearch = core?.elasticsearch.client as unknown as IScopedClusterClient;
|
||||||
this.processTreeFetcher = new Fetcher(elasticsearch);
|
this.processTreeFetcher = new Fetcher(elasticsearch);
|
||||||
|
@ -291,6 +295,10 @@ export class TelemetryReceiver implements ITelemetryReceiver {
|
||||||
return this.clusterInfo;
|
return this.clusterInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getLicenseInfo(): Nullable<ESLicense> {
|
||||||
|
return this.licenseInfo;
|
||||||
|
}
|
||||||
|
|
||||||
public getAlertsIndex(): string | undefined {
|
public getAlertsIndex(): string | undefined {
|
||||||
return this.alertsIndex;
|
return this.alertsIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
import type { Logger } from '@kbn/core/server';
|
import type { Logger } from '@kbn/core/server';
|
||||||
import { newTelemetryLogger, getPreviousDiagTaskTimestamp } from '../helpers';
|
import { newTelemetryLogger, getPreviousDiagTaskTimestamp } from '../helpers';
|
||||||
import type { ITelemetryEventsSender } from '../sender';
|
import type { ITelemetryEventsSender } from '../sender';
|
||||||
import type { TelemetryEvent } from '../types';
|
import { TelemetryChannel, type TelemetryEvent } from '../types';
|
||||||
import type { ITelemetryReceiver } from '../receiver';
|
import type { ITelemetryReceiver } from '../receiver';
|
||||||
import type { TaskExecutionPeriod } from '../task';
|
import type { TaskExecutionPeriod } from '../task';
|
||||||
import type { ITaskMetricsService } from '../task_metrics.types';
|
import type { ITaskMetricsService } from '../task_metrics.types';
|
||||||
import { TELEMETRY_CHANNEL_ENDPOINT_ALERTS } from '../constants';
|
|
||||||
import { copyAllowlistedFields, filterList } from '../filterlists';
|
import { copyAllowlistedFields, filterList } from '../filterlists';
|
||||||
|
|
||||||
export function createTelemetryDiagnosticsTaskConfig() {
|
export function createTelemetryDiagnosticsTaskConfig() {
|
||||||
|
@ -65,7 +64,7 @@ export function createTelemetryDiagnosticsTaskConfig() {
|
||||||
log.l('Sending diagnostic alerts', {
|
log.l('Sending diagnostic alerts', {
|
||||||
alerts_count: alerts.length,
|
alerts_count: alerts.length,
|
||||||
});
|
});
|
||||||
await sender.sendOnDemand(TELEMETRY_CHANNEL_ENDPOINT_ALERTS, processedAlerts);
|
sender.sendAsync(TelemetryChannel.ENDPOINT_ALERTS, processedAlerts);
|
||||||
}
|
}
|
||||||
|
|
||||||
await taskMetricsService.end(trace);
|
await taskMetricsService.end(trace);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue