[Kibana]如何支持携带身份信息的请求到Elasticsearch服务器

来源:互联网 发布:linux程序设计pdf下载 编辑:程序博客网 时间:2024/05/01 08:26

在上一篇文章里面,我们已经为Kibana服务器添加了带有表单验证的安全措施,作为下一环节,我们需要把用户验证的安全信息传递给ES服务器,以为后续基于ES上开发 RBAC(基于角色的访问控制)和IP ACL安全过滤系统打下基础。

对于ELK整体安全解决方案个人总结下来有以下几类:

  1. X-PACK(SHIELD)
    官方出品,可以保护Kibana,ES,以及Logstash的验证。控制颗粒可以达到Node,Index,设置Field。使用Elastic Cloud包含在订阅内的价格是$45一个月
  2. NGINX反向代理
    使用Nginx给Kibana,ES做HTTP的反向代理服务,并且完全依赖于Nginx的Basic验证机制以及LUA脚本来实现角色控制访问,控制颗粒度没有x-pack那么细致,在实际运维中,所有配置由系统管理员控制,无法下放到ELK管理员手中。
  3. SEARCHGUARD
    第三方ES插件以替代X-pack完整功能,并且在免费版本中即提供Basic 身份验证,基于角色的Index,alias的访问控制,并且可以和Kibana以及Logstash集成,但是只会在收费版本中提供LDAP验证的支持

个人觉得一个完整的ELK的安全套件需要拥有以下这些特性:

  • 完整端到端的安全控制,包括ELK的各个环节。
  • 用户验证,支持LDAP的验证,提供表单验证体验。
  • 角色授权,可以支持到Indices,Alias,Field以及各种ES管理接口的控制。
  • 提供Kibana到ES的代理客户端的登录安全穿透,不使用特权账号访问后台数据。
  • 配置管理由ELK管理员管理,而不假手于其他人。
  • 提供审计功能。

言归正传,我们来看下Kibana到底是如何来和ES打交道的

const elasticsearch = require('elasticsearch');...........options = _.defaults(options || {}, {      url: config.get('elasticsearch.url'),      username: config.get('elasticsearch.username'),      password: config.get('elasticsearch.password'),      verifySsl: config.get('elasticsearch.ssl.verify'),      clientCrt: config.get('elasticsearch.ssl.cert'),      clientKey: config.get('elasticsearch.ssl.key'),      ca: config.get('elasticsearch.ssl.ca'),      apiVersion: config.get('elasticsearch.apiVersion'),      pingTimeout: config.get('elasticsearch.pingTimeout'),      requestTimeout: config.get('elasticsearch.requestTimeout'),      keepAlive: true,      auth: true    });    ...........let authorization;    if (options.auth && options.username && options.password) {      uri.auth = util.format('%s:%s', options.username, options.password);    }    ....................return new elasticsearch.Client({      host,      ssl,      plugins: options.plugins,      apiVersion: options.apiVersion,      keepAlive: options.keepAlive,      pingTimeout: options.pingTimeout,      requestTimeout: options.requestTimeout,      log: function () {        this.error = function (err) {          server.log(['error', 'elasticsearch'], err);        };        this.warning = function (message) {          server.log(['warning', 'elasticsearch'], message);        };        this.info = _.noop;        this.debug = _.noop;        this.trace = _.noop;        this.close = _.noop;      }    });

可以看出,在Kibana服务器启动的时候,系统会全局初始化elasticsearch.Client的对象,如果在kibana的配置文件中,配置了elasticsearch.username 和 elasticsearch.password,系统会以标准的Http 验证头的格式访问ES URL,如:http://username:password@example.com/ ,这里能够为我们提供全局性验证信息。

再次细化,Kibana并不是完全依赖于Node的ES客户端完成数据的交互,它还使用了直接HTTP请求的,由客户端直接穿透到ES服务器端进行搜索操作。

下图是在Kibana上进行数据浏览的时候,客户端发出的一个请求,我们发现客户端组发出了一个 /_msearch ES endpoint请求

这里写图片描述

回到系统初始化阶段,我们发现Kiaban为 /_msearch端点设置了代理类

init(server, options) {      const kibanaIndex = server.config().get('kibana.index');      // Expose the client to the server      exposeClient(server);      createProxy(server, 'GET', '/{paths*}');      createProxy(server, 'POST', '/_mget');      createProxy(server, 'POST', '/{index}/_search');      createProxy(server, 'POST', '/{index}/_field_stats');      createProxy(server, 'POST', '/_msearch');      createProxy(server, 'POST', '/_search/scroll');........const options = {    method: method,    path: createProxy.createPath(route),    config: {      timeout: {        socket: server.config().get('elasticsearch.requestTimeout')      }    },    handler: {      proxy: {        mapUri: mapUri(server),        agent: createAgent(server),        xforward: true,        timeout: server.config().get('elasticsearch.requestTimeout'),        onResponse: function (err, responseFromUpstream, request, reply) {          reply(err, responseFromUpstream);        }      }    },  };

我们只需要把之前表单验证后的Basic Authentication 携带给ES就可以完美实现注入验证信息:

let customHeaders = {} ;    //console.log(customHeaders);    if(request.auth.isAuthenticated){        console.log('credentials:'+ request.auth.credentials);        customHeaders = setHeaders(headers, assign({},config.get('elasticsearch.customHeaders'),  {'authorization': request.auth.credentials}));    }    else    {      customHeaders = setHeaders(headers, config.get('elasticsearch.customHeaders'));    }

我们分别使用两个账号登录到Kibana系统,进行ES的查询交互

这里写图片描述

这里写图片描述

最后使用Wire shark来抓包看看是否如同我们所需要的结果:

这里写图片描述

这里写图片描述

可以看出ES完美接收到客户端传递给它的Basic身份信息,接下来的事情就交给Elasticsearch吧!~

0 0
原创粉丝点击