安全运行Elasticsearch集群

Elasticsearch不进行认证或授权,留下了一个习题给开发者。本文给出了概述,当你配置Elasticsearch集群的安全设置时要记住,为用户提供(有限)权限访问群集,当你不一定能(完全)信任他们时。

Introduction

作为Elasticsearch的提供商,安全对于Found是非常重要的,我们需要保护我们的用户免受其他可能的恶意,还要保护我们的用户不会因为他们自身引起麻烦。 本文基于Elasticsearch in production(生产环境),我们介绍了许多(生产环境)相关的主题讨论。在本文中我们将扩大一些内容,并阐述当实际执行的时候需要记住哪些地方。 从本质上讲,你需要仔细的端详你发给Elasticsearch的请求;就像任何其他数据库。但与大多数其他数据库不同的是,Elasticsearch有一个功能,允许任意代码执行。这带来了一些有趣的挑战! 我们来看看在不同级别的信任(你可以给你的用户)带来的细微差别,风险;从任意一端完全访问发出请求,,对另一端只是参数预先定义的请求。

Responsibility

Elasticsearch不具有用户的概念。从本质上讲,任何人都可以发送任意请求到集群(他)是一个“超级用户”。

如果你曾使用过类似PostgreSQL的系统,你可以限制访问数据库的表,函数等等,拥有高粒度的访问控制系统,你可能会试图找到一种方来限制某些操作或某些indexes,目前,Elasticsearch并不认为这是自己的工作。Elasticsearch不具有用户的概念。从本质上讲,任何人都可以发送任意请求到集群并且是一个“超级用户”。这是一个合理的限制强加。有这么多的方式来实现不同的身份验证和授权方案,其中不少是紧密耦合的应用领域。 很多在这里的建议适用于搜索引擎和数据库比Elasticsearch等为好。我们的意思并不是意味着这些本质上是不安全的,还是批评他们的选择。它是一个完全合理的决定,离开安全给用户。但是,我们要提高对Elasticsearch安全相关的方面的认识。

Goals

按重要性排序,我们要做到以下几点:

  1. 防止执行任意代码的脚本功能的使用。如果我们不能这样做,别的仅仅是“security through obscurity”,可以被绕过。但禁用动态脚本引出了一些难题,。
  2. 限制谁可以访问什么:搜索和索引。这可以通过代理层实现。
  3. __阻止请求可以压倒集群,导致拒绝式服务。这是很难完全避免,如果任意的搜索请求是允许的。 __

为了开发的目的,我们也将看到_这些东西如何应用即使在本地_运行Elasticsearch 作为不同信任级别的一个例子,假设你为不同的客户安装了多个同一套CMS。你相信CMS不做疯狂的事情,但要求验证,并有单独的索引是个好主意,以确保万一。因此,您可以允许访问CMS做任意请求向其允许的indexes。 CMS虽然暴露于天下。它不接受任何随意的请求。它将搜索参数转换到正确的Elasticsearch请求,并将其发送到相应的索引。

Scripting for Fun and Profit

最终用户(可以提供脚本)必须假定 have shell access到你的主机。

Elasticsearch具有非常强大的脚本工具。这些都是重要的在许多情况下: updates, facets, filters, scoring等等。 这些脚本不是在沙箱(sandbox)中运行。因此,最终用户(可以提供脚本)必须被假定为有 equivalent of shell access(shell访问到你的主机的权限)是等效的。 没有什么可以阻止一个脚本第二次发送到Elasticsearch从而避免任何URL-based访问控制或做任何Elasticsearch有权限做的。其结果是,如果你不能完全信任你的用户,动态脚本必须被禁用(**dynamic scripts must be disabled **)。 因此,我们建议对具有动态脚本启用黑名单或净化不安全的脚本( sanitize scripts).当脚本的执行不是在沙箱时,很难断定一个脚本没有做不好的事情。Flash和Java applet’s 安全问题的历史证明它是多么难以形成沙箱而没有漏洞。此外,被证实不可能推断脚本是否会终止( provably impossible to reason whether a script will terminate)或spin和造成拒绝式服务。

Scripting without Dynamic Scripts

我们强调禁用动态脚本的重要性。这对很多事情是重要的,所以我们需要确保我们仍然实现这些东西。因此,我们来看看使用 preloaded scripts 预装的脚本,可以在搜索时间带参数的一些例子。 预加载的脚本可以被放置在config/scripts-directory. 假设我们有如下脚本:

$ cat config/scripts/scoring/recency_boost.mvel
(0.08 / ((3.16*pow(10,-11)) * abs(now - doc[‘timestamp’].date.getMillis()) + 0.05)) + 1.0

那么我们可以定义{“script”: “scoring_recency_boost”, “params”: {“now”: 1386176910000}}。script参数是一个相对于config/scripts的路径,用_作为分隔符,注意前缀是scoring_ 而不是scoring/。 使用预装的脚本提供了另一个好处:你的脚本定义在一个地方指定,并且在使用Elasticsearch集群中的各种应用程序不散落。这有助于提高你的搜索应用程序和配置文件的可维护性。你可以改变和改善你的脚本,而无需改变每一个客户端。

Limiting Indexes and Operations

注意:本节假定使用HTTP的API。目前,还没有办法容易地限制哪些客户端可以做什么。 Elasticsearch has many ways of specifying what indexes to search across or index to.。如果你有不同的用户在相同的共享集群上,让他们发送任意搜索请求(尽管没有脚本),你可能还需要限制他们可以访问的indexes。 典型地,indexes被指定在请求的URL,例如index_pattern/type_pattern/search。然而也有一些APIs像multi-search, multi-getbulk 可以有index参数在请求的body里。重写哪些indexes被搜索和哪些documents被indexed,在 0.90.4版本里,之前介绍过的配置选项[allow_explicit_index](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/url-access-control.html)可以让你禁止这些重写。 注意这个index实际上是个index pattern 无须是index name.如果你把用户定义加在indexes前缀,你应该考虑到index pattern.例如,ndex_name = “user123\“ + user_specified_index 如果user_specified_index = “,*”将不会很好的工作,这个请求最终会像user123_,*/_search,将会搜索到每个index。 将disable_dynamic_scripts设为true和allow_explicit_index设为false有可以确定请求到 _search- 和_msearch/_mget-endpoints 仅能接触到被允许的indexes,and similarly for indexing requests to _bulk。这使得在代理层限制哪些indexes可以被接触称为可能。 如果也要严格限制哪些documents_可以被操作,你可以用filtered alias,任何search, count和类似的delete的请求将被应用filter。如果你依赖这些,make sure the underlying indexes cannot be accessed. 限制哪些indexes和endpoints你的用户可以请求,你也必须考虑到哪些_methods可以被允许。你可能不想允许任何一个人DELETE an index。一个很好的实践是idempotent requests 禁止请求直接到index 仅允许POST-ing到_search_bulk和 PUT-ing和DELETE-ing到特定的documents.

Preventing Denial of Service

不像暴露数据那样有害,请求可以导致集群崩溃或者严重的性能影响,这些也是要避免的。不幸的是,避免这些不是像改配置变量那么容易。 Elasticsearch in production 这篇文章有个单元OutOfMemory-caused crashes 总之,内存溢出对于集群有灾难性的影响,这绝不能在生产环境中出现。 Elasticsearch有许多地方会消耗大量内存,不能详尽列出,举几个例子:

  • Field caches for fields to facet, sort and script on.
  • Filter caches.
  • Segments pending flushing.
  • Index metadata.

