From 35d7a24833674dfafa7bd2f7a28e8e61e003312e Mon Sep 17 00:00:00 2001 From: Moritz Mack Date: Tue, 22 Jul 2025 12:09:59 +0200 Subject: [PATCH 1/3] Grant server read/write permissions on shared data path "path.shared_data". Relates to ES-12447 --- .../entitlement/bootstrap/EntitlementBootstrap.java | 3 +++ .../entitlement/bootstrap/HardcodedEntitlements.java | 2 ++ .../entitlement/runtime/policy/PathLookup.java | 1 + .../entitlement/runtime/policy/PathLookupImpl.java | 2 ++ .../bootstrap/FilesEntitlementsValidationTests.java | 1 + .../runtime/policy/FileAccessTreeTests.java | 1 + .../runtime/policy/PolicyManagerTests.java | 1 + .../policy/entitlements/FilesEntitlementTests.java | 1 + .../org/elasticsearch/bootstrap/Elasticsearch.java | 1 + .../bootstrap/TestEntitlementBootstrap.java | 12 +++++++++++- 10 files changed, 24 insertions(+), 1 deletion(-) diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java index 3d364f4b53cec..7a38ff50a8d6d 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java @@ -46,6 +46,7 @@ public class EntitlementBootstrap { * @param scopeResolver a functor to map a Java Class to the component and module it belongs to. * @param settingResolver a functor to resolve a setting name pattern for one or more Elasticsearch settings. * @param dataDirs data directories for Elasticsearch + * @param sharedDataDir shared data directory for Elasticsearch (deprecated) * @param sharedRepoDirs shared repository directories for Elasticsearch * @param configDir the config directory for Elasticsearch * @param libDir the lib directory for Elasticsearch @@ -63,6 +64,7 @@ public static void bootstrap( Function, PolicyManager.PolicyScope> scopeResolver, Function> settingResolver, Path[] dataDirs, + Path sharedDataDir, Path[] sharedRepoDirs, Path configDir, Path libDir, @@ -82,6 +84,7 @@ public static void bootstrap( getUserHome(), configDir, dataDirs, + sharedDataDir, sharedRepoDirs, libDir, modulesDir, diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java index 7ac921e29174f..278b9e773ae1f 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java @@ -37,6 +37,7 @@ import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LOGS; import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.MODULES; import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.PLUGINS; +import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.SHARED_DATA; import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.SHARED_REPO; import static org.elasticsearch.entitlement.runtime.policy.Platform.LINUX; import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ; @@ -57,6 +58,7 @@ private static List createServerEntitlements(Path pidFile) { FilesEntitlement.FileData.ofBaseDirPath(LOGS, READ_WRITE), FilesEntitlement.FileData.ofBaseDirPath(LIB, READ), FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE), + FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE), FilesEntitlement.FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE), // exclusive settings file FilesEntitlement.FileData.ofRelativePath(Path.of("operator/settings.json"), CONFIG, READ_WRITE).withExclusive(true), diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java index 3d2daf5e407c6..2febb301d1ab4 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java @@ -24,6 +24,7 @@ enum BaseDir { USER_HOME, CONFIG, DATA, + SHARED_DATA, SHARED_REPO, LIB, MODULES, diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java index df259254025bb..9dec5148fbcaf 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java @@ -25,6 +25,7 @@ public record PathLookupImpl( Path homeDir, Path configDir, Path[] dataDirs, + Path sharedDataDir, Path[] sharedRepoDirs, Path libDir, Path modulesDir, @@ -56,6 +57,7 @@ public Stream getBaseDirPaths(BaseDir baseDir) { return switch (baseDir) { case USER_HOME -> Stream.of(homeDir); case DATA -> Arrays.stream(dataDirs); + case SHARED_DATA -> Stream.of(sharedDataDir); case SHARED_REPO -> Arrays.stream(sharedRepoDirs); case CONFIG -> Stream.of(configDir); case LIB -> Stream.of(libDir); diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java index 7c4a14dd44cab..07631e7dbf5d6 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java @@ -48,6 +48,7 @@ public static void beforeClass() { testBaseDir.resolve("user/home"), TEST_CONFIG_DIR, new Path[] { testBaseDir.resolve("data1"), testBaseDir.resolve("data2") }, + Path.of("/shareddata"), new Path[] { testBaseDir.resolve("shared1"), testBaseDir.resolve("shared2") }, TEST_LIBS_DIR, testBaseDir.resolve("modules"), diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java index 9307f89b4d0d3..5f5378b5e1fe9 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java @@ -59,6 +59,7 @@ private static Path path(String s) { Path.of("/home"), Path.of("/config"), new Path[] { Path.of("/data1"), Path.of("/data2") }, + Path.of("/shareddata"), new Path[] { Path.of("/shared1"), Path.of("/shared2") }, Path.of("/lib"), Path.of("/modules"), diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java index e1f20a0eae990..29678d14fc507 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java @@ -71,6 +71,7 @@ public static void beforeClass() { baseDir.resolve("/user/home"), baseDir.resolve("/config"), new Path[] { baseDir.resolve("/data1/"), baseDir.resolve("/data2") }, + Path.of("/shareddata"), new Path[] { baseDir.resolve("/shared1"), baseDir.resolve("/shared2") }, baseDir.resolve("/lib"), baseDir.resolve("/modules"), diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java index 84c4833ca6aae..d6f85eb4f069a 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java @@ -47,6 +47,7 @@ public static void setupRoot() { Path.of("/home"), Path.of("/config"), new Path[] { Path.of("/data1"), Path.of("/data2") }, + Path.of("/shareddata"), new Path[] { Path.of("/shared1"), Path.of("/shared2") }, Path.of("/lib"), Path.of("/modules"), diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java b/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java index e38f2f88d4ad9..8b59a59dcf313 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java @@ -256,6 +256,7 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException { scopeResolver::resolveClassToScope, nodeEnv.settings()::getValues, nodeEnv.dataDirs(), + nodeEnv.sharedDataDir(), nodeEnv.repoDirs(), nodeEnv.configDir(), nodeEnv.libDir(), diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java index 3e6f09915358b..432861e433d3c 100644 --- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java +++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java @@ -12,11 +12,11 @@ import org.elasticsearch.bootstrap.TestBuildInfo; import org.elasticsearch.bootstrap.TestBuildInfoParser; import org.elasticsearch.bootstrap.TestScopeResolver; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.Booleans; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.PathUtils; -import org.elasticsearch.core.Strings; import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.entitlement.initialization.EntitlementInitialization; import org.elasticsearch.entitlement.runtime.policy.PathLookup; @@ -54,6 +54,7 @@ import static org.elasticsearch.env.Environment.PATH_DATA_SETTING; import static org.elasticsearch.env.Environment.PATH_HOME_SETTING; import static org.elasticsearch.env.Environment.PATH_REPO_SETTING; +import static org.elasticsearch.env.Environment.PATH_SHARED_DATA_SETTING; public class TestEntitlementBootstrap { @@ -85,10 +86,12 @@ public static void registerNodeBaseDirs(Settings settings, Path configPath) { Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings)); Path configDir = configPath != null ? configPath : homeDir.resolve("config"); Collection dataDirs = dataDirs(settings, homeDir); + Path sharedDataDir = sharedDataDir(settings); Collection repoDirs = repoDirs(settings); logger.debug("Registering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs); baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir))); baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs))); + baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.add(sharedDataDir))); baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs))); policyManager.reset(); } @@ -100,10 +103,12 @@ public static void unregisterNodeBaseDirs(Settings settings, Path configPath) { Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings)); Path configDir = configPath != null ? configPath : homeDir.resolve("config"); Collection dataDirs = dataDirs(settings, homeDir); + Path sharedDataDir = sharedDataDir(settings); Collection repoDirs = repoDirs(settings); logger.debug("Unregistering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs); baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir))); baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs))); + baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.remove(sharedDataDir))); baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs))); policyManager.reset(); } @@ -115,6 +120,11 @@ private static Collection dataDirs(Settings settings, Path homeDir) { : dataDirs.stream().map(TestEntitlementBootstrap::absolutePath).toList(); } + private static Path sharedDataDir(Settings settings) { + String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings); + return Strings.hasText(sharedDataDir) ? absolutePath(sharedDataDir) : null; + } + private static Collection repoDirs(Settings settings) { return PATH_REPO_SETTING.get(settings).stream().map(TestEntitlementBootstrap::absolutePath).toList(); } From 90ef9a38dd488eed9ffa1db60b5712ae3a5a4294 Mon Sep 17 00:00:00 2001 From: Moritz Mack Date: Tue, 22 Jul 2025 12:14:04 +0200 Subject: [PATCH 2/3] Update docs/changelog/131680.yaml --- docs/changelog/131680.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changelog/131680.yaml diff --git a/docs/changelog/131680.yaml b/docs/changelog/131680.yaml new file mode 100644 index 0000000000000..67ccde4730dea --- /dev/null +++ b/docs/changelog/131680.yaml @@ -0,0 +1,5 @@ +pr: 131680 +summary: Grant server read/write permissions on shared data path "path.shared_data" +area: Infra/Entitlements +type: bug +issues: [] From b681afe3bd4411b38527ce09d29e3d35a35f520e Mon Sep 17 00:00:00 2001 From: Moritz Mack Date: Tue, 22 Jul 2025 12:33:06 +0200 Subject: [PATCH 3/3] fix --- docs/changelog/131680.yaml | 4 ++-- .../entitlement/runtime/policy/PathLookupImpl.java | 2 +- .../bootstrap/TestEntitlementBootstrap.java | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/changelog/131680.yaml b/docs/changelog/131680.yaml index 67ccde4730dea..0eec4d117b28f 100644 --- a/docs/changelog/131680.yaml +++ b/docs/changelog/131680.yaml @@ -1,5 +1,5 @@ pr: 131680 -summary: Grant server read/write permissions on shared data path "path.shared_data" -area: Infra/Entitlements +summary: Grant server module read/write entitlements for deprecated path setting "path.shared_data" +area: Infra/Core type: bug issues: [] diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java index 9dec5148fbcaf..d3be1d08ef989 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java @@ -57,7 +57,7 @@ public Stream getBaseDirPaths(BaseDir baseDir) { return switch (baseDir) { case USER_HOME -> Stream.of(homeDir); case DATA -> Arrays.stream(dataDirs); - case SHARED_DATA -> Stream.of(sharedDataDir); + case SHARED_DATA -> Stream.ofNullable(sharedDataDir); case SHARED_REPO -> Arrays.stream(sharedRepoDirs); case CONFIG -> Stream.of(configDir); case LIB -> Stream.of(libDir); diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java index 432861e433d3c..1edc0b4763abb 100644 --- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java +++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java @@ -86,12 +86,12 @@ public static void registerNodeBaseDirs(Settings settings, Path configPath) { Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings)); Path configDir = configPath != null ? configPath : homeDir.resolve("config"); Collection dataDirs = dataDirs(settings, homeDir); - Path sharedDataDir = sharedDataDir(settings); + Collection sharedDataDir = sharedDataDir(settings); Collection repoDirs = repoDirs(settings); logger.debug("Registering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs); baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir))); baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs))); - baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.add(sharedDataDir))); + baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.addAll(sharedDataDir))); baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs))); policyManager.reset(); } @@ -103,12 +103,12 @@ public static void unregisterNodeBaseDirs(Settings settings, Path configPath) { Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings)); Path configDir = configPath != null ? configPath : homeDir.resolve("config"); Collection dataDirs = dataDirs(settings, homeDir); - Path sharedDataDir = sharedDataDir(settings); + Collection sharedDataDir = sharedDataDir(settings); Collection repoDirs = repoDirs(settings); logger.debug("Unregistering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs); baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir))); baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs))); - baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.remove(sharedDataDir))); + baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.removeAll(sharedDataDir))); baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs))); policyManager.reset(); } @@ -120,9 +120,9 @@ private static Collection dataDirs(Settings settings, Path homeDir) { : dataDirs.stream().map(TestEntitlementBootstrap::absolutePath).toList(); } - private static Path sharedDataDir(Settings settings) { + private static Collection sharedDataDir(Settings settings) { String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings); - return Strings.hasText(sharedDataDir) ? absolutePath(sharedDataDir) : null; + return Strings.hasText(sharedDataDir) ? List.of(absolutePath(sharedDataDir)) : List.of(); } private static Collection repoDirs(Settings settings) {