Skip to content
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

Added data streams privileges to better control delete actions in UI #83573

Merged
merged 9 commits into from
Nov 26, 2020

Conversation

yuliacech
Copy link
Contributor

@yuliacech yuliacech commented Nov 17, 2020

Summary

This PR adds a privileges check to data streams tab in Index Management so that the user without a delete privilege wont see a delete button/action anymore.

Screenshots

Screenshot 2020-11-18 at 14 35 03

Screenshot 2020-11-18 at 14 35 59

How to test

Instructions
  1. create 2 data streams with following dev tools commands:
PUT /_ilm/policy/my-data-stream-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "25GB"
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

PUT /_index_template/my-data-stream-template
{
  "index_patterns": [ "my-data-stream*" ],
  "data_stream": { },
  "priority": 200,
  "template": {
    "settings": {
      "index.lifecycle.name": "my-data-stream-policy"
    }
  }
}

POST /my-data-stream/_doc/
{
  "@timestamp": "2020-12-06T11:04:05.000Z",
  "user": {
    "id": "vlb44hny"
  },
  "message": "Login attempt failed"
}

PUT /_index_template/my-data-stream-template-2
{
  "index_patterns": [ "no-delete-data-stream*" ],
  "data_stream": { },
  "priority": 200,
  "template": {
    "settings": {
      "index.lifecycle.name": "my-data-stream-policy"
    }
  }
}

POST /no-delete-data-stream/_doc/
{
  "@timestamp": "2020-12-06T11:04:05.000Z",
  "user": {
    "id": "vlb44hny"
  },
  "message": "Login attempt failed"
}
  1. Navigate to Index Management -> Data Streams to check delete button/actions for both data streams
  2. Create a user with some delete privileges missing:
  • Navigate to Roles and create a role with manage privileges on cluster, view_index_metadata, monitor on all indices (*) and delete_index privileges on my-data-stream index.
Screenshot 2020-11-11 at 16 51 52 - Also add all Kibana privileges to this user Screenshot 2020-11-18 at 14 28 10 - Create a test user and add the test role to the user
  1. Login with the test user and check that delete button/actions are not displayed for no-delete-data-stream

Checklist

TODO

Add api integration tests in a following PR

Release note

In the Index Management app, buttons to delete a data stream are now controlled by user's privileges.

@yuliacech
Copy link
Contributor Author

@elasticmachine merge upstream

@yuliacech yuliacech added Feature:Index Management Index and index templates UI Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more v7.11.0 v8.0.0 labels Nov 18, 2020
@yuliacech yuliacech marked this pull request as ready for review November 18, 2020 13:46
@yuliacech yuliacech requested a review from a team as a code owner November 18, 2020 13:46
@elasticmachine
Copy link
Contributor

Pinging @elastic/es-ui (Team:Elasticsearch UI)

@yuliacech yuliacech force-pushed the data_streams_privileges branch from b2ab845 to 1549295 Compare November 19, 2020 10:16
Copy link
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

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

Great job @yuliacech ! I reviewed the code but I haven't yet been able to test locally (do you mind adding the console commands required?) For the privileges I guess I only need to create a user without the "delete_index" privilege, or is there other privileges to take into account?

Regarding the approach taken: I wonder if it would not be better to fetch the privileges at the same time as we fetch de data streams (a single request) and enhance them. Wouldn't that simplify the client code? I was wondering what happens "in between" the 2 calls (fetch the resource, fetch its privileges). Does the button to delete the stream appear or not? If the HTTP request for the privileges fails, how do we handle it client-side? For those scenarios, it seems easier to do it all server-side and have a fallback mechanism in a single place.

We'd end up with objects like this

{
  name: 'my-data-stream',
  ...
  __meta__: {
    privileges: {
      delete: true, // defaults to "true" if privilege request failed
    }
  }
}

WDYT?

@@ -240,6 +248,9 @@ export const DataStreamList: React.FunctionComponent<RouteComponentProps<MatchPa
reload();
}
}}
canDelete={
!deletePrivileges || deletePrivileges[attemptToURIDecode(dataStreamName)!]?.delete_index
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that there are 3 calls to attemptToURIDecode(dataStreamName) in the file and we use the decoded name everywhere. Can we make the call once at the top of the component and used it everywhere?

const decodedName = dataStreamName !== undefined
 ? attemptToURIDecode(dataStreamName)
 : undefined;

@@ -47,3 +47,5 @@ export interface DataStreamIndex {
name: string;
uuid: string;
}

export type DataStreamPrivileges<K extends string> = Record<string, { [key in K]: boolean }>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Using generic is an interesting approach but I wonder if it is worth the lack of explicitness and what exactly we gain from it.

This would be much clearer to me

export interface DataStreamPrivileges {
  delete_index?: boolean;
}

Whenever we read the interface we know what privileges the data stream app (or section) relies on. What are your thoughts on this?

@@ -162,6 +165,9 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
},
isPrimary: true,
'data-test-subj': 'deleteDataStream',
available: ({ name }: DataStream) => {
Copy link
Contributor

@sebelga sebelga Nov 19, 2020

Choose a reason for hiding this comment

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

nit: We could have a method for this and use it here and below (L168)

const hasDeletePrivilege = ({ name }: DataStream) => !deletePrivileges || deletePrivileges[name]?.delete_index;

...

available: hasDeletePrivilege

...

toolsLeft: selection.length > 0 && (!deletePrivileges || selection.every(hasDeletePrivilege)) ? ( ...

@@ -449,4 +460,78 @@ describe('Data Streams tab', () => {
expect(tableCellsValues).toEqual([['', 'non-managed-data-stream', 'green', '1', 'Delete']]);
});
});