加载一个过大的字段可能是最普通引起内存溢出的原因,两个重要的改善将会随着Elasticsearch 1.0的到来更好的处理这些: 首先是document values.,在mapping里映射这些字段,Elasticsearch会用一种方式写入值使得依赖于操作系统页面缓存而更加有效的使用这些值。这可以极大的消减堆内存的消耗,尽管这种实现会使得慢一点儿。 第二个改善,执行写入操作的时候并不提交到master,is a circuit breaker. 其目的是强行限制多少内存可以被用于加载字段,如果超过这个限制将会中断,默认是禁用的,在合理的限制下,请求尝试加载过多将会中断并报CircuitBreakingException,这比OutOfMemory安全多了! 这些都需要一点儿调整配置和提交计划。虽然在内存使用率上改善了很多,仍然有个验证的性能影响,当miss-loading一个巨大的字段,其他真正需要的字段可能会被抹去,接着强制再次加载它们。 如果你允许任意结构的文档,你可能希望禁用动态mapping,虽然Elasticsearch经常被描述为一个无模式的数据库,Elasticsearch隐式的创建模。这在开发的时候工作的很好,可能需要在生产环境中关闭,例如,它可能导致问题,如果值作为你的对象的键: 假设你有一个对象{"access": [ {"123": "read"}, {"124": "write"} ]},虽然看似无害,这将在mapping里产生一个entry为每一个ID,随着成千上万这样的keys。mapping的大小会爆炸式的增长,因为每个key都会有一个entry。mapping也是集群状态的一部分,被复制到每一个节点。与面向文档的数据库(没有模式概念的)可以很好的工作,并将documents作为blobs。然而在Elasticsearch中绝不要把值作为键。这个例子应该改为{"access": [ {"user_id": 123, "level": "read"}, {"user_id": 124: "level": "write"} ] },with `access` as a nested type. 总之,虽然可以限制哪些indexex可以被搜索或indexed通过个简单的代理层,但不可能接受任意的请求erubuyong担心集群的稳定性和性能。这是关于任何数据库或搜索引擎的一个状况,应该不会感到意外。我们看到很多这种实现,Kibana it makes a lot of sense,因为它在很大程度上是一个Elasticsearch仪表板。但如果你复制它的使用模式并重新实现它在你最终用户所面对的应用程序,你也把这里提到的风险带过去了。

Staying Safe while Developing with Elasticsearch

Elasticsearch is 通常是通过 HTTP绑定到 localhost.直观地看,外部的注释无法连接到监听localhost的程序或被公司的防火墙保护的。然而你的浏览器可以抵达你的localhost,也许可能连接上servers通过公司的内部网络. 任何你访问的网站可以发送请求到你的本地Elasticsearch节点。你的浏览器会愉快地发起 HTTP 请求到 127.0.0.1/_search. 因此,任何网站可以探索任何运行在你本地的Elasticsearch的数据.然后它可以POST到某处调整settings for cross-origin resource sharing 会有些帮助, 尽管它还是可以tongue JSONP请求进行搜索。 我们对动态脚本的警告,在这里也适用。你肯定不希望任何网站可以在你的机器上运行代码. 我们建议将Elasticsearch运行在虚拟主机里,若你开发时用这台机器并用它来浏览网页。不要在本地保存命案数据并禁用动态脚本。

Suggested Solutions

限制访问indexes并添加身份验证和SSL可以由多种工具来完成。这些已经超出本文的范围,Nginx做这个很流行,此外有各种Elasticsearch插件尝试添加基本认证.在Found我们提供这些作为代理层的一部分来路由请求。你可以配置 ACLs 来 HTTP 基本认证, SSL, 和限制哪些方法和路径可以被访问。此外,这些规则可以被组合,以适应几乎任何情况。大多数Elasticsearch 客户端现在支持HTTP基本认证,SSL和其他好东西,包括官方的客户端,所以没有理由不用它们。

尽管 Elasticsearch是 multi-tenant(多用户)的 ,并能愉快地服务于许多不同的用户和应用在同一个集群有些时候你可能想要创建多个集群分割资源并提供额外的安全性。 从本质上讲,要减少对 [Preventing denial of service]一节中描述的问题和风险的影响范围. 例如,如果你有一个巨大的尖峰流量,增加吞吐量记录(你使用Logstash和Kibana捕获分析,对吧?)不应该影响到更重要的应用程序的性能。 Today, it’s easier than ever to use technologies like LXC and Docker to isolate processes, and constrain resource usage like disk space, memory and CPU. That is exactly what we do at Found. Customer clusters are completely isolated and resources are dedicated, not overprovisioned. This is very important, without these practices we would not be able to guarantee an acceptable level of security and performance would be unreliable.

Key Takeaways

This article has covered a lot of ground, but be sure to keep in mind the following.

  1. Disable dynamic scripts. They are dangerous.
  2. Understand the sometimes tricky configuration is required to limit access controls to indexes.
  3. Consider the performance implications of multiple tenants, a weakness or a bad query in one can bring down an entire cluster!

很酷的东西不断的加入Elasticsearch,正在一个令人兴奋的步伐,有些改善会使生活更加容易当处理这里提到过的挑战时。有些会带来新的挑战,你必须认为安全性是交给你的。记住安全性就像洋葱(onion), 一个好的策略是设置多层。不要让Elasticsearch 成为脆弱的一层在你应用程序的security onion!

原文:https://www.found.no/foundation/elasticsearch-security/