The easy way to find security privileges in Elasticsearch

blog-thumb-elasticsearch-gears-light-blue.png

It can be hard to find the required privileges for strict security in Elasticsearch. In this blog, I will outline the procedures I use to find my required privileges in two examples. 

Example 1 

Let's create a user that can only interact with index-* indices and the index alias. They will be able to:

  • Create the index if it does not exist
  • Index document into the index (create and update)
  • Delete documents from the index

We start by creating a new user with Kibana Dev Tools Console access:

```
PUT _security/role/test
{
  "applications" : [
    {
      "application" : "kibana-.kibana",
      "privileges" : [
        "feature_dev_tools.all"
      ],
      "resources" : [
        "space:default"
      ]
    }
  ]
}
```

```
PUT _security/user/test
{
  "username": "test",
  "password": "****",
  "roles": [
    "test"
  ],
  "metadata": {},
  "enabled": true
}
```

We can then login as that user and try the commands our user will, taking note of the errors. Tip: use a different browser or a private window of the same browser. This will make the step of adding privileges to our role much easier.

For example, let's GET our alias and our indices:

```
GET index
GET index-*
```

```
{
  "error" : {
    ...
    "reason" : "action [indices:admin/get] is unauthorized for user [test] with roles [test], this action is granted by the index privileges [view_index_metadata,manage,all]"
  },
  ...
}
```

The interesting parts of the error message are:

  • action [indices:admin/get], the exact action that is missing, but this is also an internal implementation detail so we will ignore this
  • index privileges [view_index_metadata,manage,all], privileges which contain the action, ordered from most restrictive to least restrictive

Let’s take view_index_metadata, the most restrictive:

```
PUT _security/role/test
{
  "indices": [
    {
      "names": [
        "index",
        "index-*"
      ],
      "privileges": [
        "view_index_metadata"
      ]
    }
  ],
  "applications" : [
    {
      "application" : "kibana-.kibana",
      "privileges" : [
        "feature_dev_tools.all"
      ],
      "resources" : [
        "space:default"
      ]
    }
  ]
}
```

This is incredibly limited and will not work for my next command:

```
PUT index-1/_doc/1
{
  "field": "value"
}
```

```
{
  "error" : {
    ...
    "reason" : "action [indices:data/write/index] is unauthorized for user [test] on indices [], this action is granted by the index privileges [create_doc,create,index,write,all]"
  },
  "status" : 403
}
```

From this we get extract the privilege:

  • index privileges [create_doc,create,index,write,all], specifically create_doc

But note: even if I add this, I will not be ready to go yet, with the following error coming next:


```
{
  "error" : {
    ...
    "reason" : "action [indices:data/write/index:op_type/index] is unauthorized for user [test] with roles [test] on indices [index-1], this action is granted by the index privileges [create,index,write,all]"
  },
  "status" : 403
}
```

If we continue this iteratively, we would get to the following role:

```
PUT _security/role/test
{
  "indices": [
    {
      "names": [
        "index",
        "index-*"
      ],
      "privileges": [
        "view_index_metadata",
        "create_doc",
        "auto_configure",
        "create"
      ]
    }
  ],
  "applications" : [
    {
      "application" : "kibana-.kibana",
      "privileges" : [
        "feature_dev_tools.all"
      ],
      "resources" : [
        "space:default"
      ]
    }
  ]
}

```

We can also continue this for every other request we would like to send. In many cases, this is overkill though. Unless you are on a project with extremely tight security needs, it is often easier to use the least restrictive privilege, like the following:

```
PUT _security/role/test
{
  "indices": [
    {
      "names": [
        "index",
        "index-*"
      ],
      "privileges": [
        "all"
      ]
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": [
        "feature_dev_tools.all"
      ],
      "resources": [
        "space:default"
      ]
    }
  ]
}
```

Be careful with this privilege above though, as it also allows that user to delete those indices and any data inside of them.

Example 2

A user with cluster-level permissions to see the Elastic homepage and the ilm policies.

We start by creating a new user with Kibana Dev Tools access as in example 1, and we then run our commands:

```
GET /
GET _ilm/policy
```

Which gives us:

```
{
  "error" : {
    ...
    "reason" : "action [cluster:monitor/main] is unauthorized for user [test], this action is granted by the cluster privileges [monitor,manage,all]"
  },
  "status" : 403
}
```

And:

```
{
  "error" : {
    ...
    "reason" : "action [cluster:admin/ilm/get] is unauthorized for user [test], this action is granted by the cluster privileges [read_ilm,manage_ilm,manage,all]"
  },
  "status" : 403
}
```

To fix these, we can use the following role:

```
PUT _security/role/test
{
  "cluster": [
    "monitor",
    "read_ilm"

  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": [
        "feature_dev_tools.all"
      ],
      "resources": [
        "space:default"
      ]
    }
  ]
}
```

More to come

This post showed a simple way to iteratively get the permissions needed for my user’s desired actions. As you can see, there are simply too many combinations to cover them all with built-in roles, let alone to cover them all in some documentation. I hope you find this simple trick useful, and for those of you who prefer to use the UI, I am working on a similar example there.

In the meantime, you can try out this method in your existing environment, or spin up a free trial of Elastic Cloud and test it out. Enjoy!