Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public record BootstrapArgs(
Path configDir,
Path libDir,
Path pluginsDir,
Map<String, Path> bundlesDirs,
Path logsDir,
Path tempDir,
Path pidFile,
Expand All @@ -58,6 +59,7 @@ public record BootstrapArgs(
requireNonNull(configDir);
requireNonNull(libDir);
requireNonNull(pluginsDir);
requireNonNull(bundlesDirs);
requireNonNull(logsDir);
requireNonNull(tempDir);
requireNonNull(suppressFailureLogClasses);
Expand All @@ -78,10 +80,11 @@ public static BootstrapArgs bootstrapArgs() {
* @param pluginResolver a functor to map a Java Class to the plugin it belongs to (the plugin name).
* @param settingResolver a functor to resolve a setting name pattern for one or more Elasticsearch settings.
* @param dataDirs data directories for Elasticsearch
* @param sharedRepoDirs shared repository directories for Elasticsearch
* @param sharedRepoDirs shared repository directories for Elasticsearch
* @param configDir the config directory for Elasticsearch
* @param libDir the lib directory for Elasticsearch
* @param pluginsDir the directory where plugins are installed for Elasticsearch
* @param bundlesDirs a map holding the path for each plugin or module, by plugin (or module) name.
* @param tempDir the temp directory for Elasticsearch
* @param logsDir the log directory for Elasticsearch
* @param pidFile path to a pid file for Elasticsearch, or {@code null} if one was not specified
Expand All @@ -96,6 +99,7 @@ public static void bootstrap(
Path configDir,
Path libDir,
Path pluginsDir,
Map<String, Path> bundlesDirs,
Path logsDir,
Path tempDir,
Path pidFile,
Expand All @@ -114,6 +118,7 @@ public static void bootstrap(
configDir,
libDir,
pluginsDir,
bundlesDirs,
logsDir,
tempDir,
pidFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,12 @@ private static PolicyManager createPolicyManager() {
)
)
);
var resolver = EntitlementBootstrap.bootstrapArgs().pluginResolver();
return new PolicyManager(
serverPolicy,
agentEntitlements,
pluginPolicies,
resolver,
EntitlementBootstrap.bootstrapArgs().pluginResolver(),
EntitlementBootstrap.bootstrapArgs().bundlesDirs(),
AGENTS_PACKAGE_NAME,
ENTITLEMENTS_MODULE,
pathLookup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

package org.elasticsearch.entitlement.runtime.policy;

import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.Strings;
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode;
Expand Down Expand Up @@ -91,6 +92,7 @@ private FileAccessTree(
String moduleName,
FilesEntitlement filesEntitlement,
PathLookup pathLookup,
Path componentDir,
List<ExclusivePath> exclusivePaths
) {
List<String> updatedExclusivePaths = new ArrayList<>();
Expand Down Expand Up @@ -139,10 +141,13 @@ private FileAccessTree(
});
}

// everything has access to the temp dir, config dir and the jdk
// everything has access to the temp dir, config dir, to their own dir (their own jar files) and the jdk
addPathAndMaybeLink.accept(pathLookup.tempDir(), READ_WRITE);
// TODO: this grants read access to the config dir for all modules until explicit read entitlements can be added
addPathAndMaybeLink.accept(pathLookup.configDir(), Mode.READ);
if (componentDir != null) {
addPathAndMaybeLink.accept(componentDir, Mode.READ);
}

// TODO: watcher uses javax.activation which looks for known mime types configuration, should this be global or explicit in watcher?
Path jdk = Paths.get(System.getProperty("java.home"));
Expand Down Expand Up @@ -179,9 +184,10 @@ public static FileAccessTree of(
String moduleName,
FilesEntitlement filesEntitlement,
PathLookup pathLookup,
@Nullable Path componentDir,
List<ExclusivePath> exclusivePaths
) {
return new FileAccessTree(componentName, moduleName, filesEntitlement, pathLookup, exclusivePaths);
return new FileAccessTree(componentName, moduleName, filesEntitlement, pathLookup, componentDir, exclusivePaths);
}

boolean canRead(Path path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,20 @@ public <E extends Entitlement> Stream<E> getEntitlements(Class<E> entitlementCla
}
}

private FileAccessTree getDefaultFileAccess(String componentName) {
return FileAccessTree.of(
componentName,
UNKNOWN_COMPONENT_NAME,
FilesEntitlement.EMPTY,
pathLookup,
bundlesDirs.get(componentName),
List.of()
);
}

// pkg private for testing
ModuleEntitlements defaultEntitlements(String componentName) {
return new ModuleEntitlements(componentName, Map.of(), defaultFileAccess);
return new ModuleEntitlements(componentName, Map.of(), getDefaultFileAccess(componentName));
}

// pkg private for testing
Expand All @@ -107,7 +118,7 @@ ModuleEntitlements policyEntitlements(String componentName, String moduleName, L
return new ModuleEntitlements(
componentName,
entitlements.stream().collect(groupingBy(Entitlement::getClass)),
FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, exclusivePaths)
FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, bundlesDirs.get(componentName), exclusivePaths)
);
}

Expand All @@ -118,7 +129,6 @@ ModuleEntitlements policyEntitlements(String componentName, String moduleName, L
private final Map<String, Map<String, List<Entitlement>>> pluginsEntitlements;
private final Function<Class<?>, String> pluginResolver;
private final PathLookup pathLookup;
private final FileAccessTree defaultFileAccess;
private final Set<Class<?>> mutedClasses;

public static final String ALL_UNNAMED = "ALL-UNNAMED";
Expand All @@ -139,6 +149,7 @@ private static Set<Module> findSystemModules() {
).collect(Collectors.toUnmodifiableSet());
}

private final Map<String, Path> bundlesDirs;
/**
* The package name containing classes from the APM agent.
*/
Expand All @@ -161,6 +172,7 @@ public PolicyManager(
List<Entitlement> apmAgentEntitlements,
Map<String, Policy> pluginPolicies,
Function<Class<?>, String> pluginResolver,
Map<String, Path> bundlesDirs,
String apmAgentPackageName,
Module entitlementsModule,
PathLookup pathLookup,
Expand All @@ -172,16 +184,10 @@ public PolicyManager(
.stream()
.collect(toUnmodifiableMap(Map.Entry::getKey, e -> buildScopeEntitlementsMap(e.getValue())));
this.pluginResolver = pluginResolver;
this.bundlesDirs = bundlesDirs;
this.apmAgentPackageName = apmAgentPackageName;
this.entitlementsModule = entitlementsModule;
this.pathLookup = requireNonNull(pathLookup);
this.defaultFileAccess = FileAccessTree.of(
UNKNOWN_COMPONENT_NAME,
UNKNOWN_COMPONENT_NAME,
FilesEntitlement.EMPTY,
pathLookup,
List.of()
);
this.mutedClasses = suppressFailureLogClasses;

List<ExclusiveFileEntitlement> exclusiveFileEntitlements = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,13 @@ public void testFollowLinks() throws IOException {
}

public void testTempDirAccess() {
var tree = FileAccessTree.of("test-component", "test-module", FilesEntitlement.EMPTY, TEST_PATH_LOOKUP, List.of());
var tree = FileAccessTree.of("test-component", "test-module", FilesEntitlement.EMPTY, TEST_PATH_LOOKUP, null, List.of());
assertThat(tree.canRead(TEST_PATH_LOOKUP.tempDir()), is(true));
assertThat(tree.canWrite(TEST_PATH_LOOKUP.tempDir()), is(true));
}

public void testConfigDirAccess() {
var tree = FileAccessTree.of("test-component", "test-module", FilesEntitlement.EMPTY, TEST_PATH_LOOKUP, List.of());
var tree = FileAccessTree.of("test-component", "test-module", FilesEntitlement.EMPTY, TEST_PATH_LOOKUP, null, List.of());
assertThat(tree.canRead(TEST_PATH_LOOKUP.configDir()), is(true));
assertThat(tree.canWrite(TEST_PATH_LOOKUP.configDir()), is(false));
}
Expand Down Expand Up @@ -453,6 +453,7 @@ public void testWindowsAbsolutPathAccess() {
)
),
TEST_PATH_LOOKUP,
null,
List.of()
);

Expand All @@ -464,7 +465,7 @@ public void testWindowsAbsolutPathAccess() {
}

FileAccessTree accessTree(FilesEntitlement entitlement, List<ExclusivePath> exclusivePaths) {
return FileAccessTree.of("test-component", "test-module", entitlement, TEST_PATH_LOOKUP, exclusivePaths);
return FileAccessTree.of("test-component", "test-module", entitlement, TEST_PATH_LOOKUP, null, exclusivePaths);
}

static FilesEntitlement entitlement(String... values) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void testGetEntitlementsThrowsOnMissingPluginUnnamedModule() {
List.of(),
Map.of("plugin1", createPluginPolicy("plugin.module")),
c -> "plugin1",
Map.of("plugin1", Path.of("modules", "plugin1")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -110,6 +111,7 @@ public void testGetEntitlementsThrowsOnMissingPolicyForPlugin() {
List.of(),
Map.of(),
c -> "plugin1",
Map.of("plugin1", Path.of("modules", "plugin1")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -131,6 +133,7 @@ public void testGetEntitlementsFailureIsCached() {
List.of(),
Map.of(),
c -> "plugin1",
Map.of("plugin1", Path.of("modules", "plugin1")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -157,6 +160,7 @@ public void testGetEntitlementsReturnsEntitlementsForPluginUnnamedModule() {
List.of(),
Map.ofEntries(entry("plugin2", createPluginPolicy(ALL_UNNAMED))),
c -> "plugin2",
Map.of("plugin2", Path.of("modules", "plugin2")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -176,6 +180,7 @@ public void testGetEntitlementsThrowsOnMissingPolicyForServer() throws ClassNotF
List.of(),
Map.of(),
c -> null,
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -207,6 +212,7 @@ public void testGetEntitlementsReturnsEntitlementsForServerModule() throws Class
List.of(),
Map.of(),
c -> null,
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -234,6 +240,7 @@ public void testGetEntitlementsReturnsEntitlementsForPluginModule() throws IOExc
List.of(),
Map.of("mock-plugin", createPluginPolicy("org.example.plugin")),
c -> "mock-plugin",
Map.of("mock-plugin", Path.of("modules", "mock-plugin")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -254,6 +261,7 @@ public void testGetEntitlementsResultIsCached() {
List.of(),
Map.ofEntries(entry("plugin2", createPluginPolicy(ALL_UNNAMED))),
c -> "plugin2",
Map.of("plugin2", Path.of("modules", "plugin2")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -314,6 +322,7 @@ public void testAgentsEntitlements() throws IOException, ClassNotFoundException
List.of(new CreateClassLoaderEntitlement()),
Map.of(),
c -> c.getPackageName().startsWith(TEST_AGENTS_PACKAGE_NAME) ? null : "test",
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -343,6 +352,7 @@ public void testDuplicateEntitlements() {
List.of(),
Map.of(),
c -> "test",
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -361,6 +371,7 @@ public void testDuplicateEntitlements() {
List.of(new CreateClassLoaderEntitlement(), new CreateClassLoaderEntitlement()),
Map.of(),
c -> "test",
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -399,6 +410,7 @@ public void testDuplicateEntitlements() {
)
),
c -> "plugin1",
Map.of("plugin1", Path.of("modules", "plugin1")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -451,6 +463,7 @@ public void testFilesEntitlementsWithExclusive() {
)
),
c -> "",
Map.of("plugin1", Path.of("modules", "plugin1"), "plugin2", Path.of("modules", "plugin2")),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand Down Expand Up @@ -497,6 +510,7 @@ public void testFilesEntitlementsWithExclusive() {
)
),
c -> "",
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -523,6 +537,7 @@ public void testPluginResolverOverridesAgents() {
List.of(new CreateClassLoaderEntitlement()),
Map.of(),
c -> "test", // Insist that the class is in a plugin
Map.of(),
TEST_AGENTS_PACKAGE_NAME,
NO_ENTITLEMENTS_MODULE,
TEST_PATH_LOOKUP,
Expand All @@ -545,6 +560,7 @@ private static PolicyManager policyManager(String agentsPackageName, Module enti
List.of(),
Map.of(),
c -> "test",
Map.of(),
agentsPackageName,
entitlementsModule,
TEST_PATH_LOOKUP,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.elasticsearch.nativeaccess.NativeAccess;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeValidationException;
import org.elasticsearch.plugins.PluginBundle;
import org.elasticsearch.plugins.PluginsLoader;
import org.elasticsearch.rest.MethodHandlers;
import org.elasticsearch.transport.RequestHandlerRegistry;
Expand All @@ -70,6 +71,7 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.elasticsearch.bootstrap.BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING;
Expand Down Expand Up @@ -245,6 +247,8 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
pluginsLoader = PluginsLoader.createPluginsLoader(modulesBundles, pluginsBundles, findPluginsWithNativeAccess(pluginPolicies));

var pluginsResolver = PluginsResolver.create(pluginsLoader);
Map<String, Path> bundlesDirs = Stream.concat(modulesBundles.stream(), pluginsBundles.stream())
.collect(Collectors.toUnmodifiableMap(bundle -> bundle.pluginDescriptor().getName(), PluginBundle::getDir));
EntitlementBootstrap.bootstrap(
pluginPolicies,
pluginsResolver::resolveClassToPluginName,
Expand All @@ -254,6 +258,7 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
nodeEnv.configDir(),
nodeEnv.libDir(),
nodeEnv.pluginsDir(),
bundlesDirs,
nodeEnv.logsDir(),
nodeEnv.tmpDir(),
args.pidFile(),
Expand Down