Skip to content

[Write restricted dashboards] Audit events#241101

Merged
SiddharthMantri merged 4 commits intoelastic:security/read-only-dashboardsfrom
SiddharthMantri:security/wrd-audit-events
Oct 29, 2025
Merged

[Write restricted dashboards] Audit events#241101
SiddharthMantri merged 4 commits intoelastic:security/read-only-dashboardsfrom
SiddharthMantri:security/wrd-audit-events

Conversation

@SiddharthMantri
Copy link
Contributor

@SiddharthMantri SiddharthMantri commented Oct 29, 2025

Closes #221755

Summary

Adds audit events on successful completion of changing object owner or access mode.

Detailed list of audit events on issue attached above.

Audit events added in this PR:

Audit Action When Audited Outcome Bypass Conditions
UPDATE_OBJECTS_OWNER • Failure: When access control enforcement fails • Success : When access control enforcement is granted 'failure' No bypass for failure case
UPDATE_OBJECTS_ACCESS_MODE • Failure: When access control enforcement fails • Success : When access control enforcement is granted 'failure' No bypass for failure case

Logging scenarios

1. AccessControl is modified by owner

  • Expected outcome: Auhorized
  • Log example:
{"event":{"action":"saved_object_update_objects_access_mode","category":["database"],"type":["change"],"outcome":"success"},"kibana":{"space_id":"default","session_id":"ujNfHZISIOS99ANjQxxSAjxtY+D0D0/VnGBDDIJG5IE=","saved_object":{"type":"access_control_type","id":"bdceca5c-cd1e-442e-8272-55c632398cc7"}},"user":{"id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0","name":"elastic","roles":["superuser"]},"trace":{"id":"3df30168-353c-48ee-b0ee-bb671f40d9f4"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"9.0.0"},"@timestamp":"2025-10-29T17:26:38.099+01:00","message":"User has updated access mode of access_control_type [id=bdceca5c-cd1e-442e-8272-55c632398cc7]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":42523,"uptime":107.077655333},"span":{"id":"2bf159f3eed6e557"}}

2. AccessControl is modified by non-owner

  • Expected outcome: Unauthorized
  • Log example:
{"event":{"action":"saved_object_update_objects_access_mode","category":["database"],"type":["change"],"outcome":"failure"},"kibana":{"space_id":"default","session_id":"Mn8eOxtCD7MOGlCPR4tRdfDpsKNSTXzVfXIAmzFNNsc=","unauthorized_spaces":["default"],"unauthorized_types":["access_control_type"]},"error":{"code":"Error","message":"Unable to manage_access_control for types access_control_type"},"user":{"id":"u_EWATCHX9oIEsmcXj8aA1FkcaY3DE-XEpsiGTjrR2PmM_0","name":"test_user","roles":["editor"]},"trace":{"id":"c3497d4e-3a93-4d3b-8800-6062009f1b77"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"9.0.0"},"@timestamp":"2025-10-29T17:44:28.893+01:00","message":"Failed attempt to update access mode of saved objects","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":42523,"uptime":1177.897796208},"span":{"id":"912b67ee3b28dd14"}}

3. AccessControl is modified by admin on non-admin owned object

  • Expected outcome: Authorized
  • Logs:
{"event":{"action":"saved_object_update_objects_access_mode","category":["database"],"type":["change"],"outcome":"success"},"kibana":{"space_id":"default","session_id":"ujNfHZISIOS99ANjQxxSAjxtY+D0D0/VnGBDDIJG5IE=","saved_object":{"type":"access_control_type","id":"03eb9fcd-584b-4766-bfba-327a4f0f696c"}},"user":{"id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0","name":"elastic","roles":["superuser"]},"trace":{"id":"c6005951-24e4-4142-b13d-8bf101ca5468"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"9.0.0"},"@timestamp":"2025-10-29T18:09:28.253+01:00","message":"User has updated access mode of access_control_type [id=03eb9fcd-584b-4766-bfba-327a4f0f696c]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":61700,"uptime":596.898178917},"span":{"id":"b2b8a487b44915c8"}}

