[Telemetry][Security Solution] Enrich endpoint alerts with license info (#188760)

This commit is contained in:
Sebastián Zaffarano 2024-07-22 12:56:27 +02:00 committed by GitHub
parent 47842f9c43
commit aa6aa26866
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 43 additions and 11 deletions

View file

@ -22,8 +22,8 @@ const asyncUnlink = Util.promisify(Fs.unlink);
*/
export async function eventually<T>(
cb: () => Promise<T>,
duration: number = 60000,
interval: number = 1000
duration: number = 120000,
interval: number = 3000
) {
let elapsed = 0;

View file

@ -148,8 +148,7 @@ describe('telemetry tasks', () => {
});
});
// FLAKY: https://github.com/elastic/kibana/issues/187719
describe.skip('detection-rules', () => {
describe('detection-rules', () => {
it('should execute when scheduled', async () => {
await mockAndScheduleDetectionRulesTask();
@ -263,7 +262,7 @@ describe('telemetry tasks', () => {
// 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('alerts-endpoint');
return url.startsWith(ENDPOINT_STAGING) && url.endsWith(TelemetryChannel.ENDPOINT_ALERTS);
});
expect(found).not.toBeFalsy();
@ -274,6 +273,25 @@ describe('telemetry tasks', () => {
expect(body).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', () => {
@ -680,8 +698,7 @@ describe('telemetry tasks', () => {
expect(body.file).toStrictEqual(alertsDetectionsRequest.file);
});
// Flaky: https://github.com/elastic/kibana/issues/188234
it.skip('should manage runtime errors searching endpoint metrics', async () => {
it('should manage runtime errors searching endpoint metrics', async () => {
const errorMessage = 'Something went wront';
async function* mockedGenerator(

View file

@ -21,7 +21,7 @@ import { TelemetryChannel, TelemetryCounter } from './types';
import * as collections from './collections_helpers';
import { CachedSubject, retryOnError$ } from './rxjs_helpers';
import { SenderUtils } from './sender_helpers';
import { newTelemetryLogger } from './helpers';
import { copyLicenseFields, newTelemetryLogger } from './helpers';
import { type TelemetryLogger } from './telemetry_logger';
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,
...additional,

View file

@ -102,6 +102,8 @@ export interface ITelemetryReceiver {
fetchClusterInfo(): Promise<ESClusterInfo>;
getLicenseInfo(): Nullable<ESLicense>;
fetchLicenseInfo(): Promise<Nullable<ESLicense>>;
closePointInTime(pitId: string): Promise<void>;
@ -248,6 +250,7 @@ export class TelemetryReceiver implements ITelemetryReceiver {
private getIndexForType?: (type: string) => string;
private alertsIndex?: string;
private clusterInfo?: ESClusterInfo;
private licenseInfo?: Nullable<ESLicense>;
private processTreeFetcher?: Fetcher;
private packageService?: PackageService;
private experimentalFeatures: ExperimentalFeatures | undefined;
@ -280,6 +283,7 @@ export class TelemetryReceiver implements ITelemetryReceiver {
this.soClient =
core?.savedObjects.createInternalRepository() as unknown as SavedObjectsClientContract;
this.clusterInfo = await this.fetchClusterInfo();
this.licenseInfo = await this.fetchLicenseInfo();
this.experimentalFeatures = endpointContextService?.experimentalFeatures;
const elasticsearch = core?.elasticsearch.client as unknown as IScopedClusterClient;
this.processTreeFetcher = new Fetcher(elasticsearch);
@ -291,6 +295,10 @@ export class TelemetryReceiver implements ITelemetryReceiver {
return this.clusterInfo;
}
public getLicenseInfo(): Nullable<ESLicense> {
return this.licenseInfo;
}
public getAlertsIndex(): string | undefined {
return this.alertsIndex;
}

View file

@ -8,11 +8,10 @@
import type { Logger } from '@kbn/core/server';
import { newTelemetryLogger, getPreviousDiagTaskTimestamp } from '../helpers';
import type { ITelemetryEventsSender } from '../sender';
import type { TelemetryEvent } from '../types';
import { TelemetryChannel, type TelemetryEvent } from '../types';
import type { ITelemetryReceiver } from '../receiver';
import type { TaskExecutionPeriod } from '../task';
import type { ITaskMetricsService } from '../task_metrics.types';
import { TELEMETRY_CHANNEL_ENDPOINT_ALERTS } from '../constants';
import { copyAllowlistedFields, filterList } from '../filterlists';
export function createTelemetryDiagnosticsTaskConfig() {
@ -65,7 +64,7 @@ export function createTelemetryDiagnosticsTaskConfig() {
log.l('Sending diagnostic alerts', {
alerts_count: alerts.length,
});
await sender.sendOnDemand(TELEMETRY_CHANNEL_ENDPOINT_ALERTS, processedAlerts);
sender.sendAsync(TelemetryChannel.ENDPOINT_ALERTS, processedAlerts);
}
await taskMetricsService.end(trace);