创建经典插件
经典插件为 Elasticsearch 提供了自定义身份验证、授权、评分等机制。
经典插件要求您为每个新的 Elasticsearch 版本构建一个新版本。 安装插件和加载插件时,将检查此版本。 如果存在 elasticsearch.version
不正确的插件,Elasticsearch 将拒绝启动。
经典插件是 ZIP 文件,由 JAR 文件和一个名为 plugin-descriptor.properties
的元数据文件组成,该文件是描述插件的 Java 属性文件。
请注意,只有插件根目录下的 JAR 文件才会添加到插件的类路径中。 如果需要其他资源,请将其打包到资源 JAR 中。
Elasticsearch 存储库包含插件示例。 其中一些包括
- 一个带有自定义设置的插件
- 一个带有自定义采集处理器的插件
- 添加自定义 rest 端点
- 添加一个自定义重打分器
- 一个用 Java 实现的脚本
这些示例提供了入门所需的基本框架。 有关如何编写插件的更多信息,我们建议查看现有插件的源代码以获取灵感。
使用 bin/elasticsearch-plugin install file:///path/to/your/plugin
安装您的插件以进行测试。 仅当 Java 插件位于 plugins/
目录中时,它才会自动加载。
某些插件可能需要额外的授权。
Elasticsearch 限制了执行某些安全敏感操作的能力,这是其授权安全机制的一部分(例如,限制远程代码执行 (RCE) 漏洞可能造成的损失)。
授权模型基于 Java 模块。 授予 Java 模块的授权允许该模块的代码执行与该授权相关的安全敏感操作。 例如,创建线程的能力仅限于具有 manage_threads
授权的模块; 同样,从文件系统读取文件的能力仅限于具有该特定文件的 files
授权的模块。
实际上,授权允许插件代码调用一组定义明确的相应 JDK 方法; 如果没有授权,对这些 JDK 方法的调用将被拒绝并抛出 NotEntitledException
。 插件可以包含可选的 entitlement-policy.yaml
文件来定义模块和所需的授权。 插件请求的任何其他授权将以大警告显示给用户,并且用户在以交互方式安装插件时必须确认它们。 因此,最好避免请求任何虚假授权!
如果您使用的是 Elasticsearch Gradle 构建系统,请将此文件放在 src/main/plugin-metadata
中,它将在单元测试期间应用。
授权策略适用于您的所有插件 jar 文件(您自己的代码和第三方依赖项)。 您必须相应地编写您的策略文件。 例如,如果一个插件使用 Example API 客户端来执行网络操作,它将需要一个可能如下所示的策略
org.elasticsearch.example-plugin:
- manage_threads
com.example.api.client:
- set_https_connection_properties
- outbound_network
请注意,网络相关的授权是如何授予给 com.example.api.client
模块的,因为执行敏感网络操作的代码位于 example-api-client
依赖项中。
如果您的插件不是模块化的,则所有授权都必须在 catch-all ALL-UNNAMED
模块名称下指定
ALL-UNNAMED:
- manage_threads
- set_https_connection_properties
- outbound_network
当前在 Elasticsearch 中实施和强制执行的、可供插件使用的授权如下
允许代码调用创建或修改 Java 线程上的属性的方法,例如 Thread#start
或 ThreadGroup#setMaxPriority
。
此授权很少是必要的。 您的插件应使用 Elasticsearch 线程池和执行器(请参阅 Plugin#getExecutorBuilders
)而不是创建和管理自己的线程。 当在 ES 线程池上执行时,插件应避免修改线程名称、优先级、守护程序状态和上下文类加载器。
但是,许多支持异步操作的第三方库,例如 Apache HTTP 客户端,需要创建和管理自己的线程。 在这种情况下,请求此授权是有意义的。
示例
org.example.module:
- manage_threads
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
允许代码调用方法来建立网络连接。 Elasticsearch 默认不授予任何网络访问权限; 每个需要直接连接到外部资源(例如,上传或下载数据)的插件都必须请求此授权。
示例
org.example.module:
- outbound_network
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
允许代码调用方法来更改已建立的 HTTPS 连接上的属性。 虽然这通常是无害的(例如,google API 客户端使用它来修改他们刚刚创建的 HTTPS 连接),但这些方法允许代码更改任意连接。
示例
org.example.module:
- set_https_connection_properties
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
允许代码调用方法来监听传入连接,以便外部资源可以直接连接到您的插件。 只有在绝对必要时才应使用此授权(例如,如果您依赖的库需要它进行身份验证)。 授予它会使 Elasticsearch 节点更容易受到攻击。 此授权已弃用,可能会在未来版本的 Elasticsearch 中删除。
示例
org.example.module:
- inbound_network
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
允许代码加载本机库并调用受限方法。 此授权还允许授予它的模块的本机访问。 本机代码可能会更改 JVM 或规避访问检查,例如文件或网络限制。
示例
org.example.module:
- load_native_libraries
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
允许代码访问文件系统,以读取或写入授权字段指定的路径。 托管 Elasticsearch 的操作系统的文件系统可能包含敏感文件,例如凭据。 某些文件应该始终可以被 Elasticsearch 访问,但插件无法直接访问它们:Elasticsearch 强制某些文件只能由其核心代码读取,而其他一些文件则根本无法读取或写入。 插件始终被授予对 Elasticsearch 配置目录的 read
访问权限和对临时目录的 read_write
访问权限; 如果插件需要读取、写入或访问其他文件或目录,则必须通过此授权指定它们。
可以指定 3 种不同类型的文件授权
path
指定绝对路径relative_path
指定相对路径。 该路径将通过relative_to
字段解析,该字段用于限定相对路径。 它可以是特定的 Elasticsearch 目录(config
或data
),也可以是用户主目录 (home
)(运行 Elasticsearch 的用户的主目录)relative_path
指定通过relative_to
字段解析的路径,该字段可以具有以下值path_setting
指定通过 Elasticsearch 设置定义的路径。 该路径可以是绝对路径或相对路径; 在后一种情况下,该路径将使用basedir_if_relative
路径解析(该路径可以采用与relative_to
相同的值)
这 3 种类型中的每一种都有一些额外的字段
mode
(必需):可以是read
或read_write
platform
(可选):指示此项仅适用于一个平台,该平台可以是linux
、macos
或windows
之一。 在其他平台上,该项将被忽略。 如果未指定此字段,则该项适用于所有平台。exclusive
:此路径的访问权限是此插件独有的; 这意味着其他插件将无法访问它,即使它们具有通常会授予对该路径的访问权限的授权。
示例
org.example.module:
- files:
- path: "/absolute/path"
mode: read
- relative_path: "relative/file.txt"
relative_to: data
mode: read_write
- path_setting: setting.name
basedir_if_relative: data
mode: read
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
允许代码设置一个或多个系统属性(例如,通过调用 System#setProperty
)。 授予此授权的代码可以更改 properties
字段中列出的属性。 通常,最好避免动态更改系统属性,因为这可能会影响稍后读取该属性的代码。 系统属性的全局性质意味着一个插件可能会影响另一个插件,具体取决于加载顺序。
示例
org.example.module:
- write_system_properties:
properties:
- property.one
- property.two
- 如果插件是非模块化的,则为 'ALL-UNNAMED'
有关更多信息,请查看 Elasticsearch 存储库中的授权README。