describe('delete data stream privileges', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

The title is a bit misleading as it seems that we will delete the privileges :) What about simply: "Privileges: 'delete data stream'"

@yuliacech
Copy link
Contributor Author

Hi @sebelga , thanks a lot for your suggestions! I really like the idea of fetching privileges at the same time as data streams, let me add privileges to the data stream response instead. If you still want to check it locally in the mean time, there is a 'how to test' section in PR description, I've just made the title bigger for better visibility.

@sebelga
Copy link
Contributor

sebelga commented Nov 19, 2020

Great, I hadn't seen the description sorry! I just tested locally and it works as expected! 👍 I also throttled the requests and indeed the delete button first appears then disappears. It is not a huge deal, if the user is quick enough to click on it before it disappears he will get a non authorized error from ES anyway.
I think that the main advantage of having a single request for both the resource and the privileges is more the simplicity of how it is later consumed in the client. I'll review once you make the change, cheers!

@yuliacech yuliacech marked this pull request as draft November 20, 2020 15:09
@yuliacech yuliacech marked this pull request as ready for review November 23, 2020 09:19
@yuliacech
Copy link
Contributor Author

@elasticmachine merge upstream

@yuliacech
Copy link
Contributor Author

Hi @sebelga , could you please have another look? I moved the privileges request inside the call for data streams as you suggested.

Copy link
Contributor

@sebelga sebelga left a comment

Choose a reason for hiding this comment

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

Thanks for making those changes @yuliacech ! I think it is much cleaner like this on the client-side. I tested locally and works as expected 👍

I left a few comments but no blockers.
I see that the link to the ILM policy now works from inside the detail panel, I just wonder why we need a full Kibana reload to access it. If we click on ILM in the menu on the left there is no page reload. Maybe something to investigate in a separate work.

delete_index: boolean;
}

type PrivilegesField = PrivilegesFieldFromEs;
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure I understand why we create an alias here. Do you mind explaining?

Also not sure why there is a "Field" in the naming :) I would have called the interface simply Privileges instead of PrivilegesFieldFromEs but maybe I'm missing something.


if (dataStreamsStats) {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { store_size, maximum_timestamp } = dataStreamsStats.find(
Copy link
Contributor

Choose a reason for hiding this comment

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

The find can potentially return undefined so I wonder if deconstructing the value without asserting it is defined could potentially throw. I wonder why Typescript does not complain on this 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you are right, it can be undefined at the end of the line for TypeScript not to complain. But I was thinking that we rely too much on ES returning the same data streams in both requests, but if a data stream is deleted between the requests then this logic would fail. So I added a default empty object instead.

@yuliacech
Copy link
Contributor Author

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
indexManagement 1.5MB 1.5MB +257.0B

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
indexManagement 114.2KB 114.2KB +61.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@yuliacech yuliacech merged commit 51f75a5 into elastic:master Nov 26, 2020
yuliacech added a commit to yuliacech/kibana that referenced this pull request Nov 26, 2020
…lastic#83573)

* Added data streams privileges to better control delete actions in UI

* Fix type check issues

* Change data streams privileges request

* Fixed type check issue

* Fixed api integration test

* Cleaned up not needed code

* Renamed some data streams and added a default value for stats find

Co-authored-by: Kibana Machine <[email protected]>
gmmorris added a commit to gmmorris/kibana that referenced this pull request Nov 30, 2020
* master:
  [Security Solution] Exceptions Cypress tests (elastic#81759)
  [ML] Fix spaces job ID check (elastic#84404)
  [Security Solution][Detections] Handle dupes when processing threshold rules (elastic#83062)
  skip flaky suite (elastic#84440)
  skip flaky suite (elastic#84445)
  [APM] Fix missing `service.node.name` (elastic#84269)
  Upgrade fp-ts to 2.8.6 (elastic#83866)
  Added data streams privileges to better control delete actions in UI (elastic#83573)
  Improve short-url redirect validation (elastic#84366)
  TSVB offsets (elastic#83051)
  [Discover] Fix navigating back when changing index pattern (elastic#84061)
  [Logs UI] Polish the UI for the log entry examples in the anomaly table (elastic#82139)
  [Logs UI] Limit the height of the "view in context" container (elastic#83178)
  [Application Usage] Update `schema` with new `fleet` rename (elastic#84327)
  fix identation in list (elastic#84301)
yuliacech added a commit that referenced this pull request Nov 30, 2020
…83573) (#84428)

* Added data streams privileges to better control delete actions in UI

* Fix type check issues

* Change data streams privileges request

* Fixed type check issue

* Fixed api integration test

* Cleaned up not needed code

* Renamed some data streams and added a default value for stats find

Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Kibana Machine <[email protected]>
@yuliacech yuliacech deleted the data_streams_privileges branch December 3, 2020 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Index Management Index and index templates UI release_note:enhancement Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more v7.11.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants