Skip to content

[Task Manager] Use UIAM API Key for tasks in serverless#254315

Closed
ersin-erdal wants to merge 24 commits intoelastic:mainfrom
ersin-erdal:use-uiam-api-keys-in-tm
Closed

[Task Manager] Use UIAM API Key for tasks in serverless#254315
ersin-erdal wants to merge 24 commits intoelastic:mainfrom
ersin-erdal:use-uiam-api-keys-in-tm

Conversation

@ersin-erdal
Copy link
Copy Markdown
Contributor

@ersin-erdal ersin-erdal commented Feb 21, 2026

Related https://github.com/elastic/response-ops-team/issues/527

This PR adopts the UIAM APIKeys in the Task Manager plugin.

when security.authc?.apiKeys?.uiam is provided, we grant both the ES and UIAM APIKeys and persist in the task SO, so we can switch between two of them.
On task create -with a request- we grant ES and UIAM APIKeys.
On task update we grant ES and UIAM APIKeys and invalidate the old API Keys.
On task delete we invalidate the old API Keys.
If we don't use an api key after granting it - because of an error - invalidate the unused ones.

When xpack.task_manager.api_key_type is uiam we create the fakeRequest we use in the task with UIAM API Key.

To verify:

  • Add below configs to your serverless.dev.yml
    xpack.task_manager.api_key_type: 'uiam'
    xpack.task_manager.invalidate_api_key_task.removalDelay: '10s'
    xpack.task_manager.invalidate_api_key_task.interval: '1m'
    so we can see the invalidation task works without a problem.

  • Run Kibana and Elasticsearch with the below commands:
    yarn es serverless --projectType observability --uiam
    yarn start --serverless oblt --uiam --run-examples

  • Login with the system_indices_superuser user.

  • Go to: http://localhost:5601/app/triggersActionsUiExample/task_manager_with_api_key

  • Create task 1 and task 2

  • Use the below query to check if the task has both ES and UIAM API Keys

GET /.kibana_task_manager_*/_search
{
  "query": { 
    "bool": { 
      "must": [
        { "match": { "task.taskType":   "taskWithApiKey" }}
      ]
    }
  }
}
  • Remove one of the tasks, and check if both ES and UIAM API Keys to be queued to be invalidated.
GET /.kibana_task_manager_*/_search
{
  "query": {
    "match": {
      "type": {
        "query": "api_key_to_invalidate"
      }
    }
  }
}
  • Wait for a minute and do the same as above, the API Keys should be invalidated and removed from the index.
    There shouldn't be any error on the console.

  • Add the task you removed again and do the same tests with Remove All Tasks which uses bulkDelete.

@ersin-erdal ersin-erdal changed the title Use UIAM API Key for tasks in serverless [Task Manager] Use UIAM API Key for tasks in serverless Feb 21, 2026
@ersin-erdal ersin-erdal marked this pull request as ready for review February 23, 2026 19:38
@ersin-erdal ersin-erdal requested a review from a team as a code owner February 23, 2026 19:38
@ersin-erdal ersin-erdal added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// labels Feb 23, 2026
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/response-ops (Team:ResponseOps)

@elastic-vault-github-plugin-prod elastic-vault-github-plugin-prod Bot requested a review from a team as a code owner February 23, 2026 19:57
@ersin-erdal ersin-erdal requested a review from a team as a code owner February 24, 2026 00:23
Copy link
Copy Markdown
Member

@afharo afharo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SO changes LGTM

@darnautov darnautov self-requested a review February 25, 2026 08:00
@elena-shostak elena-shostak removed their request for review March 6, 2026 19:19
ersin-erdal and others added 7 commits March 14, 2026 14:10
# Conflicts:
#	packages/kbn-check-saved-objects-cli/src/migrations/__fixtures__/task/10.8.0.json
#	src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts
#	x-pack/platform/plugins/shared/task_manager/server/integration_tests/managed_configuration.test.ts
#	x-pack/platform/plugins/shared/task_manager/server/metrics/create_aggregator.test.ts
#	x-pack/platform/plugins/shared/task_manager/server/monitoring/configuration_statistics.test.ts
#	x-pack/platform/plugins/shared/task_manager/server/plugin.test.ts
#	x-pack/platform/plugins/shared/task_manager/server/plugin.ts
#	x-pack/platform/plugins/shared/task_manager/server/saved_objects/model_versions/task_model_versions.ts
#	x-pack/platform/plugins/shared/task_manager/server/saved_objects/schemas/task.ts
#	x-pack/platform/plugins/shared/task_manager/server/task_store.test.ts
#	x-pack/platform/plugins/shared/task_manager/server/task_store.ts
| ApiKeyAndUserScopeBoth;

export interface CreateApiKeyOptions {
shouldGrantUiam: boolean;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we make it more generic and accept a list of api key types to generate?

Suggested change
shouldGrantUiam: boolean;
apiKeyTypes: ApiKeyType[];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this should stay as it is, this is to check if uiam.grant is enabled or not. we use ApiKeyType when we decide which API Key to use.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This request led me to change the whole architecture of api key handling, had to switch to strategy pattern.
Created another PR: #259373
With this one we can add a new strategy as we have new apiKey types.

if (apiKeyIdsToRemove.length) {
// after successful updates we should invalidate the old API keys (ES and/or UIAM)
const allSucceeded = updatedSavedObjects.every((so) => !so.error);
if (apiKeysToRemove.length && allSucceeded) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old behavior invalidated keys per-document for each individually successful update. The new code invalidates only when the entire batch succeeds. So if any from the batch failed, 0 old API keys get invalidated, and we end up with orphaned API keys.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed it.

const { apiKey, userScope } = taskInstance;
if (apiKey && userScope) {
const { apiKey, uiamApiKey, userScope } = taskInstance;
if ((apiKey || uiamApiKey) && userScope && !userScope.apiKeyCreatedByUser) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously when regenerateApiKey: true was passed, tasks with API keys created by user were still included and got new system-created keys (the old user key was preserved / not invalidated). Now they're excluded entirely. I agree it makes sense to exclude userScope.apiKeyCreatedByUser, but it's a (breaking) change in the behaviour, isn't it? I believe we should either document it as a fix, or preserve the old behaviour

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, removed the extra check against apiKeyCreatedByUser

: taskInstance.apiKey;

if (apiKeyType === ApiKeyType.UIAM && taskInstance.apiKey && !taskInstance.uiamApiKey) {
this.logger.error(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should a warning, similar to alerting

Suggested change
this.logger.error(
this.logger.warn(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

private getFakeKibanaRequest(apiKey?: string, spaceId?: string): KibanaRequest | undefined {
if (apiKey) {
const requestHeaders: Headers = {};
private getFakeKibanaRequest(taskInstance: ConcreteTaskInstance): KibanaRequest | undefined {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we add some unit tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@elasticmachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] affected Scout: [ security / entity_store ] plugin / local-stateful-classic - Automated email resolution integration tests - Basic email matching — two entities with same email

Metrics [docs]

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
taskManager 10 11 +1
Unknown metric groups

API count

id before after diff
taskManager 122 123 +1

History

@ersin-erdal
Copy link
Copy Markdown
Contributor Author

closing in favor of: #259373

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:CPS release_note:skip Skip the PR/issue when compiling release notes Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t//

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants