Are these restrictions specific only to the toXContent
method, or do they apply more broadly across other parts of Elasticsearch's core (e.g., serialization, deserialization, API response generation)? I want to make sure I'm adhering to best practices when accessing external resources or customizing output.
As in server module I used IO operations to read some external configuration files and I used createPolicyManager
method of EntitlementInitialization.java
class for it.
Here I am attaching my createPolicyManager
method :
private static PolicyManager createPolicyManager() {
EntitlementBootstrap.BootstrapArgs bootstrapArgs = EntitlementBootstrap.bootstrapArgs();
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
PathLookup pathLookup = bootstrapArgs.pathLookup();
List<Scope> serverScopes = new ArrayList<>();
List<FileData> serverModuleFileDatas = new ArrayList<>();
Collections.addAll(
serverModuleFileDatas,
// Base ES directories
FileData.ofBaseDirPath(PLUGINS, READ),
FileData.ofBaseDirPath(MODULES, READ),
FileData.ofBaseDirPath(CONFIG, READ),
FileData.ofBaseDirPath(LOGS, READ_WRITE),
FileData.ofBaseDirPath(LIB, READ),
FileData.ofBaseDirPath(DATA, READ_WRITE),
FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
// exclusive settings file
FileData.ofRelativePath(Path.of("operator/settings.json"), CONFIG, READ_WRITE).withExclusive(true),
// OS release on Linux
FileData.ofPath(Path.of("/etc/os-release"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/etc/system-release"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/usr/lib/os-release"), READ).withPlatform(LINUX),
// read max virtual memory areas
FileData.ofPath(Path.of("/proc/sys/vm/max_map_count"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/proc/meminfo"), READ).withPlatform(LINUX),
// load averages on Linux
FileData.ofPath(Path.of("/proc/loadavg"), READ).withPlatform(LINUX),
// control group stats on Linux. cgroup v2 stats are in an unpredicable
// location under `/sys/fs/cgroup`, so unfortunately we have to allow
// read access to the entire directory hierarchy.
FileData.ofPath(Path.of("/proc/self/cgroup"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ).withPlatform(LINUX),
// // io stats on Linux
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ).withPlatform(LINUX),
FileData.ofPath(Path.of("/proc/diskstats"), READ).withPlatform(LINUX)
);
if (pathLookup.pidFile() != null) {
serverModuleFileDatas.add(FileData.ofPath(pathLookup.pidFile(), READ_WRITE));
}
// Add custom entitlements for cav.util.SSLUtil in org.elasticsearch.server
serverModuleFileDatas.add(FileData.ofRelativePath(Path.of("config/cert"), CONFIG, READ_WRITE));
String nsWdir = System.getProperty("ns.wdir");
if (nsWdir == null) {
throw new IllegalStateException("System property 'ns.wdir' must be set");
}
Path nosqlConfigPath = Path.of(nsWdir, "webapps/sys/nosqlConfiguration.properties");
serverModuleFileDatas.add(FileData.ofPath(nosqlConfigPath, READ_WRITE));
// Add custom entitlements /etc/version
String esHome = System.getProperty("es.path.home");
Path versionFilePath = Path.of(esHome,"etc/version");
serverModuleFileDatas.add(FileData.ofPath(versionFilePath, READ));
serverScopes.add(new Scope("rest-root", List.of(new FilesEntitlement(List.of(FileData.ofPath(versionFilePath, READ))))));
serverScopes.add(
new Scope(
"ConfigDB",
List.of(
new FilesEntitlement(
List.of(FileData.ofPath(nosqlConfigPath, READ_WRITE))
)
)
)
);
serverScopes.add(
new Scope(
"mongo.java.driver",
List.of(
new ManageThreadsEntitlement(),
new OutboundNetworkEntitlement()
)
)
);
Collections.addAll(
serverScopes,
new Scope(
"org.elasticsearch.base",
List.of(
new CreateClassLoaderEntitlement(),
new FilesEntitlement(
List.of(
// TODO: what in es.base is accessing shared repo?
FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
FileData.ofBaseDirPath(DATA, READ_WRITE)
)
)
)
),
new Scope("org.elasticsearch.xcontent", List.of(new CreateClassLoaderEntitlement())),
new Scope(
"org.elasticsearch.server",
List.of(
new ExitVMEntitlement(),
new ReadStoreAttributesEntitlement(),
new CreateClassLoaderEntitlement(),
new InboundNetworkEntitlement(),
new LoadNativeLibrariesEntitlement(),
new ManageThreadsEntitlement(),
new FilesEntitlement(serverModuleFileDatas)
)
),
new Scope("java.desktop", List.of(new LoadNativeLibrariesEntitlement())),
new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
new Scope(
"org.apache.lucene.core",
List.of(
new LoadNativeLibrariesEntitlement(),
new ManageThreadsEntitlement(),
new FilesEntitlement(List.of(FileData.ofBaseDirPath(CONFIG, READ), FileData.ofBaseDirPath(DATA, READ_WRITE)))
)
),
new Scope("org.apache.lucene.misc", List.of(new FilesEntitlement(List.of(FileData.ofBaseDirPath(DATA, READ_WRITE))))),
new Scope(
"org.apache.logging.log4j.core",
List.of(new ManageThreadsEntitlement(), new FilesEntitlement(List.of(FileData.ofBaseDirPath(LOGS, READ_WRITE))))
),
new Scope(
"org.elasticsearch.nativeaccess",
List.of(new LoadNativeLibrariesEntitlement(), new FilesEntitlement(List.of(FileData.ofBaseDirPath(DATA, READ_WRITE))))
)
);
// conditionally add FIPS entitlements if FIPS only functionality is enforced
if (Booleans.parseBoolean(System.getProperty("org.bouncycastle.fips.approved_only"), false)) {
// if custom trust store is set, grant read access to its location, otherwise use the default JDK trust store
String trustStore = System.getProperty("javax.net.ssl.trustStore");
Path trustStorePath = trustStore != null
? Path.of(trustStore)
: Path.of(System.getProperty("java.home")).resolve("lib/security/jssecacerts");
Collections.addAll(
serverScopes,
new Scope(
"org.bouncycastle.fips.tls",
List.of(
new FilesEntitlement(List.of(FileData.ofPath(trustStorePath, READ))),
new ManageThreadsEntitlement(),
new OutboundNetworkEntitlement()
)
),
new Scope(
"org.bouncycastle.fips.core",
// read to lib dir is required for checksum validation
List.of(new FilesEntitlement(List.of(FileData.ofBaseDirPath(LIB, READ))), new ManageThreadsEntitlement())
)
);
}
var serverPolicy = new Policy(
"server",
bootstrapArgs.serverPolicyPatch() == null
? serverScopes
: PolicyUtils.mergeScopes(serverScopes, bootstrapArgs.serverPolicyPatch().scopes())
);
// agents run without a module, so this is a special hack for the apm agent
// this should be removed once https://github.com/elastic/elasticsearch/issues/109335 is completed
// See also modules/apm/src/main/plugin-metadata/entitlement-policy.yaml
List<Entitlement> agentEntitlements = List.of(
new CreateClassLoaderEntitlement(),
new ManageThreadsEntitlement(),
new SetHttpsConnectionPropertiesEntitlement(),
new OutboundNetworkEntitlement(),
new WriteSystemPropertiesEntitlement(Set.of("AsyncProfiler.safemode")),
new LoadNativeLibrariesEntitlement(),
new FilesEntitlement(
List.of(
FileData.ofBaseDirPath(LOGS, READ_WRITE),
FileData.ofPath(Path.of("/proc/meminfo"), READ),
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ)
)
)
);
validateFilesEntitlements(pluginPolicies, pathLookup);
return new PolicyManager(
serverPolicy,
agentEntitlements,
pluginPolicies,
EntitlementBootstrap.bootstrapArgs().scopeResolver(),
EntitlementBootstrap.bootstrapArgs().sourcePaths(),
ENTITLEMENTS_MODULE,
pathLookup,
bootstrapArgs.suppressFailureLogClasses()
);
}