Steps to test using integration tests

You can use the existing integration tests for access control by adding the following to the config file at: x-pack/platform/test/spaces_api_integration/access_control_objects/config.ts

Config to add at kbnTestServer.serverArgs

...
'--xpack.security.audit.enabled=true',
'--xpack.security.audit.appender.type=file',
'--xpack.security.audit.appender.fileName=./kibana_audit.log',
 '--xpack.security.audit.appender.layout.type=json'

Once you run the tests as

no
de scripts/functional_tests_server --config x-pack/platform/test/spaces_api_integration/access_control_objects/config.ts

You can perform the tests as described here #224411 and verify the logs in kibana_audit.log file generated at the root level of your kibana repository.

@SiddharthMantri
Copy link
Contributor Author

@elasticmachine merge upstream

@elena-shostak elena-shostak self-requested a review October 29, 2025 15:02
Copy link
Contributor

@elena-shostak elena-shostak left a comment

Choose a reason for hiding this comment

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

Verified locally, can confirm audit events are logged 🥇

{"event":{"action":"saved_object_update_objects_access_mode","category":["database"],"type":["change"],"outcome":"success"},"kibana":{"space_id":"default","session_id":"t7/G14FYLIcazDDDJJAZq1gxZWmDUEbwmcqPY5elTkw=","saved_object":{"type":"access_control_type","id":"dea18e44-35d0-4742-979d-80f648729f2d"}},"user":{"id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0","name":"elastic","roles":["superuser"]},"trace":{"id":"e7846a78-d1ae-4964-bac5-43481975047c"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"9.0.0"},"@timestamp":"2025-10-29T18:53:20.166+01:00","message":"User has updated access mode of access_control_type [id=dea18e44-35d0-4742-979d-80f648729f2d]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":60576,"uptime":1590.573061042},"span":{"id":"60e751cf7fdde50f"}}

---
{"event":{"action":"saved_object_update_objects_owner","category":["database"],"type":["change"],"outcome":"success"},"kibana":{"space_id":"default","session_id":"k5srR22XWFHSt/qBe6qLZ2b0aGT+ZRXUyPZhz9lfKSg=","saved_object":{"type":"access_control_type","id":"6c5fdbbb-38b8-4883-b72b-fe571672043c"}},"user":{"id":"u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0","name":"elastic","roles":["superuser"]},"trace":{"id":"f46e6d2f-94cd-4ede-9d9b-6cd8d190a26b"},"client":{"ip":"127.0.0.1"},"service":{"node":{"roles":["background_tasks","ui"]}},"ecs":{"version":"9.0.0"},"@timestamp":"2025-10-29T18:57:29.182+01:00","message":"User has updated owner of access_control_type [id=6c5fdbbb-38b8-4883-b72b-fe571672043c]","log":{"level":"INFO","logger":"plugins.security.audit.ecs"},"process":{"pid":60576,"uptime":1839.584627708},"span":{"id":"d0f06bcea572331b"}}
@elasticmachine
Copy link
Contributor

💔 Build Failed

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #68 / Rules Management - Rule creation APIs @serverless @ess @serverlessQA create_rules @skipInServerless missing timestamps generates two signals with a "partial failure" status
  • [job] [logs] FTR Configs #47 / serverless observability UI - ML and Discover discover/observabilitySolution/context_awareness extension getRecommendedFields data view mode should show recommended fields section for matching profile

Metrics [docs]

‼️ ERROR: no builds found for mergeBase sha [a13cfa2]

History

@SiddharthMantri SiddharthMantri merged commit 3c5c01b into elastic:security/read-only-dashboards Oct 29, 2025
11 of 12 checks passed
SiddharthMantri added a commit that referenced this pull request Dec 12, 2025
Closes elastic/kibana-team#808

The respective teams have been raising PRs against this feature branch.
Approved PRs merged so far:
- #221916
- #224411 
- #239973 
- #241101
- #238468
- #233552
- #228416 
- #241168
- #244746
- #244830

## Summary
This pull request overhauls the saved object management workflow by
introducing the concept of ownership for SOs - specifically enabled for
dashboards only at the moment. Owners and administrators can now control
a new write-restricted flag on their objects, allowing them to keep work
draft/uneditable state before publishing. This change enables users to
define who can modify shared objects, providing a crucial capability to
manage and share dashboards.


## Release note
Kibana Dashboards now support ownership and "write_restricted" mode.
Users can now keep dashboards publicly editable or in a write-restricted
state until they are ready to publish, giving them more control over who
can edit their dashboards, regardless of broader space permissions.


## How to test

### Serverless
Please reach out to me via slack or in the project channel
(#read-only-dashboards) to be invited to the serverless environment
where this feature has been enabled.

### Local

- Clone this PR
- Enable the feature by editing kibana.yml to include 
```
savedObjects.enableAccessControl: true
```
- Start ES and Kibana as you would
- Once started, seed Kibana with sample data. This should create a few
dashboards.
- Navigate to dashboards and create a new one.
- In the share modal, change the view mode `Everybody in the space Can
View`,
<img width="500" height="410" alt="image"
src="https://github.com/user-attachments/assets/b895442f-cce3-41a6-8b47-d206a9afbf43"
/>

- Now create a new role which grants access to indices and dashboards
all. Create a new user and then assign that role to the newly created
user.
<img width="500" height="410" alt="image"
src="https://github.com/user-attachments/assets/dd5251e1-a3b5-41a8-abc1-7e67399d65d2"
/>

- Login as the new user and navigate to the dashboard you had initially
set as `Can view`. You'll see that you're not able to edit the dashboard
and a warning like
<img width="500" height="410" alt="Screenshot 2025-11-28 at 12 30 50"
src="https://github.com/user-attachments/assets/1f71ccc7-9dc6-4a68-9a2c-540aa74e4f03"
/>



###  Local (2nd option)

You can also follow the instructions in
#224411 that detail how to use
the funtional test runner to test this using the test plugin created for
this feature.

### Risk matrix

- What happens when your feature is used in a non-default space or a
custom
  space? Works as expected
- What happens when there are multiple Kibana nodes using the same
Elasticsearch
  cluster? Does not depend on functionality of kibana nodes
- What happens when a plugin you depend on is disabled? Changes are in
core and security - both are always available
- What happens when a feature you depend on is disabled? No dependency
- What happens when a third party integration you depend on is not
responding? No third party inregration
- Does the feature work in Elastic Cloud? Yes
- Does the feature create a setting that needs to be exposed, or
configured
  differently than the default, on the Elastic Cloud? No
- Is there a significant performance impact that may affect Cloud Kibana
  instances? No
- Does your feature need to be aware of running in a container? No
- Does the feature Work with security disabled, or fails gracefully? If
disabled, fails gracefully.
- Are there performance risks associated with your feature? No
- Could this cause memory to leak in either the browser or server? No
- Will your feature still work if Kibana is run behind a reverse proxy?
Yes
- Does your feature affect other plugins? No, other plugins could choose
to use it if registering a SO with ownable types
- Are migrations handled gracefully? Does the feature affect old indices
or saved objects? Yes, migrations taken care of.
- Are you using any technologies, protocols, techniques, conventions,
libraries, NPM modules, etc. that may be new or unprecedented in Kibana?
No

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jeramy Soucy <jeramy.soucy@elastic.co>
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
Co-authored-by: Christiane (Tina) Heiligers <christiane.heiligers@elastic.co>
Co-authored-by: Krzysztof Kowalczyk <krzysztof.kowalczyk@elastic.co>
Co-authored-by: Gerard Soldevila <gerard.soldevila@elastic.co>
seanrathier pushed a commit to seanrathier/kibana that referenced this pull request Dec 15, 2025
Closes elastic/kibana-team#808

The respective teams have been raising PRs against this feature branch.
Approved PRs merged so far:
- elastic#221916
- elastic#224411 
- elastic#239973 
- elastic#241101
- elastic#238468
- elastic#233552
- elastic#228416 
- elastic#241168
- elastic#244746
- elastic#244830

## Summary
This pull request overhauls the saved object management workflow by
introducing the concept of ownership for SOs - specifically enabled for
dashboards only at the moment. Owners and administrators can now control
a new write-restricted flag on their objects, allowing them to keep work
draft/uneditable state before publishing. This change enables users to
define who can modify shared objects, providing a crucial capability to
manage and share dashboards.


## Release note
Kibana Dashboards now support ownership and "write_restricted" mode.
Users can now keep dashboards publicly editable or in a write-restricted
state until they are ready to publish, giving them more control over who
can edit their dashboards, regardless of broader space permissions.


## How to test

### Serverless
Please reach out to me via slack or in the project channel
(#read-only-dashboards) to be invited to the serverless environment
where this feature has been enabled.

### Local

- Clone this PR
- Enable the feature by editing kibana.yml to include 
```
savedObjects.enableAccessControl: true
```
- Start ES and Kibana as you would
- Once started, seed Kibana with sample data. This should create a few
dashboards.
- Navigate to dashboards and create a new one.
- In the share modal, change the view mode `Everybody in the space Can
View`,
<img width="500" height="410" alt="image"
src="https://github.com/user-attachments/assets/b895442f-cce3-41a6-8b47-d206a9afbf43"
/>

- Now create a new role which grants access to indices and dashboards
all. Create a new user and then assign that role to the newly created
user.
<img width="500" height="410" alt="image"
src="https://github.com/user-attachments/assets/dd5251e1-a3b5-41a8-abc1-7e67399d65d2"
/>

- Login as the new user and navigate to the dashboard you had initially
set as `Can view`. You'll see that you're not able to edit the dashboard
and a warning like
<img width="500" height="410" alt="Screenshot 2025-11-28 at 12 30 50"
src="https://github.com/user-attachments/assets/1f71ccc7-9dc6-4a68-9a2c-540aa74e4f03"
/>



###  Local (2nd option)

You can also follow the instructions in
elastic#224411 that detail how to use
the funtional test runner to test this using the test plugin created for
this feature.

### Risk matrix

- What happens when your feature is used in a non-default space or a
custom
  space? Works as expected
- What happens when there are multiple Kibana nodes using the same
Elasticsearch
  cluster? Does not depend on functionality of kibana nodes
- What happens when a plugin you depend on is disabled? Changes are in
core and security - both are always available
- What happens when a feature you depend on is disabled? No dependency
- What happens when a third party integration you depend on is not
responding? No third party inregration
- Does the feature work in Elastic Cloud? Yes
- Does the feature create a setting that needs to be exposed, or
configured
  differently than the default, on the Elastic Cloud? No
- Is there a significant performance impact that may affect Cloud Kibana
  instances? No
- Does your feature need to be aware of running in a container? No
- Does the feature Work with security disabled, or fails gracefully? If
disabled, fails gracefully.
- Are there performance risks associated with your feature? No
- Could this cause memory to leak in either the browser or server? No
- Will your feature still work if Kibana is run behind a reverse proxy?
Yes
- Does your feature affect other plugins? No, other plugins could choose
to use it if registering a SO with ownable types
- Are migrations handled gracefully? Does the feature affect old indices
or saved objects? Yes, migrations taken care of.
- Are you using any technologies, protocols, techniques, conventions,
libraries, NPM modules, etc. that may be new or unprecedented in Kibana?
No

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jeramy Soucy <jeramy.soucy@elastic.co>
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
Co-authored-by: Christiane (Tina) Heiligers <christiane.heiligers@elastic.co>
Co-authored-by: Krzysztof Kowalczyk <krzysztof.kowalczyk@elastic.co>
Co-authored-by: Gerard Soldevila <gerard.soldevila@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants