Browse Source

[8.x] Permanently switch from SecurityManager to Entitlements (#124865) (#125076)

* Permanently switch from SecurityManager to Entitlements (#124865)

The JDK team has completely disabled the Java SecurityManager from Java 24. Elasticsearch has always used the Java SecurityManager as an additional protection mechanism; in order to retain this second line of defense, the Elasticsearch Core/Infra team has been working on the Entitlements project.

Similar to SecurityManager, Entitlements only allow calling specific methods in the JDK when the caller has a matching policy attached. In other words, if some code (in the main Elasticsearch codebase, in a plugin/module, or in a script) attempts to perform a "privileged" operation and it is not entitled to do so, a NotEntitledException will be thrown.

This PR includes the minimal set of changes to always use Entitlements, regardless of system properties or Java version.

Relates to ES-10921

* Update changelog
Lorenzo Dematté 7 months ago
parent
commit
653313b374

+ 4 - 8
build-tools/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java

@@ -42,7 +42,7 @@ public abstract class RunTask extends DefaultTestClustersTask {
 
     private Boolean debug = false;
     private Boolean cliDebug = false;
-    private Boolean entitlementsEnabled = false;
+
     private Boolean apmServerEnabled = false;
 
     private Boolean preserveData = false;
@@ -74,9 +74,7 @@ public abstract class RunTask extends DefaultTestClustersTask {
         option = "entitlements",
         description = "Use the Entitlements agent system in place of SecurityManager to enforce sandbox policies."
     )
-    public void setEntitlementsEnabled(boolean enabled) {
-        this.entitlementsEnabled = enabled;
-    }
+    public void setEntitlementsEnabled(boolean enabled) {}
 
     @Input
     public Boolean getDebug() {
@@ -90,7 +88,7 @@ public abstract class RunTask extends DefaultTestClustersTask {
 
     @Input
     public Boolean getEntitlementsEnabled() {
-        return entitlementsEnabled;
+        return true;
     }
 
     @Input
@@ -240,9 +238,7 @@ public abstract class RunTask extends DefaultTestClustersTask {
         if (cliDebug) {
             enableCliDebug();
         }
-        if (entitlementsEnabled) {
-            enableEntitlements();
-        }
+        enableEntitlements();
     }
 
     @TaskAction

+ 9 - 12
distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/SystemJvmOptions.java

@@ -11,8 +11,6 @@ package org.elasticsearch.server.cli;
 
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.concurrent.EsExecutors;
-import org.elasticsearch.core.Booleans;
-import org.elasticsearch.core.UpdateForV9;
 import org.elasticsearch.jdk.RuntimeVersionFeature;
 
 import java.io.IOException;
@@ -27,10 +25,10 @@ final class SystemJvmOptions {
 
     static List<String> systemJvmOptions(Settings nodeSettings, final Map<String, String> sysprops) {
         String distroType = sysprops.get("es.distribution.type");
+        String javaType = sysprops.get("es.java.type");
         boolean isHotspot = sysprops.getOrDefault("sun.management.compiler", "").contains("HotSpot");
-        boolean entitlementsExplicitlyEnabled = Booleans.parseBoolean(sysprops.getOrDefault("es.entitlements.enabled", "true"));
-        // java 24+ only supports entitlements, but it may be enabled on earlier versions explicitly
-        boolean useEntitlements = RuntimeVersionFeature.isSecurityManagerAvailable() == false || entitlementsExplicitlyEnabled;
+
+        boolean useEntitlements = true;
         return Stream.of(
             Stream.of(
                 /*
@@ -69,20 +67,20 @@ final class SystemJvmOptions {
                 "-Djava.locale.providers=" + getLocaleProviders(),
                 // Enable vectorization for whatever version we are running. This ensures we use vectorization even when running EA builds.
                 "-Dorg.apache.lucene.vectorization.upperJavaFeatureVersion=" + Runtime.version().feature(),
-                // Pass through distribution type
-                "-Des.distribution.type=" + distroType
+                // Pass through distribution type and java type
+                "-Des.distribution.type=" + distroType,
+                "-Des.java.type=" + javaType
             ),
             maybeEnableNativeAccess(useEntitlements),
             maybeOverrideDockerCgroup(distroType),
             maybeSetActiveProcessorCount(nodeSettings),
             maybeSetReplayFile(distroType, isHotspot),
             maybeWorkaroundG1Bug(),
-            maybeAllowSecurityManager(),
+            maybeAllowSecurityManager(useEntitlements),
             maybeAttachEntitlementAgent(useEntitlements)
         ).flatMap(s -> s).toList();
     }
 
-    @UpdateForV9    // only use CLDR in v9+
     private static String getLocaleProviders() {
         /*
          * When on pre-23, use COMPAT instead to maintain existing date formats as much as we can,
@@ -162,9 +160,8 @@ final class SystemJvmOptions {
         return Stream.of();
     }
 
-    private static Stream<String> maybeAllowSecurityManager() {
-        if (RuntimeVersionFeature.isSecurityManagerAvailable()) {
-            // Will become conditional on useEntitlements once entitlements can run without SM
+    private static Stream<String> maybeAllowSecurityManager(boolean useEntitlements) {
+        if (RuntimeVersionFeature.isSecurityManagerAvailable() && useEntitlements == false) {
             return Stream.of("-Djava.security.manager=allow");
         }
         return Stream.of();

+ 8 - 0
docs/changelog/125076.yaml

@@ -0,0 +1,8 @@
+pr: 125076
+summary: "Permanently switch from Java SecurityManager to Entitlements.
+  The Java SecurityManager has been deprecated since Java 17, and it is now completely disabled in Java 24. In order
+  to retain an similar level of protection, Elasticsearch implemented its own protection mechanism, Entitlements.
+  Starting with this version, Entitlements will permanently replace the Java SecurityManager."
+area: Infra/Core
+type: upgrade
+issues: []

+ 1 - 5
modules/ingest-attachment/src/main/java/org/elasticsearch/ingest/attachment/TikaImpl.java

@@ -18,11 +18,9 @@ import org.apache.tika.parser.Parser;
 import org.apache.tika.parser.ParserDecorator;
 import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.bootstrap.FilePermissionUtils;
-import org.elasticsearch.core.Booleans;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.jdk.JarHell;
-import org.elasticsearch.jdk.RuntimeVersionFeature;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -129,9 +127,7 @@ final class TikaImpl {
         : null;
 
     private static boolean isUsingSecurityManager() {
-        boolean entitlementsEnabled = Booleans.parseBoolean(System.getProperty("es.entitlements.enabled"), false)
-            || RuntimeVersionFeature.isSecurityManagerAvailable() == false;
-        return entitlementsEnabled == false;
+        return false;
     }
 
     // compute some minimal permissions for parsers. they only get r/w access to the java temp directory,

+ 2 - 4
server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

@@ -28,7 +28,6 @@ import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.transport.BoundTransportAddress;
 import org.elasticsearch.common.util.concurrent.RunOnce;
 import org.elasticsearch.core.AbstractRefCounted;
-import org.elasticsearch.core.Booleans;
 import org.elasticsearch.core.CheckedConsumer;
 import org.elasticsearch.core.IOUtils;
 import org.elasticsearch.core.SuppressForbidden;
@@ -124,9 +123,8 @@ class Elasticsearch {
         final PrintStream out = getStdout();
         final PrintStream err = getStderr();
         final ServerArgs args;
-        final boolean entitlementsEnabled = Booleans.parseBoolean(System.getProperty("es.entitlements.enabled", "true"));
-        // java 24+ only supports entitlements, but it may be enabled on earlier versions explicitly
-        final boolean useEntitlements = RuntimeVersionFeature.isSecurityManagerAvailable() == false || entitlementsEnabled;
+
+        final boolean useEntitlements = true;
         try {
             initSecurityProperties();
 

+ 1 - 1
x-pack/qa/security-example-spi-extension/src/main/java/org/elasticsearch/example/ExampleSecurityExtension.java

@@ -36,7 +36,7 @@ import static org.elasticsearch.example.role.CustomInMemoryRolesProvider.ROLE_B;
 public class ExampleSecurityExtension implements SecurityExtension {
 
     static {
-        final boolean useEntitlements = Boolean.parseBoolean(System.getProperty("es.entitlements.enabled"));
+        final boolean useEntitlements = true;
         if (useEntitlements == false && RuntimeVersionFeature.isSecurityManagerAvailable()) {
             // check that the extension's policy works.
             AccessController.doPrivileged((PrivilegedAction<Void>) () -> {