4
votes

Context

I am embedding a Kibana 4 dashboard at several places in a web app I am working on using Node.js and Express. The embedding is context-dependent, meaning that depending on where the dashboard is embedded, the query to Elasticsearch changes.

Moreover, some pages where dashboards are embedded are limited to some users who have the right permissions.

As there is no authentication implemented yet in Kibana 4, by changing the query in the dashboard embed URL, any user could show the dashboard of a page they don't have access.

Our solution

The idea is to block any external connection to Kibana (port 5601) and to have a custom URL going through our web app and check the user permissions (kind of a proxy). And if the user has the permission, then our web app forward the HTTP queries to Kibana. As our web app and Kibana are on the same server, these queries are not blocked.

To route the custom URL and check the permission, we have the following:

app.route('/items/:itemId/analytics/*')
   .all(api.requiresAccess('user'),
        api.requiresPermissions('item', 'modify'),
        items.getAnalytics);

Then we use Request in the getAnalytics function:

exports.getAnalytics = function (req, res) {
  var itemId = req.item.id;
  var kibanaParamsRegexp = /analytics\/(.*)/;
  var kibanaParamsMatch = kibanaParamsRegexp.exec(req.originalUrl);
  var kibanaParams = kibanaParamsMatch[1];
  var method = req.method;
  var dashboardId = 'Standard-Dashboard';

  var kibanaDashboardURL = 'http://localhost:5601';

  
  if (kibanaParams === '') { // First request to get the dashboard
    kibanaDashboardURL += '/#/dashboard/' + dashboardId + '?embed' +
    '&_a=(query:(query_string:(analyze_wildcard:!t,query:\'path:' + itemId + '\')))' +
    '&_g=(time:(from:now-1y,mode:quick,to:now))';
  } else { // Following requests to get the dashboard
    kibanaDashboardURL += '/' + kibanaParams;
  }

  app.logger.info('Received from the dashboard: ' + req.originalUrl);
  app.logger.info('Requesting to Kibana: ' + kibanaDashboardURL);
  app.logger.info('Query body: ' + JSON.stringify(req.body));

  if (method === 'POST') {
    var options = {
      url: kibanaDashboardURL,
      json: true,
      body: req.body
    };

    request.post(options,
      function (err, httpResponse, body) {
        if (err) {
          return console.log('POST failed: ', err);
        }
        console.log('POST successful. Sever response: ', body);
      }).pipe(res);
  } else if (method === 'GET' || method === 'HEAD') {
    request.get(kibanaDashboardURL).pipe(res);
  }
};

Therefore, instead of http://localhost:5601/#/dashboard/Standard-dashboard?embed&_a=(query:(query_string:(analyze_wildcard:!t,query:'path: 5539e831b5b79bf9f4b06a3c')))&_g=(time:(from:now-1y,mode:quick,to:now)),
I have to use http://localhost:8000/items/5539e831b5b79bf9f4b06a3c/analytics/ which checks the permissions.

The problem

The first requests, which are mainly GETs and a few POSTs, are passing without problem. But at some point I have a POST request that receives back a 500 Internal Sever error in response to the request, which stops the dashboard loading.

To try to find the issue I compared the network traffic (in the web inspector) between the load of the dashboard with the original Kibana URL and the redirected URL through the web app. The beginning is identical, but at some point (before the request receiving a 500 error back), the dashboard load through the original URL makes a request that is not done with the redirected URL. The request is a POST to http://localhost:5601/elasticsearch/_mget?timeout=0&ignore_unavailable=true&preference=1434374357241 with the following body:
{"docs":[{"_index":".kibana","_type":"dashboard","_id":"Standard-Dashboard"}]}.

This request seem quite important as it contains the dashboard id and I suppose that its absence is what generate the 500 error later on. But I don't know why this request is not sent when I redirect the queries through the web app.

I also have tried with the modules http-proxy and express-http-proxy but I am facing the same issues.

2
Did you solve your problem? I am interested in your solution!DaTebe
@DaTebe I'm not working anymore on the project that has this issue. As far as I remember we didn't find a solution. I didn't check the suggested answers so I cannot say if they solve or not the problem.David S.
Hay. thanks for your response! Your URL '/items/:itemId/analytics/*' reminds me of an Learning Autoring System which uses Kibana with a Proxy. Did you work on that specific Application? (Graasp.eu)DaTebe
@DaTebe Nice catch! Yes, this is an issue I had while I was working on Graasp.euDavid S.
@DaTebe I contacted them and they found a proper solution. You can contact Andrii Vozniuk. Good luck with your thesis!David S.

2 Answers

2
votes

For those who are searching for answer to this kind of questions. I have enabled a Nginx proxy that sits between my Elasticsearch and Kibana to configure authorized access to dashboards and charts. Look at my post here: https://udaysagars.wordpress.com/2016/04/04/how-i-configured-authorized-access-to-kibana-dashboards/

1
votes

To answer your question Elastic Co has developed a product named Shield which provides access control & you can give the access of each cluster,indices to user along with username & password for access.

Also you can use a user made Kibana Authentication proxy which works perfectly with Kibana which can be seen here:

https://github.com/fangli/kibana-authentication-proxyhttps://github.com/fangli/kibana-authentication-proxy