web-dev-qa-db-ja.com

Kibana 3で基本認証を実装する方法と場所

Elasticsearchサーバーを、基本認証を提供するApacheリバースプロキシの背後に置きました。

ブラウザから直接Apacheへの認証は正常に機能します。しかし、Kibana 3を使用してサーバーにアクセスすると、認証エラーが表示されます。

明らかに、KibanaのAjax呼び出しと共に認証ヘッダーが送信されないためです。

以下をKibanaベンダーディレクトリのelastic-angular-client.jsに追加して、迅速かつダーティな認証を実装しました。しかし、何らかの理由で機能しません。

$http.defaults.headers.common.Authorization = 'Basic ' + Base64Encode('user:Password');

Kibanaで基本認証を実装するための最良のアプローチと場所は何ですか?

/*! elastic.js - v1.1.1 - 2013-05-24
 * https://github.com/fullscale/elastic.js
 * Copyright (c) 2013 FullScale Labs, LLC; Licensed MIT */

/*jshint browser:true */
/*global angular:true */
'use strict';

/* 
Angular.js service wrapping the elastic.js API. This module can simply
be injected into your angular controllers. 
*/
angular.module('elasticjs.service', [])
  .factory('ejsResource', ['$http', function ($http) {

  return function (config) {
    var

      // use existing ejs object if it exists
      ejs = window.ejs || {},

      /* results are returned as a promise */
      promiseThen = function (httpPromise, successcb, errorcb) {
        return httpPromise.then(function (response) {
          (successcb || angular.noop)(response.data);
          return response.data;
        }, function (response) {
          (errorcb || angular.noop)(response.data);
          return response.data;
        });
      };

    // check if we have a config object
    // if not, we have the server url so
    // we convert it to a config object
    if (config !== Object(config)) {
      config = {server: config};
    }

    // set url to empty string if it was not specified
    if (config.server == null) {
      config.server = '';
    }

    /* implement the elastic.js client interface for angular */
    ejs.client = {
      server: function (s) {
        if (s == null) {
          return config.server;
        }

        config.server = s;
        return this;
      },
      post: function (path, data, successcb, errorcb) {
        $http.defaults.headers.common.Authorization = 'Basic ' + Base64Encode('user:Password');
        console.log($http.defaults.headers);
        path = config.server + path;
        var reqConfig = {url: path, data: data, method: 'POST'};
        return promiseThen($http(angular.extend(reqConfig, config)), successcb, errorcb);
      },
      get: function (path, data, successcb, errorcb) {
        $http.defaults.headers.common.Authorization = 'Basic ' + Base64Encode('user:Password');
        path = config.server + path;
        // no body on get request, data will be request params
        var reqConfig = {url: path, params: data, method: 'GET'};
        return promiseThen($http(angular.extend(reqConfig, config)), successcb, errorcb);
      },
      put: function (path, data, successcb, errorcb) {
        $http.defaults.headers.common.Authorization = 'Basic ' + Base64Encode('user:Password');
        path = config.server + path;
        var reqConfig = {url: path, data: data, method: 'PUT'};
        return promiseThen($http(angular.extend(reqConfig, config)), successcb, errorcb);
      },
      del: function (path, data, successcb, errorcb) {
        $http.defaults.headers.common.Authorization = 'Basic ' + Base64Encode('user:Password');
        path = config.server + path;
        var reqConfig = {url: path, data: data, method: 'DELETE'};
        return promiseThen($http(angular.extend(reqConfig, config)), successcb, errorcb);
      },
      head: function (path, data, successcb, errorcb) {
        $http.defaults.headers.common.Authorization = 'Basic ' + Base64Encode('user:Password');
        path = config.server + path;
        // no body on HEAD request, data will be request params
        var reqConfig = {url: path, params: data, method: 'HEAD'};
        return $http(angular.extend(reqConfig, config))
          .then(function (response) {
          (successcb || angular.noop)(response.headers());
          return response.headers();
        }, function (response) {
          (errorcb || angular.noop)(undefined);
          return undefined;
        });
      }
    };

    return ejs;
  };
}]);

