"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TASK_ID = void 0; exports.initializeApiKeyInvalidator = initializeApiKeyInvalidator; exports.scheduleApiKeyInvalidatorTask = scheduleApiKeyInvalidatorTask; var _coreSavedObjectsServer = require("@kbn/core-saved-objects-server"); var _get_cadence = require("../lib/get_cadence"); var _task_state = require("./task_state"); /* * 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. */ const TASK_TYPE = 'alerts_invalidate_api_keys'; const TASK_ID = `Alerts-${TASK_TYPE}`; exports.TASK_ID = TASK_ID; const invalidateAPIKeys = async (params, securityPluginStart) => { if (!securityPluginStart) { return { apiKeysEnabled: false }; } const invalidateAPIKeyResult = await securityPluginStart.authc.apiKeys.invalidateAsInternalUser(params); // Null when Elasticsearch security is disabled if (!invalidateAPIKeyResult) { return { apiKeysEnabled: false }; } return { apiKeysEnabled: true, result: invalidateAPIKeyResult }; }; function initializeApiKeyInvalidator(logger, coreStartServices, taskManager, config) { registerApiKeyInvalidatorTaskDefinition(logger, coreStartServices, taskManager, config); } async function scheduleApiKeyInvalidatorTask(logger, config, taskManager) { const interval = config.invalidateApiKeysTask.interval; try { await taskManager.ensureScheduled({ id: TASK_ID, taskType: TASK_TYPE, schedule: { interval }, state: _task_state.emptyState, params: {} }); } catch (e) { logger.error(`Error scheduling ${TASK_ID} task, received ${e.message}`); } } function registerApiKeyInvalidatorTaskDefinition(logger, coreStartServices, taskManager, config) { taskManager.registerTaskDefinitions({ [TASK_TYPE]: { title: 'Invalidate alert API Keys', stateSchemaByVersion: _task_state.stateSchemaByVersion, createTaskRunner: taskRunner(logger, coreStartServices, config) } }); } function getFakeKibanaRequest(basePath) { const requestHeaders = {}; return { headers: requestHeaders, getBasePath: () => basePath, path: '/', route: { settings: {} }, url: { href: '/' }, raw: { req: { url: '/' } } }; } function taskRunner(logger, coreStartServices, config) { return ({ taskInstance }) => { const state = taskInstance.state; return { async run() { let totalInvalidated = 0; try { const [{ savedObjects, http }, { encryptedSavedObjects, security }] = await coreStartServices; const savedObjectsClient = savedObjects.getScopedClient(getFakeKibanaRequest(http.basePath.serverBasePath), { includedHiddenTypes: ['api_key_pending_invalidation'], excludedExtensions: [_coreSavedObjectsServer.SECURITY_EXTENSION_ID] }); const encryptedSavedObjectsClient = encryptedSavedObjects.getClient({ includedHiddenTypes: ['api_key_pending_invalidation'] }); const configuredDelay = config.invalidateApiKeysTask.removalDelay; const delay = (0, _get_cadence.timePeriodBeforeDate)(new Date(), configuredDelay).toISOString(); let hasApiKeysPendingInvalidation = true; const PAGE_SIZE = 100; do { const apiKeysToInvalidate = await savedObjectsClient.find({ type: 'api_key_pending_invalidation', filter: `api_key_pending_invalidation.attributes.createdAt <= "${delay}"`, page: 1, sortField: 'createdAt', sortOrder: 'asc', perPage: PAGE_SIZE }); totalInvalidated += await invalidateApiKeys(logger, savedObjectsClient, apiKeysToInvalidate, encryptedSavedObjectsClient, security); hasApiKeysPendingInvalidation = apiKeysToInvalidate.total > PAGE_SIZE; } while (hasApiKeysPendingInvalidation); const updatedState = { runs: (state.runs || 0) + 1, total_invalidated: totalInvalidated }; return { state: updatedState, schedule: { interval: config.invalidateApiKeysTask.interval } }; } catch (e) { logger.warn(`Error executing alerting apiKey invalidation task: ${e.message}`); const updatedState = { runs: state.runs + 1, total_invalidated: totalInvalidated }; return { state: updatedState, schedule: { interval: config.invalidateApiKeysTask.interval } }; } } }; }; } async function invalidateApiKeys(logger, savedObjectsClient, apiKeysToInvalidate, encryptedSavedObjectsClient, securityPluginStart) { let totalInvalidated = 0; const apiKeyIds = await Promise.all(apiKeysToInvalidate.saved_objects.map(async apiKeyObj => { const decryptedApiKey = await encryptedSavedObjectsClient.getDecryptedAsInternalUser('api_key_pending_invalidation', apiKeyObj.id); return decryptedApiKey.attributes.apiKeyId; })); if (apiKeyIds.length > 0) { const response = await invalidateAPIKeys({ ids: apiKeyIds }, securityPluginStart); if (response.apiKeysEnabled === true && response.result.error_count > 0) { logger.error(`Failed to invalidate API Keys [ids="${apiKeyIds.join(', ')}"]`); } else { await Promise.all(apiKeysToInvalidate.saved_objects.map(async apiKeyObj => { try { await savedObjectsClient.delete('api_key_pending_invalidation', apiKeyObj.id); totalInvalidated++; } catch (err) { logger.error(`Failed to delete invalidated API key "${apiKeyObj.attributes.apiKeyId}". Error: ${err.message}`); } })); } } logger.debug(`Total invalidated API keys "${totalInvalidated}"`); return totalInvalidated; }