# Kibana 4 dashboards access control with Shield

**URL:** <https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151>\
**Category:** Elasticsearch\
**Tags:** elastic-stack-security\
**Created:** [June 8, 2015, 5:07pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151 "2015-06-08T17:07:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [June 8, 2015, 5:07pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/1 "2015-06-08T17:07:15Z")

</div>

Hi all,

I have bunch of dashboards (DB1, DB2, DB3 & DB4) and I like to enforce user level access control.

```
user_1:
- DB1, DB2 & DB3

user_2:
- DB2 & DB4

user_3:
 - DB1 & DB4

```

Also, let's say user\_2 has access to creating new and modifying dashboards (DB2 & DB4).

I see that in the roles.yml file we could assign specific access levels to a kibana4 user, but how does that ensure locking the kibana4 dashboards.

Thanks,

MT

---

<div class="post-metadata">

**Author:** ![skearns](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/skearns/32/125945_2.png) [@skearns](https://discuss.elastic.co/u/skearns)\
**Post date:** [June 8, 2015, 8:01pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/2 "2015-06-08T20:01:08Z")

</div>

Hi Matt,

Today, the integration between Shield and Kibana doesn't extend to individual dashboards, though as you might imagine, this is a frequently requested feature.

In the short term, I suggest focusing on protecting the _data_ with Shield - ensuring that user\_2 cannot see the data that powers DB1 or DB3. You could do this by protecting whole indexes, or by defining aliases with filters and only granting permission to the filtered alias. This would mean that even if user\_2 can see that DB1 and DB3 exist, they won't be able to see any of the _data_ that backs them up, so they would just see empty charts and error messages.

In the longer term, we are planning the tighter integration. Is this example representative of the minimum-requirements for your use-case, or are there other ways to secure things that might meet your needs? e.g. give each user a set of private dashboards and a set of globally shared dashboards? If you can share more about your requirements, we would appreciate it.

---

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [June 8, 2015, 8:44pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/3 "2015-06-08T20:44:04Z")

</div>

Thanks Steve for your quick response. Securing of the data is not a major concerns for us (at-least for now). Once a user is authenticated, he/she is already inside our secure zone.

The issue that we often face is, that we have 100+ dashboards from various departments all users have write access to it. Again, we are not so concerned about the "read" part as of now.

Just by the looks of it, we have to hack the Kibana 4 source code or we write a wrapper to go on top of it with a reverse proxy or something.

Please let me know if you have any workable suggestions for now. I would rather not touch the code base, just because I don't want to get stuck with a version of the product. We want to be able to upgrade as the newer versions started to show up.

Btw, Is there a way for me to write a plugin for it? (Although readme document in the plugin directory says not to do that!! 😊 ).

Thanks,

Matt

---

<div class="post-metadata">

**Author:** ![skearns](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/skearns/32/125945_2.png) [@skearns](https://discuss.elastic.co/u/skearns)\
**Post date:** [June 10, 2015, 8:22pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/4 "2015-06-10T20:22:14Z")

</div>

Hi Matt,

I see your challenge. In the short term, I wonder if naming standards and Kibana's existing dashboard search would be a suitable solution? If all "Department1" dashboards share a naming scheme like "D1: ", it would be relatively easy for a user to search the saved dashboards. This might be a good idea anyway, so admins or other power-users can quickly search/filter the list.

I agree that if you can avoid it, it's best not to be tied to a specific version of Kibana with complex custom modifications.. things are moving fast - Kibana 4.1 was released today!

As for the plugin question - I'm not sure that this sort of need would be a good candidate for a Kibana plugin, at least how I think of them, so I'm hopeful that the naming/filtering trick will work for you, or at least give you some other ideas to chase!

Thanks,  
Steve

---

<div class="post-metadata">

**Author:** ![PatrickKik](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/patrickkik/32/619_2.png) [@PatrickKik](https://discuss.elastic.co/u/PatrickKik)\
**Post date:** [June 11, 2015, 9:15am UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/5 "2015-06-11T09:15:56Z")

</div>

I haven't tried it yet, but it might be possible to be really creative with filtered aliases on the .kibana index to limit the number of visible dashboards.

---

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [June 11, 2015, 1:40pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/6 "2015-06-11T13:40:49Z")

</div>

Thanks Guys for all the suggestions, as I mentioned we don't want any custom developments that will prevent us from upgrading to newer versions.

So what we are looking into is to intercept the AJAX call that gets passed to the frontend (kibana\_index) and append 4 letter unique identifier for various groups. This way we are running one instance of the kibana4 with multiple kibana indexes.

In order for me to achive this, I am looking into nginx + lua rules.

Thanks,  
Matt

---

<div class="post-metadata">

**Author:** ![palmerabollo](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/palmerabollo/32/44772_2.png) [@palmerabollo](https://discuss.elastic.co/u/palmerabollo)\
**Post date:** [July 12, 2015, 8:57am UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/7 "2015-07-12T08:57:58Z")

</div>

Hi @matt, did you manage to get your nginx+lua working? I was about to try the same approach, so any issues you might be encountered are very valuable. Do you happen to have your lua rules in github or any other public repository? Thank you.

---

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [July 13, 2015, 4:24am UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/8 "2015-07-13T04:24:39Z")

</div>

Hey,

I am still working on the issue. Profiling the Kibana 4 + Elastic + Shield took some time, but I think I am almost there (95% done!), Once completed I will post my findings here. Is there anything specific that you have run into?

I am really new to lua and finding it very interesting as well. Let me know.

Matt

---

<div class="post-metadata">

**Author:** ![palmerabollo](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/palmerabollo/32/44772_2.png) [@palmerabollo](https://discuss.elastic.co/u/palmerabollo)\
**Post date:** [July 13, 2015, 6:42am UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/9 "2015-07-13T06:42:35Z")

</div>

Thanks @matt . I'm particularly interested in how you intercept the AJAX calls from the frontend (kibana\_index) and how you solved [Kibana 4.x with multiple indexes](https://discuss.elastic.co/t/kibana-4-x-with-multiple-indexes/23991).

If I'm not wrong, kibana passes the index name in different (inconsistent) ways. Sometimes in the **body** :

```
POST http://localhost:9200/_mget?timeout=0&ignore_unavailable=true&preference=1436769679508
BODY:
{"docs":[{"_index":".kibana","_type":"index-pattern","_id":"[myindex-]YYYY.MM.DD"}]}

```

Other times in the **URL** itself:

```
POST http://localhost:9200/.kibana/index-pattern/_search?fields=
BODY:
{"query":{"match_all":{}},"size":2147483647}
```

---

<div class="post-metadata">

**Author:** ![palmerabollo](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/palmerabollo/32/44772_2.png) [@palmerabollo](https://discuss.elastic.co/u/palmerabollo)\
**Post date:** [July 14, 2015, 12:00pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/10 "2015-07-14T12:00:40Z")

</div>

For me, the most difficult part is to use a shared .kibana index to store "metadata" (dashboards, visualizations...). It doesn't seem possible to use a different index for each user (for example .kibana-) due to some restrictions in kibana code. I've filed an issue here [https://github.com/elastic/kibana/issues/4421](https://github.com/elastic/kibana/issues/4421) just in case anyone is interested in it.

With that change, using a nginx+lua proxy in the middle would be trivial IMO.

---

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [July 14, 2015, 2:03pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/11 "2015-07-14T14:03:51Z")

</div>

My Nginx sits between the outside world and Kibana.

when you point the brower to the localhost:80 it takes you to a form where I put the username/password & few other user inputs. It gets sumitted to localhost:80/validate. In my nginx/lua I have a location = /vadate entry that process the form input and then does a proxy pass (by setting the user:password in the header for shild to authenticate the user).

I also have a location = /config if the argument match +b=7467 then I read the body (which is a json output) decode the json and replace the index name set in the kibana.yml (.kibana) with the new index name (which I have composed in my previous steps). Also, I have hacked the validate.js file and allowed kibana to create indexes that are not defined in the kibana.yml file. From this point onwards its between the useragent (brower) to kibana.

Although, I have tested these components individually, I am still stuck at Shield authentication with LDAP which I think I am not using nginx/lua properly. Still learning this beast!!

Hope this helps!

---

<div class="post-metadata">

**Author:** ![palmerabollo](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/palmerabollo/32/44772_2.png) [@palmerabollo](https://discuss.elastic.co/u/palmerabollo)\
**Post date:** [July 14, 2015, 7:13pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/12 "2015-07-14T19:13:52Z")

</div>

That is more or less the same approach I am following. I don't like the idea of hacking validate.js at all, that will be hard to maintain. This is why I opened the github issue.

---

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [July 14, 2015, 7:35pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/13 "2015-07-14T19:35:57Z")

</div>

Just by the looks of it, by design kibana prevents you from creating non-defined indexes. Unless the elastic guys have a solution, we are kind of stuck with it.

How are you defining the name of the index? In my case I am getting the group name as part of the login screen.

---

<div class="post-metadata">

**Author:** ![palmerabollo](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/palmerabollo/32/44772_2.png) [@palmerabollo](https://discuss.elastic.co/u/palmerabollo)\
**Post date:** [July 15, 2015, 7:15am UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/14 "2015-07-15T07:15:54Z")

</div>

My indexes are ".kibana-\<user\_login\>". I use nginx to authenticate the user, so I can use `ngx.var.remote_user` in my lua code.

My requirements are simpler than yours, I only have to restrict access to indexes in a way that users can only see their data (each user has a "index-\<user\_login\>", without using Shield. What I'm doing right now is:

- replacing ".kibana" with ".kibana-" .. ngx.var.remote\_user both in the requested uri and in the request body (lua)
- replacing the name of the index requested by the user with "index-\<user\_login\>" in the request body (lua)
- modifying validateRequest.js to allow creation of ".kibana-\*" indexes (nodejs)

---

<div class="post-metadata">

**Author:** ![matt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt/32/524_2.png) [@matt](https://discuss.elastic.co/u/matt)\
**Post date:** [July 15, 2015, 2:56pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/15 "2015-07-15T14:56:01Z")

</div>

When you say "I use nginx to authenticate" do you mean your users have to login twice? One for nginx and one for Shield?

Update:

```auto
Sorry I missed that part about "not using Shield" :smile:
```

---

<div class="post-metadata">

**Author:** ![tbragin](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/tbragin/32/45166_2.png) [@tbragin](https://discuss.elastic.co/u/tbragin)\
**Post date:** [July 20, 2015, 1:05pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/16 "2015-07-20T13:05:37Z")

</div>

For those of you working to achieve fine-grained access control within Kibana (e.g. saved object authorization), longer-term we plan to introduce these types of capabilities natively within the stack - please feel free to +1 or comment on the issue, if you have a chance:

> <https://github.com/elastic/kibana/issues/4453>

---

<div class="post-metadata">

**Author:** ![Pranav\_Sathyanarayan](https://avatars.discourse-cdn.com/v4/letter/p/bc8723/32.png) [@Pranav\_Sathyanarayan](https://discuss.elastic.co/u/Pranav_Sathyanarayan)\
**Post date:** [July 29, 2015, 12:24am UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/17 "2015-07-29T00:24:44Z")

</div>

So I tried modifying the request URI and body, however Kibana now is just stuck on loading. I am using OpenResty, @palmerabollo , do you have any suggestions on what I am doing wrong?

- EDIT: Nevermind, I managed to solve my problem utilizing Express.JS middleware that sets the kibana index based upon the Authorization header sent in my Nginx reverse proxy which reads a cookie from my application.

---

<div class="post-metadata">

**Author:** ![julienb](https://avatars.discourse-cdn.com/v4/letter/j/94ad74/32.png) [@julienb](https://discuss.elastic.co/u/julienb)\
**Post date:** [August 13, 2015, 1:14pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/18 "2015-08-13T13:14:11Z")

</div>

Hi !

I also use Nginx between the outside world and the Kibana Server;  
I am trying to create a granular access control for users. What I want to do is to filter on the request body just like you do so that users only have access to their data or their dashboard. I am having some trouble using Lua (never used this language before). Do any of you two have an example script to retrieve data in the request body and to use an if condition for response (200 or 403).  
Something like :

ngx.req.read\_body()  
local args = ngx.req.get\_post\_args()

if ($remote\_user == "user" and args[1] == _dashboard1_ then  
ngx.status = 403  
ngx.say("403 Forbidden: You don't have access to this resource.")  
return ngx.exit(403)  
end

Thanks !

---

<div class="post-metadata">

**Author:** ![palmerabollo](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/palmerabollo/32/44772_2.png) [@palmerabollo](https://discuss.elastic.co/u/palmerabollo)\
**Post date:** [August 13, 2015, 4:31pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/19 "2015-08-13T16:31:39Z")

</div>

@julienb, I don't have those kind of contitions. I've only managed to read the body and modify it using a regular expression. This way users have their own .kibana- index. I'm very interested in what you propose, though, any code you can share is more than welcome.

```
local body = ngx.req.get_body_data()
if body then
  body = ngx.re.gsub(
    body,
    "\".kibana\"",
    "\".kibana-" .. ngx.var.remote_user .. "\"")
```

---

<div class="post-metadata">

**Author:** ![julienb](https://avatars.discourse-cdn.com/v4/letter/j/94ad74/32.png) [@julienb](https://discuss.elastic.co/u/julienb)\
**Post date:** [August 17, 2015, 3:03pm UTC](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151/20 "2015-08-17T15:03:32Z")

</div>

Thanks for your fast reply.  
I have tried your code, without any success. My Lua code is not modifying the POST body at all. But I also use "proxy pass" in the same location so maybe that is the issue.  
I will try to redirect first to a location where I only use Lua code and then redirect to Kibana or to 403 error depending on the body.

I was wondering at which phase you are accessing the Lua file ? Personnaly I am using "access\_by\_lua\_file".

Thanks !

[Next page](https://discuss.elastic.co/t/kibana-4-dashboards-access-control-with-shield/2151.md?page=2)
