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

在上一篇文章里面,我们已经为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吧!~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值