The easy way to find security privileges in Elasticsearch
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!