Skip to content

Conversation

@tvernum
Copy link
Contributor

@tvernum tvernum commented May 14, 2019

Adds "_cluster" and "_index" endpoints to the get privileges API so
that builtin index and cluster privileges can be retrieved via the
Rest API

Resolves: #29771

Adds "_cluster" and "_index" endpoints to the get privileges API so
that builtin index and cluster privileges can be retrieved via the
Rest API

Resolves: elastic#29771
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security

@tvernum
Copy link
Contributor Author

tvernum commented May 14, 2019

A few notes on this:

  • I'm raising this as-is, without doc or HLRC changes (other than fixing breakages), so we can discuss the direction I've taken. I will update the client & docs when we've reached agreement.

  • This re-uses the "Get Privileges API" to get cluster + index privileges. It was always my intention when I wrote that API to add cluster + index support to it (hence calling it "get privileges" not "get application privileges") but I didn't really think through the design well enough, so now it's a bit messy.

  • The existing API is:

    • GET /_security/privilege/ to get all application privileges
    • GET /_security/privilege/{application} to get app privileges for a named application
    • GET /_security/privilege/{application}/{privileges} to get a subset of privileges for a named application
  • With this change (in v8.0), it would be:

    • GET /_security/privilege/ to get all privileges (cluster, index, application)
    • GET /_security/privilege/_cluster to get cluster privileges
    • GET /_security/privilege/_index to get index privileges
    • GET /_security/privilege/_application to get all application privileges
    • GET /_security/privilege/{application} to get app privileges for a named application
    • GET /_security/privilege/{application}/{privileges} to get a subset of privileges for a named application
  • The response output will be the same format in all cases (but we don't output empty fields)

    {
      "_cluster" : [ "all", "monitor", "etc" ],
      "_index" : [ "all", "read", "etc" ],
      "app01": {
            "priv01": {
                 "application": "app01",
                 "name": "priv01",
                 "actions" : [] ,
                 "metadata" : {}
            }
    }
    
  • When backported to 7.x it would be changed to be backwards compatible so that GET /_security/privilege/ behaves like GET /_security/privilege/_application. Otherwise the "_cluster" and "_index" response fields would be breaking. In 7.x if you want cluster/index privileges, then you need to call those endpoints explicitly.

  • The _ (_cluster etc) is because an application name must start with a lowercase letter, so this naming scheme is safe.

  • The API is arguably wrong, in that application privileges ought to be under the _application endpoint and response field (or just appplication if we no longer needed to worry about name conflicts), but to fix that we need API Versioning.

I'm proposing this approach because I think it creates the correct API at a logical level (a single API for all privileges types, with the ability to filter the output to exactly what you want), even though it has some obvious warts. Then we can fix those warts (at some point in the future) with API versioning.

I'm open to creating distinct APIs for builtin privileges, but I think that we would prefer to have it all in a single API. If I had done the design work more thoroughly the first time, then I think the direction would be obvious.

@tvernum tvernum added v7.3.0 and removed v7.2.0 labels Jun 4, 2019
@elastic elastic deleted a comment from elasticmachine Jun 4, 2019
Copy link
Contributor

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

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

I'm perfectly fine with the approach given the constraints and lack of API versioning Tim. I took a first look, will you update this PR with docs and HLRC (so we should wait for review) or merge this and tackle the rest in a followup? If the latter, I'll take one more pass tomorrow, but it already looks good to me

public final class GetPrivilegesRequest extends ActionRequest implements ApplicationPrivilegesRequest {

@Nullable
private String application;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we change this to scope in 8.0 ?

@Override
public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException {
final String application = request.param("application");
final String scope = request.param("application");
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we change the parameter name to scope in 8.0.0 and add a small comment here to explain why we map application to a scope when backporting in 7.x ?

// Application names cannot start with `_`, so we use this for built-in names
if ("_cluster".equals(scope)) {
requestBuilder.privilegeTypes(GetPrivilegesRequest.PrivilegeType.CLUSTER);
} else if ("_index".equals(scope)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: extract _cluster , _index , _application to class vars ?

@tvernum
Copy link
Contributor Author

tvernum commented Jun 6, 2019

Thanks @jkakavas I'll wait for feedback from @albertzaharovits and then add add HLRC + docs if he's happy to move forward.

@albertzaharovits
Copy link
Contributor

@elasticmachine update branch (I get Eclipse proj setup failures)

}

public Set<PrivilegeType> privilegeTypes() {
return Collections.unmodifiableSet(this.includedTypes);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: make the field immutable (do this wrapping in readFrom)

@albertzaharovits
Copy link
Contributor

I am not very much a fan of this. In all such cases (names on the top level namespace) I would prefer to just deprecate the API and create a new one. I don't like it because the client has to account for "special" application names, with different parsing rules; just think of how you'd parse this in HLRC.

However, I think we have a better option here:

Given that the current API is consistent with PUT /_security/privilege/ and DELETE /_security/privilege/{application}/{privilege}, and that the proposed changes will return constants, which are not consistent with PUT and DELETE, I suggest we maintain the GET /_security/privilege/ variants as they are, but add a "new" API such as GET /_security/builtin_privileges or, less preferred, GET /_security/privilege/_builtin . What do you think?

I think these rather extensive format changes are not worth it just for returning some constants, however convincing your writeup is.

@tvernum
Copy link
Contributor Author

tvernum commented Jun 18, 2019

OK, let's take a step back and ask what API we would want if we weren't constrained by the existing API.
Then we can decide if there's a path to that, or if there's a close-enough approximation that we can implement easily.

I think @albertzaharovits is correct in that, actually there's no real use case (or at least no currently identified use case) for retrieving all defined privileges (builtin & application). Kibana's Security Management UI wants to know about builtin privileges, and Applications will want to know about their own privileges, but I would question the use-case of anyone who actually wants to get all the builtin privileges and all the application privileges. There might be a reason for that, but I don't know what it is.
But there is definitely a use case for getting all builtin (cluster & index) privileges in 1 call (Security Management UI).

To my thinking, that means that we would want an endpoint design that:

  1. makes it easy to get cluster & index privileges in 1 call
  2. makes it easy to get application privileges for a named application
  3. could be extended to do more if we decided we needed it.

So, that would be (roughly):

  • GET /_security/privilege/builtin
  • GET/POST /_security/privilege/application/{app}
  • GET/PUT/DELETE /_security/privilege/application/{app}/{privilege}

And then we could add

  • GET /_security/privilege/ down the track if we wanted an API to get everything (for some unknown reason).

But what we have is:

  • GET/POST /_security/privilege/
  • GET/POST /_security/privilege/{app}
  • GET/PUT/DELETE /_security/privilege/{app}/{privilege}

As a path forward, I'd prefer @albertzaharovits's alternative option of

  • GET /_security/privilege/_builtin

As it keeps everything under a single namespace and is a reasonable approximation of what I think we ought to have done from the start.

@tvernum
Copy link
Contributor Author

tvernum commented Jun 18, 2019

@elasticmachine run elasticsearch-ci/bwc

@tvernum
Copy link
Contributor Author

tvernum commented Jun 19, 2019

I've updated this PR based on my most recent proposal.
It is now a new endpoint & a new Action.

It also includes Docs & HLRC changes.

@tvernum tvernum requested a review from albertzaharovits June 19, 2019 10:57
@tvernum tvernum requested a review from jkakavas June 19, 2019 10:57
@tvernum tvernum removed the >breaking label Jun 19, 2019
Copy link
Contributor

@albertzaharovits albertzaharovits left a comment

Choose a reason for hiding this comment

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

This is looking very polished! I have only one objection, which is that the privilege for the new API is to high at manage_security and I would suggest monitor (in the same basket with _ssl/certificates)
The changes entailed by this are small so I'll LGTM it now 👍

==== Authorization

To use this API, you must have - the `manage_security` cluster privilege
(or a greater privilege such as `all`)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the monitor privilege would be more suitable, what do you think?

import java.util.Objects;

/**
* Response containing one or more application privileges retrieved from the security index
Copy link
Contributor

Choose a reason for hiding this comment

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

s/one or more application privileges retrieved from the security index/built-in (cluster/index) privileges

new String[] {
"monitor", "manage_index_templates", MonitoringBulkAction.NAME, "manage_saml", "manage_token", "manage_oidc"
"monitor", "manage_index_templates", MonitoringBulkAction.NAME, "manage_saml", "manage_token", "manage_oidc",
GetBuiltinPrivilegesAction.NAME
Copy link
Contributor

Choose a reason for hiding this comment

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

If GetBuiltinPrivilegesAction collates under monitor, don't forget to update this.

import java.util.TreeSet;

/**
* Transport action to retrieve one or more application privileges from the security index
Copy link
Contributor

Choose a reason for hiding this comment

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

built-in cluster/indices privileges

import static org.elasticsearch.rest.RestRequest.Method.GET;

/**
* Rest action to retrieve an application privilege from the security index
Copy link
Contributor

Choose a reason for hiding this comment

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

built-in cluster/index privileges

@tvernum
Copy link
Contributor Author

tvernum commented Jun 24, 2019

I have only one objection, which is that the privilege for the new API is to high at manage_security and I would suggest monitor

I had the same thought, but my plan was to raise a separate PR for a read-only security privilege instead.
Do you have a strong view on this being monitor rather than read_security ?

@albertzaharovits
Copy link
Contributor

Do you have a strong view on this being monitor rather than read_security ?

@tvernum No preference.

@tvernum
Copy link
Contributor Author

tvernum commented Jun 28, 2019

@jkakavas Do you want to review this? I'd like to get it into 7.3 if I can.

@jkakavas
Copy link
Contributor

jkakavas commented Jul 1, 2019

Apologies, I got lost in my backlog. I'm happy with this being merged with the explanation in #42134 (comment) and @albertzaharovits review

@tvernum
Copy link
Contributor Author

tvernum commented Jul 3, 2019

@elasticmachine update branch

@tvernum tvernum merged commit 539a120 into elastic:master Jul 3, 2019
tvernum added a commit to tvernum/elasticsearch that referenced this pull request Jul 3, 2019
Adds a new "/_security/privilege/_builtin" endpoint so that builtin
index and cluster privileges can be retrieved via the Rest API

Backport of: elastic#42134
tvernum added a commit that referenced this pull request Jul 3, 2019
Adds a new "/_security/privilege/_builtin" endpoint so that builtin
index and cluster privileges can be retrieved via the Rest API

Backport of: #42134
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTP API to return list of privileges?

5 participants