Skip to content

Commit 4c48624

Browse files
authored
1 parent 7f96070 commit 4c48624

File tree

1 file changed

+134
-36
lines changed

1 file changed

+134
-36
lines changed

docs/plugins/development/creating-classic-plugins.asciidoc

Lines changed: 134 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -49,42 +49,140 @@ to install your plugin for testing. The Java plugin is auto-loaded only if it's
4949
`plugins/` directory.
5050

5151
[discrete]
52-
[[plugin-authors-jsm]]
53-
==== Java Security permissions
54-
55-
Some plugins may need additional security permissions. A plugin can include
56-
the optional `plugin-security.policy` file containing `grant` statements for
57-
additional permissions. Any additional permissions will be displayed to the user
58-
with a large warning, and they will have to confirm them when installing the
59-
plugin interactively. So if possible, it is best to avoid requesting any
60-
spurious permissions!
61-
62-
If you are using the {es} Gradle build system, place this file in
63-
`src/main/plugin-metadata` and it will be applied during unit tests as well.
64-
65-
The Java security model is stack-based, and additional
66-
permissions are granted to the jars in your plugin, so you have to
67-
write proper security code around operations requiring elevated privileges.
68-
You might add a check to prevent unprivileged code (such as scripts)
69-
from gaining escalated permissions. For example:
70-
71-
[source,java]
72-
--------------------------------------------------
73-
// ES permission you should check before doPrivileged() blocks
74-
import org.elasticsearch.SpecialPermission;
75-
76-
SecurityManager sm = System.getSecurityManager();
77-
if (sm != null) {
78-
// unprivileged code such as scripts do not have SpecialPermission
79-
sm.checkPermission(new SpecialPermission());
80-
}
81-
AccessController.doPrivileged(
82-
// sensitive operation
83-
);
84-
--------------------------------------------------
85-
86-
Check https://www.oracle.com/technetwork/java/seccodeguide-139067.html[Secure Coding Guidelines for Java SE]
87-
for more information.
52+
[[_entitlements_policy]]
53+
==== Entitlements policy
54+
55+
Some plugins may need additional _entitlements_.
56+
57+
{es} limits the ability to perform certain security-sensitive actions as part of its _Entitlement_ security mechanism (e.g. to limit the potential fallout from remote code execution (RCE) vulnerabilities).
58+
59+
The Entitlement model is based on Java modules.
60+
An _entitlement_ granted to a Java module allows the module's code to perform the security-sensitive action associated with that entitlement. For example, the ability to create threads is limited to modules that have the `manage_threads` entitlement; likewise, the ability to read a file from the filesystem is limited to modules that have the `files` entitlement for that particular file.
61+
62+
In practice, an entitlement allows plugin code to call a well-defined set of corresponding JDK methods; without the entitlement calls to those JDK methods are denied and throw a `NotEntitledException`. Plugin can include the optional `entitlement-policy.yaml` file to define modules and required entitlements. Any additional entitlement requested by the plugin will be displayed to the user with a large warning, and users will have to confirm them when installing the plugin interactively. Therefore, it is best to avoid requesting any spurious entitlement!
63+
64+
If you are using the {es} Gradle build system, place this file in `src/main/plugin-metadata` and it will be applied during unit tests as well.
65+
66+
An entitlement policy applies to all of your plugin jars (your own code and third party dependencies). You have to write your policy file accordingly. For example, if a plugin uses the Example API client to perform network operations, it will need a policy that may look like this:
67+
68+
```YAML
69+
org.elasticsearch.example-plugin:
70+
- manage_threads
71+
com.example.api.client:
72+
- set_https_connection_properties
73+
- outbound_network
74+
```
75+
76+
Note how the network related entitlements are granted to the `com.example.api.client` module, as the code performing the sensitive network operations is in the `example-api-client` dependency.
77+
78+
If your plugin is not modular, all entitlements must be specified under the catch-all `ALL-UNNAMED` module name:
79+
80+
```YAML
81+
ALL-UNNAMED:
82+
- manage_threads
83+
- set_https_connection_properties
84+
- outbound_network
85+
```
86+
==== Entitlements
87+
88+
The entitlements currently implemented and enforced in {es} that are available to plugins are the following ones:
89+
90+
===== `manage_threads`
91+
92+
Allows code to call methods that create or modify properties on Java Threads, for example `Thread#start` or `ThreadGroup#setMaxPriority`. In general, setting the name, priority, daemon state and context class loader are things no plugins should do when executing on
93+
{es} threadpools; however, many 3rd party libraries that support async operations (e.g. Apache HTTP client) need to manage their own threads. In this case it is justifiable to request this entitlement.
94+
95+
Example:
96+
```yaml
97+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
98+
- manage_threads
99+
```
100+
101+
===== `outbound_network`
102+
103+
Allows code to call methods to make a network connection. {es} does not grant any network access by default; each plugin that needs to directly connect to an external resource (e.g. to upload or download data) must request this entitlement.
104+
105+
Example:
106+
```yaml
107+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
108+
- outbound_network
109+
```
110+
111+
===== `set_https_connection_properties`
112+
Allows code to call methods to change properties on an established HTTPS connection. While this is generally innocuous (e.g. the google API client uses it to modify the HTTPS connections they just created), these methods can allow code to change arbitrary connections.
113+
114+
Example:
115+
```yaml
116+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
117+
- set_https_connection_properties
118+
```
119+
120+
===== `inbound_network` (deprecated)
121+
Allows code to call methods to listen for incoming connections, so external resources can connect directly to your plugin. This entitlement should only be used when absolutely necessary (e.g. if a library you depend on requires it for authentication). Granting it makes the {es} node more vulnerable to attacks. This entitlement is deprecated, and can be removed in a future version of {es}.
122+
123+
Example:
124+
```yaml
125+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
126+
- inbound_network
127+
```
128+
129+
===== `load_native_libraries`
130+
Allows code to load native libraries and call https://docs.oracle.com/en/java/javase/24/core/restricted-methods.html[restricted methods]. This entitlement also enables native access for modules it is granted to. Native code may alter the JVM or circumvent access checks such as file or network restrictions.
131+
132+
Example:
133+
```yaml
134+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
135+
- load_native_libraries
136+
```
137+
138+
===== `files`
139+
140+
Allows code to access the filesystem, to read or write paths as specified by the entitlement's fields. The filesystem of the OS hosting {es} may contain sensitive files, for example credentials. Some files are meant to be always accessible to {es}, but plugins can not access them directly: {es} enforces that certain files can only be read by its core code, while some other files can not be read or written at all. A plugin is always granted `read` access to the {es} config directory and `read_write` access to the temp directory; if the plugin requires to read, write or access additional files or directories, it must specify them via this entitlement.
141+
142+
It is possible to specify 3 different types of file entitlement:
143+
144+
* `path` to specify an absolute path
145+
* `relative_path` to specify a relative path. The path will be resolved via the `relative_to` field, which is used to qualify the relative path. It can be a specific {es} directory (`config` or `data`), or to the user home directory (`home`) (the home of the user running {es})
146+
* `relative_path` to specify a path resolved via the `relative_to` field, which can have the following values:
147+
- `config`: the {es} https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html#config-files-location[config directory]
148+
- `data`: the {es} https://www.elastic.co/guide/en/elasticsearch/reference/current/path-settings-overview.html[data directory]
149+
- `home`: the home directory of the user running {es}
150+
- `path_setting` to specify a path defined via an {es} setting. The path can be absolute or relative; in the latter case, the path will be resolved using the `basedir_if_relative` path (which can assume the same values as `relative_to`)
151+
152+
Each of the 3 types has some additional fields:
153+
154+
* `mode` (required): can be either `read` or `read_write`
155+
* `platform` (optional): indicates this item applies only to one platform, which can be one of `linux`, `macos` or `windows`. On other platforms, the item is ignored. If this field is not specified, the item applies to all platforms.
156+
* `exclusive`: access to this path is exclusive for this plugin; this means that other plugins will not be able to access to it, not even if they have an entitlement that would normally grant access to that path.
157+
158+
Example:
159+
```yaml
160+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
161+
- files:
162+
- path: "/absolute/path"
163+
mode: read
164+
- relative_path: "relative/file.txt"
165+
relative_to: data
166+
mode: read_write
167+
- path_setting: setting.name
168+
basedir_if_relative: data
169+
mode: read
170+
```
171+
172+
173+
===== `write_system_properties`
174+
Allows code to set one or more system properties (e.g. by calling `System#setProperty`). The code to which this entitlement is granted can change the properties listed in the `properties` field. In general, it's best to avoid changing a system property dynamically as this can have effects on code which later reads the property. The global nature of system properties means one plugin could then affect another, depending on load order.
175+
176+
Example:
177+
```yaml
178+
org.example.module: # or 'ALL-UNNAMED' if the plugin is non-modular
179+
- write_system_properties:
180+
properties:
181+
- property.one
182+
- property.two
183+
```
184+
Check the Entitlements {es-repo}tree/main/libs/entitlement/README.md[README in the elasticsearch repository] for more information.
185+
88186

89187
[[plugin-descriptor-file-classic]]
90188
==== The plugin descriptor file for classic plugins

0 commit comments

Comments
 (0)