Skip to content

[Entity Analytics][Lead generation] Hide leads section and disable Generate button based on ES index permissions#266586

Merged
abhishekbhatia1710 merged 4 commits intoelastic:mainfrom
abhishekbhatia1710:leads-permission-aware-ui
May 4, 2026
Merged

[Entity Analytics][Lead generation] Hide leads section and disable Generate button based on ES index permissions#266586
abhishekbhatia1710 merged 4 commits intoelastic:mainfrom
abhishekbhatia1710:leads-permission-aware-ui

Conversation

@abhishekbhatia1710
Copy link
Copy Markdown
Contributor

@abhishekbhatia1710 abhishekbhatia1710 commented Apr 30, 2026

Summary

Follow-up to #265956, addressing the review request by @ymao1 in this comment.

Closes elastic/security-team#17123

Adds permission-aware UI behaviour to the leads section based on the user's Elasticsearch index-level access to .entity_analytics.entity-leads-*:

  • No read access: the entire leads section is hidden
  • Read but no write access: leads are shown, but the Generate and Refresh buttons are disabled with a tooltip explaining the permission requirement
  • Full access: no change, UI behaves as before

How it works

A new internal API route GET /internal/entity_analytics/leads/privileges checks read and write privileges on the leads index pattern for the current user (using checkPrivilegesDynamicallyWithRequest). The result is fetched once on page load inside useHuntingLeads and drives the UI state.

Screenshots

Generate button disabled (no write access)

Screenshot 2026-04-30 at 1 54 51 PM

Leads section hidden (no read access)
Screenshot 2026-04-30 at 1 54 02 PM

Testing

Test users to create

Use the Kibana Dev Console (Stack Management > Dev Tools) to create the following users.

1. Full access user (read + write on leads index)

POST /_security/role/leads_full_access
{
  "indices": [
    {
      "names": [".entity_analytics.entity-leads-*"],
      "privileges": ["read", "write", "create_index"]
    }
  ]
}

POST /_security/user/leads_full_user
{
  "roles": ["kibana_admin", "leads_full_access"]
}

2. Read-only user (read on leads index, no write)

POST /_security/role/leads_read_only
{
  "indices": [
    {
      "names": [".entity_analytics.entity-leads-*"],
      "privileges": ["read"]
    }
  ]
}

POST /_security/user/leads_read_user
{
  "roles": ["kibana_admin", "leads_read_only"]
}

3. No access user (no leads index permissions)

POST /_security/user/leads_no_access_user
{
  "roles": ["kibana_admin"]
}

Test steps

  1. Log in as leads_full_user and navigate to the Entity Analytics page. The leads section should be fully visible with Generate and Refresh buttons enabled.
  2. Log in as leads_read_user and navigate to the Entity Analytics page. The leads section should be visible but the Generate and Refresh buttons should be disabled with a tooltip.
  3. Log in as leads_no_access_user and navigate to the Entity Analytics page. The leads section should not be rendered.

Note: For steps 2 and 3 to be meaningful, lead generation should have been enabled first (via a full-access user) so the index exists. The privilege check is role-based and works even before the index is created.

@abhishekbhatia1710 abhishekbhatia1710 self-assigned this Apr 30, 2026
@abhishekbhatia1710 abhishekbhatia1710 added Team:Entity Analytics Security Entity Analytics Team backport:version Backport to applied version labels v9.4.0 labels Apr 30, 2026
@abhishekbhatia1710 abhishekbhatia1710 marked this pull request as ready for review April 30, 2026 09:21
@abhishekbhatia1710 abhishekbhatia1710 requested a review from a team as a code owner April 30, 2026 09:21
@infra-vault-gh-plugin-prod
Copy link
Copy Markdown

Pinging @elastic/security-entity-analytics (Team:Entity Analytics)

@abhishekbhatia1710 abhishekbhatia1710 added the release_note:skip Skip the PR/issue when compiling release notes label Apr 30, 2026
Copy link
Copy Markdown
Contributor

@tcalopes tcalopes left a comment

Choose a reason for hiding this comment

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

Desk tested and code reviewed. Looks good, just left some small comments but not blocking

@kibanamachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
securitySolution 12.0MB 12.0MB +887.0B

History

cc @abhishekbhatia1710

@abhishekbhatia1710 abhishekbhatia1710 merged commit 4aec4fe into elastic:main May 4, 2026
38 checks passed
@kibanamachine
Copy link
Copy Markdown
Contributor

Starting backport for target branches: 9.4

https://github.com/elastic/kibana/actions/runs/25305608171

@kibanamachine
Copy link
Copy Markdown
Contributor

💚 All backports created successfully

Status Branch Result
9.4

Note: Successful backport PRs will be merged automatically after passing CI.

Questions ?

Please refer to the Backport tool documentation

kibanamachine added a commit that referenced this pull request May 4, 2026
…ble Generate button based on ES index permissions (#266586) (#267383)

# Backport

This will backport the following commits from `main` to `9.4`:
- [[Entity Analytics][Lead generation] Hide leads section and disable
Generate button based on ES index permissions
(#266586)](#266586)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Abhishek
Bhatia","email":"117628830+abhishekbhatia1710@users.noreply.github.com"},"sourceCommit":{"committedDate":"2026-05-04T07:02:05Z","message":"[Entity
Analytics][Lead generation] Hide leads section and disable Generate
button based on ES index permissions (#266586)\n\n##
Summary\n\nFollow-up to #265956, addressing the review request by @ymao1
in
[this\ncomment](https://github.com/elastic/kibana/pull/265956#pullrequestreview-4197650546).\n\nCloses
elastic/security-team#17123\n\nAdds permission-aware UI behaviour to the
leads section based on the\nuser's Elasticsearch index-level access
to\n`.entity_analytics.entity-leads-*`:\n\n- **No read access**: the
entire leads section is hidden\n- **Read but no write access**: leads
are shown, but the Generate and\nRefresh buttons are disabled with a
tooltip explaining the permission\nrequirement\n- **Full access**: no
change, UI behaves as before\n\n### How it works\n\nA new internal API
route `GET\n/internal/entity_analytics/leads/privileges` checks `read`
and `write`\nprivileges on the leads index pattern for the current user
(using\n`checkPrivilegesDynamicallyWithRequest`). The result is fetched
once on\npage load inside `useHuntingLeads` and drives the UI
state.\n\n## Screenshots\n\nGenerate button disabled (no write
access)\n\n<img width=\"1722\" height=\"783\" alt=\"Screenshot
2026-04-30 at 1 54
51 PM\"\nsrc=\"https://github.com/user-attachments/assets/eade852a-f204-49f3-a96d-08e64913049c\"\n/>\n\n\nLeads
section hidden (no read access)\n<img width=\"1919\" height=\"903\"
alt=\"Screenshot 2026-04-30 at 1 54
02 PM\"\nsrc=\"https://github.com/user-attachments/assets/99649213-f63e-4304-b76a-4cfc922bb987\"\n/>\n\n\n\n##
Testing\n\n### Test users to create\n\nUse the Kibana Dev Console
(`Stack Management > Dev Tools`) to create\nthe following users.\n\n**1.
Full access user** (read + write on leads index)\n\n```\nPOST
/_security/role/leads_full_access\n{\n \"indices\": [\n {\n \"names\":
[\".entity_analytics.entity-leads-*\"],\n \"privileges\": [\"read\",
\"write\", \"create_index\"]\n }\n ]\n}\n\nPOST
/_security/user/leads_full_user\n{\n \"roles\": [\"kibana_admin\",
\"leads_full_access\"]\n}\n```\n\n**2. Read-only user** (read on leads
index, no write)\n\n```\nPOST /_security/role/leads_read_only\n{\n
\"indices\": [\n {\n \"names\":
[\".entity_analytics.entity-leads-*\"],\n \"privileges\": [\"read\"]\n
}\n ]\n}\n\nPOST /_security/user/leads_read_user\n{\n \"roles\":
[\"kibana_admin\", \"leads_read_only\"]\n}\n```\n\n**3. No access user**
(no leads index permissions)\n\n```\nPOST
/_security/user/leads_no_access_user\n{\n \"roles\":
[\"kibana_admin\"]\n}\n```\n\n### Test steps\n\n1. Log in as
`leads_full_user` and navigate to the Entity Analytics\npage. The leads
section should be fully visible with Generate and\nRefresh buttons
enabled.\n2. Log in as `leads_read_user` and navigate to the Entity
Analytics\npage. The leads section should be visible but the Generate
and Refresh\nbuttons should be disabled with a tooltip.\n3. Log in as
`leads_no_access_user` and navigate to the Entity Analytics\npage. The
leads section should not be rendered.\n\n> Note: For steps 2 and 3 to be
meaningful, lead generation should have\nbeen enabled first (via a
full-access user) so the index exists. The\nprivilege check is
role-based and works even before the index
is\ncreated.","sha":"4aec4fe4cc1aeaba2a4dff558f338bc3491efd29","branchLabelMapping":{"^v9.5.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Entity
Analytics","backport:version","v9.4.0","v9.5.0"],"title":"[Entity
Analytics][Lead generation] Hide leads section and disable Generate
button based on ES index
permissions","number":266586,"url":"https://github.com/elastic/kibana/pull/266586","mergeCommit":{"message":"[Entity
Analytics][Lead generation] Hide leads section and disable Generate
button based on ES index permissions (#266586)\n\n##
Summary\n\nFollow-up to #265956, addressing the review request by @ymao1
in
[this\ncomment](https://github.com/elastic/kibana/pull/265956#pullrequestreview-4197650546).\n\nCloses
elastic/security-team#17123\n\nAdds permission-aware UI behaviour to the
leads section based on the\nuser's Elasticsearch index-level access
to\n`.entity_analytics.entity-leads-*`:\n\n- **No read access**: the
entire leads section is hidden\n- **Read but no write access**: leads
are shown, but the Generate and\nRefresh buttons are disabled with a
tooltip explaining the permission\nrequirement\n- **Full access**: no
change, UI behaves as before\n\n### How it works\n\nA new internal API
route `GET\n/internal/entity_analytics/leads/privileges` checks `read`
and `write`\nprivileges on the leads index pattern for the current user
(using\n`checkPrivilegesDynamicallyWithRequest`). The result is fetched
once on\npage load inside `useHuntingLeads` and drives the UI
state.\n\n## Screenshots\n\nGenerate button disabled (no write
access)\n\n<img width=\"1722\" height=\"783\" alt=\"Screenshot
2026-04-30 at 1 54
51 PM\"\nsrc=\"https://github.com/user-attachments/assets/eade852a-f204-49f3-a96d-08e64913049c\"\n/>\n\n\nLeads
section hidden (no read access)\n<img width=\"1919\" height=\"903\"
alt=\"Screenshot 2026-04-30 at 1 54
02 PM\"\nsrc=\"https://github.com/user-attachments/assets/99649213-f63e-4304-b76a-4cfc922bb987\"\n/>\n\n\n\n##
Testing\n\n### Test users to create\n\nUse the Kibana Dev Console
(`Stack Management > Dev Tools`) to create\nthe following users.\n\n**1.
Full access user** (read + write on leads index)\n\n```\nPOST
/_security/role/leads_full_access\n{\n \"indices\": [\n {\n \"names\":
[\".entity_analytics.entity-leads-*\"],\n \"privileges\": [\"read\",
\"write\", \"create_index\"]\n }\n ]\n}\n\nPOST
/_security/user/leads_full_user\n{\n \"roles\": [\"kibana_admin\",
\"leads_full_access\"]\n}\n```\n\n**2. Read-only user** (read on leads
index, no write)\n\n```\nPOST /_security/role/leads_read_only\n{\n
\"indices\": [\n {\n \"names\":
[\".entity_analytics.entity-leads-*\"],\n \"privileges\": [\"read\"]\n
}\n ]\n}\n\nPOST /_security/user/leads_read_user\n{\n \"roles\":
[\"kibana_admin\", \"leads_read_only\"]\n}\n```\n\n**3. No access user**
(no leads index permissions)\n\n```\nPOST
/_security/user/leads_no_access_user\n{\n \"roles\":
[\"kibana_admin\"]\n}\n```\n\n### Test steps\n\n1. Log in as
`leads_full_user` and navigate to the Entity Analytics\npage. The leads
section should be fully visible with Generate and\nRefresh buttons
enabled.\n2. Log in as `leads_read_user` and navigate to the Entity
Analytics\npage. The leads section should be visible but the Generate
and Refresh\nbuttons should be disabled with a tooltip.\n3. Log in as
`leads_no_access_user` and navigate to the Entity Analytics\npage. The
leads section should not be rendered.\n\n> Note: For steps 2 and 3 to be
meaningful, lead generation should have\nbeen enabled first (via a
full-access user) so the index exists. The\nprivilege check is
role-based and works even before the index
is\ncreated.","sha":"4aec4fe4cc1aeaba2a4dff558f338bc3491efd29"}},"sourceBranch":"main","suggestedTargetBranches":["9.4"],"targetPullRequestStates":[{"branch":"9.4","label":"v9.4.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v9.5.0","branchLabelMappingKey":"^v9.5.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/266586","number":266586,"mergeCommit":{"message":"[Entity
Analytics][Lead generation] Hide leads section and disable Generate
button based on ES index permissions (#266586)\n\n##
Summary\n\nFollow-up to #265956, addressing the review request by @ymao1
in
[this\ncomment](https://github.com/elastic/kibana/pull/265956#pullrequestreview-4197650546).\n\nCloses
elastic/security-team#17123\n\nAdds permission-aware UI behaviour to the
leads section based on the\nuser's Elasticsearch index-level access
to\n`.entity_analytics.entity-leads-*`:\n\n- **No read access**: the
entire leads section is hidden\n- **Read but no write access**: leads
are shown, but the Generate and\nRefresh buttons are disabled with a
tooltip explaining the permission\nrequirement\n- **Full access**: no
change, UI behaves as before\n\n### How it works\n\nA new internal API
route `GET\n/internal/entity_analytics/leads/privileges` checks `read`
and `write`\nprivileges on the leads index pattern for the current user
(using\n`checkPrivilegesDynamicallyWithRequest`). The result is fetched
once on\npage load inside `useHuntingLeads` and drives the UI
state.\n\n## Screenshots\n\nGenerate button disabled (no write
access)\n\n<img width=\"1722\" height=\"783\" alt=\"Screenshot
2026-04-30 at 1 54
51 PM\"\nsrc=\"https://github.com/user-attachments/assets/eade852a-f204-49f3-a96d-08e64913049c\"\n/>\n\n\nLeads
section hidden (no read access)\n<img width=\"1919\" height=\"903\"
alt=\"Screenshot 2026-04-30 at 1 54
02 PM\"\nsrc=\"https://github.com/user-attachments/assets/99649213-f63e-4304-b76a-4cfc922bb987\"\n/>\n\n\n\n##
Testing\n\n### Test users to create\n\nUse the Kibana Dev Console
(`Stack Management > Dev Tools`) to create\nthe following users.\n\n**1.
Full access user** (read + write on leads index)\n\n```\nPOST
/_security/role/leads_full_access\n{\n \"indices\": [\n {\n \"names\":
[\".entity_analytics.entity-leads-*\"],\n \"privileges\": [\"read\",
\"write\", \"create_index\"]\n }\n ]\n}\n\nPOST
/_security/user/leads_full_user\n{\n \"roles\": [\"kibana_admin\",
\"leads_full_access\"]\n}\n```\n\n**2. Read-only user** (read on leads
index, no write)\n\n```\nPOST /_security/role/leads_read_only\n{\n
\"indices\": [\n {\n \"names\":
[\".entity_analytics.entity-leads-*\"],\n \"privileges\": [\"read\"]\n
}\n ]\n}\n\nPOST /_security/user/leads_read_user\n{\n \"roles\":
[\"kibana_admin\", \"leads_read_only\"]\n}\n```\n\n**3. No access user**
(no leads index permissions)\n\n```\nPOST
/_security/user/leads_no_access_user\n{\n \"roles\":
[\"kibana_admin\"]\n}\n```\n\n### Test steps\n\n1. Log in as
`leads_full_user` and navigate to the Entity Analytics\npage. The leads
section should be fully visible with Generate and\nRefresh buttons
enabled.\n2. Log in as `leads_read_user` and navigate to the Entity
Analytics\npage. The leads section should be visible but the Generate
and Refresh\nbuttons should be disabled with a tooltip.\n3. Log in as
`leads_no_access_user` and navigate to the Entity Analytics\npage. The
leads section should not be rendered.\n\n> Note: For steps 2 and 3 to be
meaningful, lead generation should have\nbeen enabled first (via a
full-access user) so the index exists. The\nprivilege check is
role-based and works even before the index
is\ncreated.","sha":"4aec4fe4cc1aeaba2a4dff558f338bc3491efd29"}}]}]
BACKPORT-->

Co-authored-by: Abhishek Bhatia <117628830+abhishekbhatia1710@users.noreply.github.com>
seanrathier pushed a commit to seanrathier/kibana that referenced this pull request May 4, 2026
…nerate button based on ES index permissions (elastic#266586)

## Summary

Follow-up to elastic#265956, addressing the review request by @ymao1 in [this
comment](elastic#265956 (review)).

Closes elastic/security-team#17123

Adds permission-aware UI behaviour to the leads section based on the
user's Elasticsearch index-level access to
`.entity_analytics.entity-leads-*`:

- **No read access**: the entire leads section is hidden
- **Read but no write access**: leads are shown, but the Generate and
Refresh buttons are disabled with a tooltip explaining the permission
requirement
- **Full access**: no change, UI behaves as before

### How it works

A new internal API route `GET
/internal/entity_analytics/leads/privileges` checks `read` and `write`
privileges on the leads index pattern for the current user (using
`checkPrivilegesDynamicallyWithRequest`). The result is fetched once on
page load inside `useHuntingLeads` and drives the UI state.

## Screenshots

Generate button disabled (no write access)

<img width="1722" height="783" alt="Screenshot 2026-04-30 at 1 54 51 PM"
src="https://github.com/user-attachments/assets/eade852a-f204-49f3-a96d-08e64913049c"
/>


Leads section hidden (no read access)
<img width="1919" height="903" alt="Screenshot 2026-04-30 at 1 54 02 PM"
src="https://github.com/user-attachments/assets/99649213-f63e-4304-b76a-4cfc922bb987"
/>



## Testing

### Test users to create

Use the Kibana Dev Console (`Stack Management > Dev Tools`) to create
the following users.

**1. Full access user** (read + write on leads index)

```
POST /_security/role/leads_full_access
{
  "indices": [
    {
      "names": [".entity_analytics.entity-leads-*"],
      "privileges": ["read", "write", "create_index"]
    }
  ]
}

POST /_security/user/leads_full_user
{
  "roles": ["kibana_admin", "leads_full_access"]
}
```

**2. Read-only user** (read on leads index, no write)

```
POST /_security/role/leads_read_only
{
  "indices": [
    {
      "names": [".entity_analytics.entity-leads-*"],
      "privileges": ["read"]
    }
  ]
}

POST /_security/user/leads_read_user
{
  "roles": ["kibana_admin", "leads_read_only"]
}
```

**3. No access user** (no leads index permissions)

```
POST /_security/user/leads_no_access_user
{
  "roles": ["kibana_admin"]
}
```

### Test steps

1. Log in as `leads_full_user` and navigate to the Entity Analytics
page. The leads section should be fully visible with Generate and
Refresh buttons enabled.
2. Log in as `leads_read_user` and navigate to the Entity Analytics
page. The leads section should be visible but the Generate and Refresh
buttons should be disabled with a tooltip.
3. Log in as `leads_no_access_user` and navigate to the Entity Analytics
page. The leads section should not be rendered.

> Note: For steps 2 and 3 to be meaningful, lead generation should have
been enabled first (via a full-access user) so the index exists. The
privilege check is role-based and works even before the index is
created.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:version Backport to applied version labels release_note:skip Skip the PR/issue when compiling release notes Team:Entity Analytics Security Entity Analytics Team v9.4.0 v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants