Kibana 4 dashboards access control with Shield

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

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.

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!! :blush: ).

Thanks,

Matt

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

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.

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

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.

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

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.

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}

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 just in case anyone is interested in it.

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

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!

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.

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.

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)

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:

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

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:

2 Likes

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.

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 !

@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 .. "\"")

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 !