PDATE 1: Mattsの提案を実装しました。ただし、サーバーは奇妙な応答を返します。認証ヘッダーが機能していないようです。ポート81でKibanaを実行し、8181でelasticsearchを実行しているという事実と関係があるのでしょうか?

OPTIONS /solar_vendor/_search HTTP/1.1
Host: 46.252.46.173:8181
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Origin: http://46.252.46.173:81
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

これが反応です

HTTP/1.1 401 Authorization Required
Date: Fri, 08 Nov 2013 23:47:02 GMT
WWW-Authenticate: Basic realm="Username/Password"
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 346
Connection: close
Content-Type: text/html; charset=iso-8859-1

PDATE 2:これらのKibanaファイルの変更されたヘッダーですべてのインスタンスを更新しました

root@localhost:/var/www/kibana# grep -r 'ejsResource(' .

./src/app/controllers/dash.js:      $scope.ejs = ejsResource({server: config.elasticsearch, headers: {'Access-Control-Request-Headers': 'Accept, Origin, Authorization', 'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXX=='}});
./src/app/services/querySrv.js:    var ejs = ejsResource({server: config.elasticsearch, headers: {'Access-Control-Request-Headers': 'Accept, Origin, Authorization', 'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXX=='}});
./src/app/services/filterSrv.js:    var ejs = ejsResource({server: config.elasticsearch, headers: {'Access-Control-Request-Headers': 'Accept, Origin, Authorization', 'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXX=='}});
./src/app/services/dashboard.js:    var ejs = ejsResource({server: config.elasticsearch, headers: {'Access-Control-Request-Headers': 'Accept, Origin, Authorization', 'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXX=='}});

そして、このようなリバースプロキシ用に私のvhost confを変更しました

<VirtualHost *:8181>

ProxyRequests Off
ProxyPass / http://127.0.0.1:9200/
ProxyPassReverse / https://127.0.0.1:9200/

    <Location />
        Order deny,allow
        Allow from all
        AuthType Basic
        AuthName “Username/Password”
        AuthUserFile /var/www/cake2.2.4/.htpasswd
        Require valid-user

    Header always set Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS, PUT"
    Header always set Access-Control-Allow-Headers "Content-Type, X-Requested-With, X-HTTP-Method-Override, Origin, Accept, Authorization"
    Header always set Access-Control-Allow-Credentials "true"
    Header always set Cache-Control "max-age=0"
    Header always set Access-Control-Allow-Origin *

    </Location>

ErrorLog ${Apache_LOG_DIR}/error.log

</VirtualHost>

Apacheは新しい応答ヘッダーを送り返しますが、要求ヘッダーはまだどこかで間違っているようです。認証が機能しないだけです。

リクエストヘッダー

OPTIONS /solar_vendor/_search HTTP/1.1
Host: 46.252.26.173:8181
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Origin: http://46.252.26.173:81
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,content-type
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

応答ヘッダー

HTTP/1.1 401 Authorization Required
Date: Sat, 09 Nov 2013 08:48:48 GMT
Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS, PUT
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-HTTP-Method-Override, Origin, Accept, Authorization
Access-Control-Allow-Credentials: true
Cache-Control: max-age=0
Access-Control-Allow-Origin: *
WWW-Authenticate: Basic realm="Username/Password"
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 346
Connection: close
Content-Type: text/html; charset=iso-8859-1

解決策:さらに調査を行った結果、これは間違いなくCORSに関する構成の問題であることがわかりました。そのトピックに関してはかなりの数の投稿がありますが、私の問題を解決するには、Apacheで非常に細かい設定を行い、適切なものがブラウザから送信されるようにする必要があるようです。

だから私は戦略を再考し、はるかに簡単な解決策を見つけました。 vhostリバースプロキシ構成を変更して、エラスティサーチサーバーとkibanaを同じhttpポートに移動します。これにより、Kibanaのセキュリティがさらに向上します。

これは私がやったことです:

<VirtualHost *:8181>

ProxyRequests Off

ProxyPass /bigdatadesk/ http://127.0.0.1:81/bigdatadesk/src/
ProxyPassReverse /bigdatadesk/ http://127.0.0.1:81/bigdatadesk/src/

ProxyPass / http://127.0.0.1:9200/
ProxyPassReverse / https://127.0.0.1:9200/


    <Location />
        Order deny,allow
        Allow from all
        AuthType Basic
        AuthName “Username/Password”
        AuthUserFile /var/www/.htpasswd
        Require valid-user
    </Location>


ErrorLog ${Apache_LOG_DIR}/error.log

</VirtualHost>
17
Jabb

Kibanaで、既存のelastic-angular-client.jsを最新の here で置き換えます。次に、Kibanaコードで次のすべてのインスタンスを置き換えます。

$scope.ejs = ejsResource(config.elasticsearch);

$scope.ejs = ejsResource({server: config.elasticsearch, headers: {'Access-Control-Request-Headers': 'accept, Origin, authorization', 'Authorization': 'Basic ' + Base64Encode('user:Password')}});

それで十分です。

更新:

ApacheはCORS用に構成されていますか? this を参照してください。

Header always set Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS, PUT"
Header always set Access-Control-Allow-Headers "Content-Type, X-Requested-With, X-HTTP-Method-Override, Origin, Accept, Authorization"
Header always set Access-Control-Allow-Credentials "true"
Header always set Cache-Control "max-age=0"
Header always set Access-Control-Allow-Origin *
7
Matt Weber

ここに完璧な解決策があります:

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

BasicAuthバックエンドだけでなく、クライアントのGoogleOAuthおよびBasicAuthもサポートします。うまくいけば、星を付けてください、ありがとう。

10
Felix

それはCORSの問題であるという点であなたは正しいです。 Kibana 3はCORSを使用してElasticSearchと通信します。

HTTP認証ヘッダーとCookieをKibana CORSリクエストで送信できるようにするには、次の2つのことを行う必要があります。

ONE:Kibana config.jsファイルで、ElasticSearchサーバーが定義されている設定を見つけます。

elasticsearch: "http://localhost:9200",

これを次のように変更する必要があります。

elasticsearch: {server: "http://localhost:9200", withCredentials: true},

これは、サーバーがそれらを受信できる場合、Kibanaに認証ヘッダーとCookieを送信するように指示します。

TWO:次に、ElasticSearch構成ファイル(ホストサーバー上のelasticsearch.yml、CentOS7サーバー上の/etc/elasticsearch/elasticsearch.ymlにあります)に移動する必要があります。このファイルには、「ネットワークとHTTP」セクションがあります。あなたは言う行を見つける必要があります:

#http.port: 9200

この行のコメントを外して、ポートをElasticSearchを実行するポートに変更します。私は19200を選択しました。次に#transport.tcp.port: 9300設定。再び19300を選びました。

最後に、このセクションの最後に(整理のために、単にファイルの最後に以下を追加することもできます)追加します。

http.cors.allow-Origin: http://localhost:8080 http.cors.allow-credentials: true http.cors.enabled: true

上記のOriginアドレスは、WebサーバーがKibanaを提供している場所に変更できます。あるいは、単に/.*/すべてのオリジンに一致しますが、これはお勧めできません。

Elasticsearch.ymlファイルを保存し、elasticsearchサーバーを再起動します。リバースプロキシは、ポート9200で実行され、リクエストが認証される場合は19200を指すように構成する必要があります。

警告の言葉、リクエストを認証するためにCookieを使用している場合は、GET、PUT、POSTおよびDELETEリクエストにのみCookieが含まれるため、リバースプロキシ構成でHTTP OPTIONSメソッドをホワイトリストに登録する必要があります。 。OPTIONSにAuthenticationヘッダーも含まれているかどうかはテストしていませんが、Cookieと同じ状況である可能性があります。OPTIONSリクエストも通過できない場合、Kibanaは正しく機能しません。

ほとんどの場合、このコマンドは外部リクエスト経由で必要とされないため、_shutdownで終わるリクエストをブラックリストに登録するようにリバースプロキシを構成することもお勧めします。

1
Geraden