Skip to content

Allow the SavedObjectsClient to work outside of a space #131254

@jportner

Description

@jportner

Background

The SavedObjectsClient (SOC) was designed to work in the current space (aka "active space") by default. Consumers didn't need to specify what space they were in, it is determined by the HTTP request context which they use to obtain an instance of the SOC. The spaces SOC wrapper determines the active space, and sets the namespace option accordingly.

Over time we've had the need to change some SOC functions so they can work in multiple spaces. This includes:

With the exception of find/openPointInTimeForType/createPointInTimeFinder, the SavedObjectsClient always operates within the active space. Even for those other functions that can work in multiple spaces, the authorization layer still ensures that the user is authorized in the current space.

The remaining SOC functions only operate in the current space:

  • checkConflicts
  • get
  • resolve
  • bulkResolve
  • update
  • delete
  • collectMultiNamespaceReferences
  • updateObjectsSpaces
  • removeReferencesTo
  • incrementCounter

Feature

It would be useful to have the option to use the SavedObjectsClient in a space-agnostic manner. For example, this could be used to drive the ML Job Management page so you can manage jobs across all spaces that you have access to (#131134).

Unfortunately it's not trivial to change the entire SOC to behave in this manner, because some saved object types are still isolated to an individual space (namespaceType: 'single') and they do not have globally unique IDs.
I can think of three approaches to solve the ML Job Management use case.

Approach 1

ML jobs use namespaceType: 'multiple' and they do have globally unique IDs. We could potentially allow consumers to instantiate a SOC that works in a space-agnostic manner, but only for object types that have globally unique IDs. If a SOC was instantiated in this way, it would need to throw an error if a consumer attempted to use it for an isolated object type.

This would entail:

  • Changing the base SOC to allow instantiating it with this option
  • Changing the saved objects repository (SOR) to behave differently when conducting preflight checks and deserializing objects
  • Changing the SOR to force consumers to specify a namespace (or namespaces) when creating new objects
  • Changing the security SOC wrapper to handle authZ checks differently

Since the security SOC wrapper doesn't have access to the preflight check results that the SOR makes, it would have to check that the user is authorized to take that action in all spaces. This limitation would mean that users who are not "global admins" (e.g., they only have access to Kibana features in specific spaces) would never be authorized to make requests using this SOC.

Approach 2

This is a variation of Approach 1. If the security SOC wrapper had access to preflight check results, it could check authorization after the preflight check but before calling the base SOC function. We don't have the capability to do this today, but we'll likely need it anyway to implement #82725.

Approach 3

Alternatively, to support use cases like this one in the short term, the consumer could (1) create a SOC without the Spaces wrapper, (2) find objects across '*' spaces, and (3) take any subsequent update/delete actions in the context of a space where that object actually exists by specifying the namespace option.

One upside of this approach is that it only requires minimal changes to the SOC. Specifically the security SOC wrapper's find function would need to be tweaked to expand '*' to the list of actual spaces that exist, so that it can subsequently check authorization.

The ShareToSpaceFlyout logic would also need to be tweaked to allow the consumer to specify a custom API endpoint for collectMultiNamespaceReferences (AKA getShareableReferences).

A downside of this approach is that it's susceptible to race conditions. For example:

  • User loads a page with all ML jobs
  • One job "foo" exists in spaces "A" and "B"
  • A second user unshares "foo" from space "A" -- now it only exists in space "B"
  • The first user tries to make a change to "foo" -- it attempts to do this in the context of space "A" (because it has to specify a space, so the client picks the first space that the job currently exists in). However, the job no longer actually exists in space "A" so the user would see a 404 error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Feature:Saved ObjectsFeature:Security/SpacesPlatform Security - Spaces featureTeam:CorePlatform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t//Team:SecurityPlatform Security: Auth, Users, Roles, Spaces, Audit Logging, etc t//discussenhancementNew value added to drive a business resulttriage_needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions