Add opt-in config to allow read-only users to access Discover and Visualize#2416
Open
seanthegeek wants to merge 4 commits into
Open
Add opt-in config to allow read-only users to access Discover and Visualize#2416seanthegeek wants to merge 4 commits into
seanthegeek wants to merge 4 commits into
Conversation
Adds opensearch_security.readonly_mode.allow_discover (default false). When enabled, Discover is added to the read-only app allowlist so operators can surface it to users mapped to the read-only role. Default behavior is unchanged; existing deployments that rely on the current blocking behavior as informal data isolation see no change on upgrade. - server/index.ts: extend readonly_mode config schema with the flag. - public/types.ts: expose allow_discover on ClientConfigType. - public/plugin.ts: compute the readonly app allowlist from the flag. - public/test/plugin.test.ts: cover both states of the flag. - DEVELOPER_GUIDE.md: document the new option near readonly_mode.roles. Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
Importing AppStatus from src/core/public pulls monaco-editor into the test at module-load time, which crashes under jsdom before any test runs. Assert on the shape of the updater's return value instead, so the test only needs the mocks module. Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
Modern OSD hosts Discover inside the data-explorer app at /app/data-explorer/discover. The legacy `discover` app is still registered but only as a thin shim that client-side redirects to data-explorer. The AppUpdater status check runs before mount, so blocking either id produces a broken UX for read-only users even with allow_discover: true — "Application not found" on the legacy URL, or a dead nav-menu "Discover" entry (the nav link references `discover`, not `data-explorer`). Allowlist both together and document the reasoning. Also avoid importing AppStatus from src/core/public in the test; that pulls in monaco-editor which crashes under jsdom at module-load time. Assert on the shape of the updater's return value instead. Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
Member
|
Thank you @seanthegeek. This really underscores the need for better tools for admins to select what different sets of users can see in the menus. I'm not opposed to adding a new setting in the interim while better organizational tools are built for admins. |
Contributor
Author
|
@cwperks Agreed, and to ensure that other applications only show what a user has access to do. For example, "add data", "manage", "dev tools", "app directory". So users don't end up with "application not found" errors. |
Mirrors the existing opensearch_security.readonly_mode.allow_discover flag with opensearch_security.readonly_mode.allow_visualize (default false). When enabled, the Visualize app id is added to the read-only app allowlist so operators can surface it to users mapped to the read-only role. Default behavior is unchanged; existing deployments that rely on the current blocking behavior see no change on upgrade. Unlike Discover, Visualize is registered under a single app id, so only `visualize` needs to be allowlisted — no second shim id the way `data-explorer` shadows `discover`. - server/index.ts: extend readonly_mode config schema with the flag. - public/types.ts: expose allow_visualize on ClientConfigType. - public/plugin.ts: reshape the allowlist as a spread so each opt-in flag contributes independently without nested conditionals. - public/test/plugin.test.ts: add a parallel describe block for the flag (unset/false/true, independence from allow_discover, combined both-flags-true case); also fix runAndGetUpdater to read the current setup's BehaviorSubject rather than the first one, which matters once a test calls it more than once. - DEVELOPER_GUIDE.md: document the new option alongside allow_discover. Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2416 +/- ##
==========================================
+ Coverage 71.59% 71.69% +0.09%
==========================================
Files 101 101
Lines 3010 3017 +7
Branches 511 531 +20
==========================================
+ Hits 2155 2163 +8
Misses 699 699
+ Partials 156 155 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds two new opt-in configuration options (both defaulting to
false) that extend the read-only app allowlist with apps that are natural fits for a read-only audience:opensearch_security.readonly_mode.allow_discover— when enabled, adds Discover to the read-only allowlist.opensearch_security.readonly_mode.allow_visualize— when enabled, adds Visualize to the read-only allowlist.Default behavior is unchanged — read-only users continue to be blocked from both apps unless an operator explicitly opts in. The flags are independent.
Because modern OSD hosts Discover inside the
data-explorerapp at/app/data-explorer/discoverwhile the legacydiscoverapp is still registered as a thin redirect shim, the Discover allowlist extension covers both ids. Visualize has no such shim and only requires its singlevisualizeapp id. The reasoning for the Discover/data-explorer pairing is documented inline at the declaration site so a future reader doesn't try to consolidate them.Category
Enhancement
Why these changes are required?
Discover and Visualize are view-oriented applications that align naturally with the semantics of the read-only role. Discover exposes saved-search and ad-hoc query views; Visualize exposes saved-visualization views. Operators running read-only tenants for analyst or client-facing use cases currently have no supported way to expose either app to those users, even though doing so does not grant any write capability — the saved-object write paths remain blocked by the OpenSearch role.
However, some existing deployments may rely on the current blocking behavior as a form of informal data isolation — keeping read-only users confined to curated dashboards rather than browsing indices or composing charts directly. Flipping this behavior by default would break those deployments. Each app is therefore gated behind an explicit opt-in flag so existing installations see zero behavior change on upgrade, and operators can opt into Discover, Visualize, both, or neither.
For operators who want real data confinement (not just UI hiding), the correct tool remains document-level and field-level security on the OpenSearch role — UI allowlisting has never been a security boundary. This PR does not change that; it only exposes a supported way to surface Discover and Visualize when it is appropriate.
What is the old behavior before changes and new behavior after changes?
Old behavior: Read-only users are always blocked from Discover and Visualize. Neither app appears in the navigation; direct URL access returns an "Application not found" error.
New behavior: Default is unchanged. Operators can opt in per-app in
opensearch_dashboards.yml:opensearch_security.readonly_mode.allow_discover: trueadds both thediscoveranddata-explorerapp ids to the read-only allowlist. Users holding the read-only role can access Discover via the nav menu,/app/discover(legacy URL that redirects), and/app/data-explorer/discover(the modern URL).opensearch_security.readonly_mode.allow_visualize: trueadds thevisualizeapp id to the read-only allowlist. Users holding the read-only role can access Visualize via the nav menu and/app/visualize.All other read-only restrictions (no saved-object writes, no index management, etc.) remain enforced.
Issues Resolved
Enhancement follow-up to the UX improvements explored in #2415. Not a backport.
Testing
Unit tests.
public/test/plugin.test.tshas areadonly app allowlist — opt-in flagsdescribe block with parallelallow_discover flagandallow_visualize flagsub-blocks, plus a shared baseline check. Coverage:allow_discover: flag unset → bothdiscoveranddata-explorerblocked; flagfalse→ both blocked; flagtrue→ both allowed; flagtrue→ other non-allowlisted apps (e.g.visualize,management) still blocked.allow_visualize: flag unset →visualizeblocked; flagfalse→ blocked; flagtrue→ allowed; flagtrue→ other non-allowlisted apps (e.g.discover,data-explorer,management) still blocked.allow_discover: truealone does not unblock Visualize;allow_visualize: truealone does not unblock Discover; bothtruetogether unblocks all three ids.homeanddashboardsare accessible across every combination of the two flags.All 14 tests in
plugin.testpass locally (yarn test:jest_ui --testPathPattern=plugin.test).Manual testing. On a local docker-compose stack (OpenSearch + OpenSearch Dashboards 3.6.0, Security plugin built from this branch with temporary manifest retarget for local build since the 3.7.0 image is not yet published):
readonly_testmapped tokibana_read_only./app/data-explorer/discover,/app/discover, and/app/visualizeall return "Application not found". ✅allow_discover: true, allow_visualize: false: Discover accessible (nav + both URLs); Visualize still blocked. ✅allow_discover: false, allow_visualize: true: Visualize accessible (nav +/app/visualize); Discover still blocked. ✅true: both apps accessible; queries against sample indices return data in Discover; saved visualizations load in Visualize; Save controls on saved searches and saved visualizations are disabled. ✅Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.