-
Notifications
You must be signed in to change notification settings - Fork 24.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom privilege definition on roles #29820
Comments
Original comment by @skearns64:
I'm +1 to an "effective privileges" API (LINK REDACTED), but would it be possible to also integrate these custom privileges with the |
Original comment by @joshbressers: After a chat with the Kibana folks they're going to want this feature to enable Spaces properly (they can live without OLS for now). We will probably want to bump the priority of this feature. |
Original comment by @tvernum: @epixa (and @jordansissel / @andrewvc if this is going to be useful to Logstash) I've started implementing this, and there are 2 potential features that have a big impact on the implementation complexity. They're both achievable if they're truly useful (I have a prototype already), but I don't want to do them unless we actually need them.
pre-defined privilegesWe have a choice, either privileges are just a string, or they are pre-defined objects. I'll do my best to explain as succintly as possible. If we have "just a string", then a role can have:
And that's easy. But it means that So
would return
And, likewise, So, if Kibana (or Logstash, etc) wants to have a rich set of privileges like
All of those end up trying to replicate functionality that ES already has for cluster and index privileges, because we treat those privileges as objects rather than strings. We can do that for custom privileges, but it requires creating a full API to CRUD a custom privilege, and it means that resolving a user's custom privileges depends on reading them in from security index, so it's not just implementation effort, it's also runtime complexity.
And then
would work correctly for users with "all", "write" or "delete"
I've elected to use a tree based model for custom actions there because it's worked well for ES, and it seems logical to do the same thing for custom privileges if we go down the pre-defined objects path, but it's certainly open for discussion. privileges on resourcesCluster privileges are all or nothing - you have "monitor" for the whole cluster, or none of it. I can make custom privileges work like cluster privileges, or like index privileges (with the latter being added complexity). Side Note: NamingDuring my prototype, I found myself getting the words "cluster" and "custom" confused a lot in my typing. I'd like to name "custom" privileges something else. My suggestions would be (in order of my preference)
|
Original comment by @epixa: cc @kobelb as he'll be doing or coordinating most of the work around this stuff on Kibana's end. ImplementationKibana will need the ability to manage a role hierarchy, and I think from an end-user perspective it should behave similarly to ES.
Other than the existence of additional REST endpoints, how does the complexity of this implementation differ from the way ES privileges are handled today? It seems like we need to implement the complexity somewhere one way or another, so to me it's a question of whether we do it in ES or in Kibana, so understanding exactly what would be new complexity to ES is important here.
This is a little tricky for Kibana. On the surface, we want kibana-wide privileges which are sort of like cluster level privileges. There wouldn't be any concept of "write" for .kibana but only "read" for .reporting, for example. You'd simply have the "write" privilege for all of kibana. The challenge here is that some people run multiple different kibana apps on a single cluster. I can only think of one way to support this: we do index-level permissions and then hang all of the permissions for a single kibana install off of its corresponding .kibana index. Kibana then always check privileges on its index regardless of whether it ultimately accesses somewhere else like .reporting. I'm open to ideas here, though! NamingI don't have strong opinions about this, but if we do cluster-level privileges, calling them "application" privileges doesn't seem accurate. If we did index level privileges or if ES somehow tracked the notion of external applications, then application privileges would make a lot of sense to me. External privileges seems fine either way. |
Original comment by @kobelb: Court's done a good job, like usual, summarizing Kibana's usage/needs.
I think this makes sense, and I can't think of a better alternative. The only other option I can think of would be to keep the reporting custom privileges/roles in the .reporting index, but then we'd have to enumerate all of the application indices when allowing users to choose custom roles for users, making this process more complicated. I don't see any downsides to putting all of these roles/privileges in the .kibana index that corresponds to the .reporting index. |
Original comment by @tvernum:
The main difference is that the existing privileges are all fixed in code, and available with zero-lookup. API-defined privileges need to be stored in an index (technically there's other places, but it would be an index) which means we need to do I/O and async lookups and deal with unavailable shards, etc. All of which is totally fine - we do it for users, roles, role mappings, etc etc. But it's overhead that we don't want to pay for if no one needs it. |
Original comment by @kobelb:
It'll definitely be used by Kibana, and would provide a more consistent approach, so I'd also prefer it was added on the Elasticsearch side of things. |
Original comment by @tvernum:
In my examples above, I name spaced all the Kibana privileges, e.g. |
Original comment by @clintongormley: I think before we can answer a question about how to structure these privileges, we should make a big list of all the privileges that we need. The answer should fall out of that |
Original comment by @epixa: We don't know all of the privileges we'll need, but I can give an example that includes some that we do know. For the sake of not conflating our needs with any specific implementation, I'm just going to describe intentions here rather than actually giving each privilege a specific name. Nesting is represented with indents, so to give access to all children, you'd only need to give access to the parent.
This is just a straw man. I can envision a totally different approach to privilege hierarchy that breaks down privileges by the [core_]plugins that they are relevant to alongside a single set of "global" admin level privileges. From an ES perspective, the two approaches are identical. |
Original comment by @kobelb:
Just to clarify how this will likely work, when we create a specific role that has the custom Kibana privileges it will be scoped to specific indices, as this is the way that Elasticsearch roles work currently. By default we'd created the role that grants privileges to the default Within Kibana's server, we'd be verifying that the user has a role with specific custom privileges on the index. By convention, we'd be requiring users to create these namespaces themselves. |
Original comment by @jaymode: I had a chat today with @AlexP-Elastic @swallez @zanbel about the future use of x-pack security in ECE. One thing that they are looking at is using x-pack roles as the basis for authorization; currently they are only doing it at the role name if I understood correctly. I asked them to take a look at this issue and provide feedback if this is something that they would envision using. |
Original comment by @jordansissel: /cc @andrewvc @tsg @monicasarbu -- I don't think anyone from Logstash has chimed in yet about custom privilege needs. Background for Logstash: Having custom privileges may enable more powerful API in Logstash by allowing API calls to be authenticated by x-pack security in Elasticsearch. In the past, I have rejected requests for things like a step debugger, simulate api, etc, for lack of any security in the Logstash API. |
Original comment by @tvernum: @kobelb Here's the draft proposal I promised BackgroundElasticsearch implements
An example of where that goes wrong is with a naive implementation of roles, whereby
But if the role is The problem is that the runtime security checks really ought to be testing for access to "functions" (aka "features", "capabilities", or "actions") rather than checking for specific roles. In the ES security model, "Privileges" are on the user-management side, and "Actions" are on the runtime-checking side, and the linkage is that a Privilege defines all the Actions that it grants (with support for wildcards and regexp). ActionsSo, step 1 is to define the Actions that represented the Kibana features that need security checks.
As a recommendation, actions should exist in a logical tree, separated by So, I took a stab at some proposed actions from what @epixa described, and what I know of Kibana:
I don't really know what the difference between This means that:
PrivilegesPrivileges are how we can group multiple action together into something that makes sense for a customer to work with. The constraints I'm proposing for privileges names are:
I don't really know what the right names/breakdown for these are, but I've taken a rough guess:
Runtime checksWhen you call the
If a user has |
Original comment by @kobelb: When discussing this functionality previously, I was pushing for us to be able to define these custom privileges on specific indexes in Elasticsearch so we could scope the privileges to a specific instance of Kibana by specifying the appropriate .kibana index. After further reflection, this approach of custom privileges on indieces isn't something that we wish to do any longer and instead we'd like to utilize the approach that @tvernum outlined here:
From my understanding, using the namespacing approach would work nicely with your proposal. We'll have to figure out a way to get all of the custom privileges/actions into Elasticsearch, but that's a technical detail I'm sure we can figure out. |
Original comment by @kobelb: I've been thinking through Kibana's usage of the custom privileges/actions, and how we'd initially create them and how upgrades would work. The way I'm envisioning it, the privileges themselves would be rather static and we'd only be adding privileges during a minor upgrade; however, I foresee us wanting to change the actions for the privileges themselves rather frequently as we add/remove/refactor functionality. The following situation assumes that Kibana executes a series of PUT requests on startup to ensure the privileges and actions are persisted to Elasticsearch before we start up Kibana. The very first time that we deploy a version of Kibana that utilizes the custom privileges and actions, we can execute a PUT request for a custom privilege that is mapped to any number of actions. However, if we were to release a new version of Kibana that added to the list of actions, and one of the older instances of Kibana was to restart before we had a chance to upgrade all instances, it would overwrite the new list of actions. The only thing that I've been able to come-up with to solve this situation is Elasticsearch's custom privileges/actions themselves implementing the concept of a "version" or the Kibana server code itself doing the privilege to action mappings (that way we can have multiple "versions" running concurrently). Perhaps the other teams that are considering utilizing the custom privileges/actions have an alternate solution? |
Original comment by @clintongormley:
I think it would be a mistake to have two versions of kibana running against the same kibana index (and the same kibana privileges namespace). Not just from the privileges side, but from the kibana objects side too. Instead, we should store a minimum version somewhere (perhaps kibana index? perhaps custom privileges namespace?), and earlier versions should not overwrite later versions. |
Original comment by @tvernum:
We can definitely support metadata on custom privileges - we have it for almost every other object type in security, so it's pretty easy to include here. But by itself that's not quite enough, you could still get a race condition if you always try and update-privileges-unless-they-are-newer-than-my-version. |
Original comment by @kobelb:
I like Clint's suggestion here of storing the version of Kibana in the |
Original comment by @kobelb: After further thought, even if we were to check the version numbers against the .kibana index on startup, how would we ensure that multiple instances of Kibana with different versions wouldn't get past that check, both thinking they're the correct version, and then proceed to do the startup logic, leading to race conditions and inconsistent state? |
Original comment by @tvernum:
Make your startup logic idempotent? |
Original comment by @kobelb:
That was the initial plan, until multiple versions came into play. Assuming the following situation where we're currently running Kibana 6.2, and then there are two "new" instances just coming up 6.3 and 6.4. If both 6.3 and 6.4 were to get past the update/check version and then both execute their series of idempotent PUTs of the privileges and actions, we end up in an inconsistent state. Even though this situation is rather unlikely, I'm not comfortable with it being possible if we're using the startup logic to essentially control who accesses what inside of Kibana. |
Original comment by @clintongormley: The only way you're going to get around that is with locking, which then introduces the problem of refreshing and timing out the locks (combined with skewed clocks). I think we can safely put this into the realm of PEBKAC and just tell people not to do it. |
Original comment by @kobelb: If there isn't a good solution to synchronizing the privileges and actions into Elasticseach across versions, I'd rather keep the privileges in Elasticsearch but the actions that correspond to these privileges in Kibana source code. The main advantage that we get from storing the actions and their mapping to privileges in Elasticsearch is the ability to call the "hasPrivilege" API in Elasticsearch and have ES handle the actions mapping to the actual granted privileges. However, if this comes at the expense of potentially allowing users to perform actions in Kibana that they aren't authorized to do so, it's really not worth it. If we were talking about anything else besides security, accepting the PEBKAC would be just fine, but we're talking about authorization here. |
Original comment by @kobelb: We might have a way to get around the mixed-versions problem... I believe there are restrictions in-place between which versions of Kibana can communicate with which versions of Elasticsearch, there's potential for us to utilize this functionality to prevent the scenarios that I've previously outlined. Let me track down whether this is a possible solution before anyone else wastes effort addressing this concern. |
Original comment by @kobelb: The way that we currently implement the version restrictions on Kibana to ES communication won't help us in this situation, since we allow older versions of Kibana to communicate with newer versions of Elasticsearch. Additionally, this version check in Kibana is only done on startup and then periodically as part of our healthcheck, so there's a window of opportunity for any version of Kibana to communicate with any version of Elasticsearch. My concerns have been previously expressed through a number of comments, so in an effort to communicate my concerns to generate potential alternate solutions, I'm going to attempt to summarize my concern below. Apologies to those of you who have been following along and have a grasp of the issue at hand, feel free to ignore the following. In this proposal we will be storing all privileges and their mappings to actions in Elasticsearch itself. Borrowing from @tvernum's examples earlier, we could create the following privileges that are mapped to specific actions:
These custom privileges and actions would be created within Elasticsearch through a series of PUT requests on startup, that themselves would be idempotent. Elasticsearch roles would then be created that are associated with these custom privileges, and users would be assigned to these roles. Kibana would then determine whether a user was granted access to a specific action by executing a request similar to the following against Elasticsearch:
The crux of the problem comes down to us allowing different versions of Kibana to communicate with different versions of Elasticsearch, so when Kibana is upgraded that there is no downtime. This creates a problem when synchronizing the privileges and actions to Elasticsearch on startup, and when different versions of Kibana are utilizing the With regard to the problem of synchronizing the privileges and actions to Elasticsearch, if two instances of Kibana with different versions executed their startup logic at the same time we would have their series of PUT requests for the different privileges interleave, leading to an unpredictable state. @clintongormley suggested performing a check of the version of Kibana before executing the synchronization, so that we only executed the privilege and action PUTs when the version matches the version specified in the .kibana index, but this doesn’t work if two new versions of Kibana came on line at the same time and got past the version check and then began executing their series of PUTs. An alternate solution that doesn’t have this limitation is if we could execute a single PUT for all privileges and their actions, so the last one to execute the startup logic wins, but this brings us to the second issue. To support upgrading Elasticsearch first and then upgrading Kibana, we currently allow older instances of Kibana to communicate with newer instances of Elasticsearch. This means that we’ll have multiple different versions of Kibana executing the “_has_privileges” check against the same instance of Elasticsearch. The actions that are tied to the different privileges will likely change for the different versions of Kibana, and as such each version requires this If we want to store the actions to privileges mappings in Elasticsearch, I don’t see how we can get around having the privileges to actions mappings themselves be versioned. This could be done by adding a parameter when the privileges are inserted, specifying the version:
And then when we check the actions, we would specify the version of the actions that we’re checking:
We’d want the roles to be associated with the “un-versioned” privilege, so that when we do upgrade the privileges to actions mappings, we wouldn’t be requiring the user to go through an mutate all of their existing roles. If we only stored the privileges themselves in Elasticsearch, we wouldn’t have to do this versioning of the privileges to actions mapping, and instead we could do this in the Kibana server code and this would be versioned implicitly. While I see there being benefit to us always performing authorization via the |
Original comment by @clintongormley: @kobelb We neither test nor support running multiple versions of kibana against the same index. It is expected that there will be some downtime when upgrading. |
Original comment by @kobelb: @clintongormley we do for minors: https://github.com/elastic/kibana/blob/aa69744f67547484e3b80d122a6c83baa7ce4d80/src/core_plugins/elasticsearch/lib/__tests__/is_es_compatible_with_kibana.js#L27 This allows us to run Kibana 6.2.0 against ES 6.3.0 |
Original comment by @clintongormley: @kobelb that's different, that's about different versions of kibana and elasticsearch. The problem we started with was two different versions of kibana running against the same kibana index at the same time. That isn't supported. So if we store the kibana version in the index, we can check that version at startup time, problem solved. |
Original comment by @kobelb:
Just to be clear, we do support this now. I was just able to spin up an instance of Elasticsearch 6.2.0, Kibana 6.1.0 and Kibana 6.2.0 and they're all operating normally. If we were to change this behavior, and store the version of Kibana in the .kibana index, we'd need some way to check this version in the .kibana index before executing the If we were to use the Elasticsearch version itself to perform a similar function, we'd need some way to specify the expected version number in the |
Original comment by @clintongormley:
The fact that it appears to work is not the same as supporting it. There are no tests, we have no forwards compatibility policy, and we document shutting down the old kibana before starting the new one: https://www.elastic.co/guide/en/kibana/current/upgrade-standard.html
If the user has the ability to install new versions of the kibana server (which includes providing the kibana user credentials), then what are we trying to defend against? Only user error. I think this is way out of scope. The product can only function within the stated rules: shut down the old server before starting the new one. |
Original comment by @kobelb:
Nowhere in those docs do we recommend shutting down all instances of Kibana across the entire Elasticsearch cluster before starting a single instance of the new Kibana version up. Those instructions appear to be largely targeted at upgrading a single instance of Kibana. The rolling upgrade of Kibana is something that I've been told that we support; however, I don't see it clearly documented anywhere. However, the way the code is written, it definitely appears to work that way. @epixa do you happen to know of any definitive documentation whether we support the rolling upgrade of Kibana or not?
I'm trying to ensure that we're authorizing access to Kibana in a predictable and consistent manner. If starting up a single new instance of Kibana authorizes a user in an older version of Kibana to perform actions they previously were unable to perform, this seems like a serious security vulnerability. |
Original comment by @tvernum: While this feature is a helpful example of the sorts of problems that can come up when trying to support (or prevent) mixed versions, trying to solve it here is not going to be effective. If you support mixed versions, then it affects everything. Any feature could write a change to the Kibana index that is not backwards compatible with earlier Kibana versions. So, if there's a desire to officially support this, then it's a big task. Maintaining that sort of backwards compatibility in ES (to support rolling upgrades) takes a lot of time and effort. You don't want to embark on that journey without some serious consideration. I assume that the team will conclude that it's not worthwhile to support mixed versions, in which case I have a solution for you. We can definitely support a bulk privileges API to make this as atomic as possible (it won't actually be atomic, because ES doesn't work that way, but we'll minimise the window). Then, just use a psuedo action to control version access. When you install the privileges, include
etc (but watch out for :all) Then when you want to check privileges, include a check for |
Original comment by @kobelb: After talking with @epixa, we're alright with making it so that when a new instance of Kibana starts up it essentially makes all older instances running against the same cluster no longer authorize users, so the proposal that @tvernum just made solves that situation. The fact that we're allowing this situation currently, with a Kibana 6.2 and 6.1 running at the same time against Elasticsearch 6.2 is indeed "not supported" as you were alluding to @clintongormley, it just happens to work somewhat, yet in unpredictable ways. Apologies for my misunderstanding earlier. |
Original comment by @legrego: How do we want to assign custom permissions to roles? Will we modify the existing role API endpoints to include this, or will it be managed by a separate endpoint? I'm trying to stub out the ES implementation in Kibana, and I want to make sure I'm moving in the right direction |
Original comment by @tvernum: There will be new APIs to create custom privileges, but we will use the existing roles API to associate those privilges with roles. |
Original comment by @kobelb: @tvernum is it safe to assume that work is on-going on implementing the custom privileges/actions? I know that there has been a lot of "chatter" from the Kibana team in regard to our requirements, but it feels like this has stabilized and your initial proposal seems to satisfy our envisioned use-cases for RBAC. |
Original comment by @tvernum: Yes, it's my plan to pick it up again with a target of 6.4. It would be good to hear more from cloud EMAIL REDACTED / @swallez ) and ingest EMAIL REDACTED / @tsg) about whether this seems to suit their future needs, but I think we're implementing a full featured setup, so if it works for Kibana it probably works more generally. |
Original comment by @clintongormley: @tvernum I know that @kobelb is wanting to use the custom privileges feature for work he's doing for the 6.4 release, so it would be good to come up with at least an API spec as early as possible so that they can work in parallel with you. |
Original comment by @tvernum: NamingI've called them "application privileges" because custom and cluster are too close and were bound to cause an implementation bug at some point where IDE auto-completion picked the wrong field somewhere. Application privileges have an Application names must match the regex Privilege actions must contain a Defining PrivilegesTher eare 3 new end points: GET, PUT, DELETE privilege On my WIP they are:
For the POST of multiple privileges the JSON looks like:
Assigning PrivilegesRoles gain a new
"resources" follow the same matching rules as index names, but their meaning is entirely up to the consumer. They could be used for Kibana objects if that's helpful, or you can just assign the Checking privilegesThe
The "privileges" field can contain a mix of privilege-names (like
The results of
|
Original comment by @tvernum: I've updated the description above to reflect a recent change I've made to make the application name explicit. |
This commit introduces "Application Privileges" to the X-Pack security model. Application Privileges are managed within Elasticsearch, and can be tested with the _has_privileges API, but do not grant access to any actions or resources within Elasticsearch. Their purpose is to allow applications outside of Elasticsearch to represent and store their own privileges model within Elasticsearch roles. Access to manage application privileges is handled in a new way that grants permission to specific application names only. This lays the foundation for more OLS on cluster privileges, which is implemented by allowing a cluster permission to inspect not just the action being executed, but also the request to which the action is applied. To support this, a "conditional cluster privilege" is introduced, which is like the existing cluster privilege, except that it has a Predicate over the request as well as over the action name. Specifically, this adds - GET/PUT/DELETE actions for defining application level privileges - application privileges in role definitions - application privileges in the has_privileges API - changes to the cluster permission class to support checking of request objects - a new "global" element on role definition to provide cluster object level security (only for manage application privileges) - changes to `kibana_user`, `kibana_dashboard_only_user` and `kibana_system` roles to use and manage application privileges Closes #29820 Closes #31559
Original comment by @jaymode:
In order to support security for other components of the stack, we will provide a primitive on the roles that exist in elasticsearch. This primitive is a new entry or entries alongside the current indices and cluster entries. The entries would contain an array of arbitrary string values.
If other applications in the stack need the ability to get a view of the current user's combined privileges, we would need an API to render this combined view. When merging roles we should simply combine all of the lists.
The text was updated successfully, but these errors were encountered: