Skip to content

Install the Elastic Slack app with a UIAM service account - #292776

Open
vigneshshanmugam wants to merge 28 commits into
elastic:mainfrom
vigneshshanmugam:feat/relay-uiam-service-account-install
Open

vigneshshanmugam wants to merge 28 commits into
elastic:mainfrom
vigneshshanmugam:feat/relay-uiam-service-account-install

Conversation

@vigneshshanmugam

@vigneshshanmugam vigneshshanmugam commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

Summary

  • When xpack.actions.relay.uiam.enabled is on, Slack connect creates UIAM service account, adds Relay (relay-service) to assumable_by in the security plugin, and sends only uiam_service_account_id to RelayClient.startInstall.
  • Previously, install always sent kibana_api_key. That path is unchanged when the flag is off.
  • Previously created service account are deleted when disconnecting relay or on install error
  • The HTTP create route still accepts { name } only. Callers cannot pass assumable_by or trustedPlatformAssumers.

Part of elastic/relay-service#340.

Live install still depends on Relay storing that id (elastic/relay-service#325) and on Agent Builder accepting the exchanged token. UIAM still snapshots the creating user's application privileges and cannot re-bound them (#284463).

@legrego On the security side, we had to made change to allow to pass additionnal assumable_by , and add a revoke method, let me know if it's seems acceptable and any change we could make there.

@vigneshshanmugam I also refactored this a lot to avoid too much duplicate code between the API key/service account path.

Identify risks

  • The flag is default off and Serverless-only. ECH install stays on the API key.

Test plan

  • node scripts/jest for the Slack app service, Relay client, UIAM and Elasticsearch service accounts, and the core service-account contract
  • Live Serverless install once Relay stores uiam_service_account_id

Release notes

release_note:skip

The behavior is behind xpack.actions.relay.uiam.enabled, which defaults to off.

Made with Cursor

Serverless installs behind xpack.actions.relay.uiam.enabled send a service-account id instead of an API key, and reuse of that id stays behind manage_security.

Co-authored-by: Cursor <cursoragent@cursor.com>
@infra-vault-gh-plugin-prod

infra-vault-gh-plugin-prod Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor
🤖 Jobs for this PR can be triggered through checkboxes. 🚧

ℹ️ To trigger the CI, please tick the checkbox below 👇

  • Click to trigger kibana-pull-request for this PR!
  • Click to trigger kibana-deploy-project-from-pr for this PR!
  • Click to trigger kibana-deploy-cloud-from-pr for this PR!
  • Click to trigger kibana-entity-store-performance-from-pr for this PR!
  • Click to trigger kibana-storybooks-from-pr for this PR!

@kibanamachine

Copy link
Copy Markdown
Contributor

API Contract Breaking Changes

The following breaking change(s) were detected across the public OpenAPI surface, grouped by stability tier. Stable and Technical Preview changes fail the check and should be resolved; Experimental changes are informational.

Experimental — informational, not blocking merge (2)

Experimental APIs are allowed to introduce breaking changes. These are listed for visibility only and do not fail this check.

Endpoint Reason oasdiffId Source
/api/streams/{name}/content/export POST added '#/components/schemas/Kibana_HTTP_APIs__zod_v4_53___schema0' to the 'include/anyOf[subschema #2]/objects/routing/items/' request property 'allOf' list request-property-all-of-added /opt/buildkite-agent/builds/bk-agent-prod-gcp-1790348516373054107/elastic/kibana-pull-request/kibana/oas_docs/output/kibana.yaml
/api/streams/{name}/content/export POST added '#/components/schemas/Kibana_HTTP_APIs__zod_v4_53___schema0' to the 'include/anyOf[subschema #2]/objects/routing/items/' request property 'allOf' list request-property-all-of-added /opt/buildkite-agent/builds/bk-agent-prod-gcp-1790348516373054107/elastic/kibana-pull-request/kibana/oas_docs/output/kibana.serverless.yaml

What to do

  1. Fix the breaking change if it was unintentional.
  2. If intentional, add an approved entry to packages/kbn-api-contracts/allowlist.json and coordinate with the owning team. Use the oasdiffId and source values from the table above to scope the allowlist entry to this specific change.

See the @kbn/api-contracts README for tier definitions and the allowlist workflow.

@nchaulet
nchaulet marked this pull request as ready for review September 29, 2026 15:13
@nchaulet
nchaulet requested review from a team as code owners September 29, 2026 15:13
@kibanamachine

Copy link
Copy Markdown
Contributor

PR size reminder

This PR has 1234 added lines of reviewable code, which is above the 500-line guideline for Nightshift PRs.

Large PRs get significantly less review engagement and take longer to merge. Consider splitting this into smaller, focused PRs before requesting review.

@nchaulet nchaulet added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels Sep 29, 2026
@nchaulet
nchaulet requested a review from legrego September 29, 2026 15:14
Comment on lines +654 to +658
await this.writeConnection(soClient, {
...connection,
status: RELAY_APP_CONNECTION_STATUS.notConnected,
apiKeyId: null,
tenantKey: null,

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.

Severity: low

Disconnect now retains all attributes via ...connection, including an old error. After a failed unbind is retried successfully (or an errored install is disconnected), getStatus still includes that error alongside not_connected, so users see a stale failure even though disconnect succeeded. Clear the error when writing the retained document.

getStatus returns ...(connection.error ? { error: connection.error } : {}) regardless of status.

Generated by Libra. React with 👍 or 👎 to give feedback on this comment.

@legrego
legrego removed the request for review from elena-shostak September 29, 2026 19:26
…-service-account-install

# Conflicts:
#	x-pack/platform/plugins/shared/security/server/service_accounts/es_service_accounts.test.ts
#	x-pack/platform/plugins/shared/security/server/service_accounts/es_service_accounts.ts
#	x-pack/platform/plugins/shared/security/server/service_accounts/uiam_service_accounts.ts

const RELAY_SERVICE_ACCOUNT_NAME_PREFIX = 'nightshift-relay-agent-builder';

const RELAY_SERVICE_ACCOUNT_ROLES = ['viewer'];

@nchaulet nchaulet Oct 1, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The uiam service account create method now require roles, that is better than using user roles, but this open the question of what role we want to user for that service account? we probably a new built in role? I would address that as a follow up

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@vigneshshanmugam curious to have your thoughts on that, I think we should have a dedicated built in role for relay

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree, viewer is too broad. Can we explore creating a dedicated role for Relay's use case? This will allow you to dynamically update the required privileges over time as well, as your requirements change.

@nchaulet nchaulet Oct 7, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@legrego do you have any thoughs on how we could create that role? should we just create a custom role in Kibana at runtime (it do not seems the more robust) Or should we go the way of adding a built-in role? also it seems there is not really a system role concept

nchaulet and others added 2 commits October 1, 2026 12:26
…-service-account-install

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Comment thread src/core/packages/security/server/src/service_accounts.ts Outdated
Comment thread x-pack/platform/plugins/shared/security/server/service_accounts/assumable_by.ts Outdated
...connection,
status: RELAY_APP_CONNECTION_STATUS.error,
apiKeyId: null,
serviceAccountId: null,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the revoke step fails (errors are swallowed), then we will erase the service account id from Kibana's memory here. Won't we end up with an orphaned service account at that point?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes we have the same behaviour for api keys, user should still be able to manually revoke the old service account, but it avoid a out of sync state with a service account id stored in a saved object that we cannot revoke anymore, the error is logged


const RELAY_SERVICE_ACCOUNT_NAME_PREFIX = 'nightshift-relay-agent-builder';

const RELAY_SERVICE_ACCOUNT_ROLES = ['viewer'];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree, viewer is too broad. Can we explore creating a dedicated role for Relay's use case? This will allow you to dynamically update the required privileges over time as well, as your requirements change.

Comment thread x-pack/platform/plugins/shared/security/server/build_delegate_apis.ts Outdated
nchaulet and others added 3 commits October 7, 2026 09:19
…s/assumable_by.ts

Co-authored-by: Larry Gregory <lgregorydev@gmail.com>
…vigneshshanmugam/kibana into feat/relay-uiam-service-account-install
Comment on lines +129 to +130
delete: async (request, id, params) =>
requireServiceAccounts().management.delete(request, id, params),

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.

Severity: P2 (Medium)

Reject a non-forced delete when bound workloads remain; the delegate currently resolves successfully while leaving the account active.

Generated by Libra. React with 👍 or 👎 to give feedback on this comment.

Comment on lines +436 to +437
const license = await this.server.licensing.getLicense();
const agentId = await credential.resolveAgentId();

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.

Severity: P3 (Low)

Add a regression test for license lookup failure after credential creation to verify cleanup runs and Relay is not called.

Generated by Libra. React with 👍 or 👎 to give feedback on this comment.

@kibanamachine

kibanamachine commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

💔 Build Failed

Failed CI Steps

Metrics [docs]

Unknown metric groups

workflow yaml validation

id before after diff
infosec_demo.yaml (150 steps, 270 vars)/e2e/total 118 120 +2
infosec_demo.yaml (150 steps, 270 vars)/e2e/validateIfConditions 4 5 +1
infosec_demo.yaml (150 steps, 270 vars)/e2e/validateVariables 42 43 +1
infosec_demo.yaml (150 steps, 270 vars)/validateIfConditions 4 5 +1
total +5

History

This branch has not been deployed

No deployments
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 ci:build-serverless-image release_note:skip Skip the PR/issue when compiling release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants