Skip to content

Commit ee01010

Browse files
committed
Extract hardcoded entitlements creation to a separate class (elastic#127698)
Moving creation of hardcoded entitlements (server policy + APM agent) to a separate class
1 parent b9d08bd commit ee01010

File tree

2 files changed

+213
-241
lines changed

2 files changed

+213
-241
lines changed

libs/entitlement/src/main/java/org/elasticsearch/entitlement/initialization/EntitlementInitialization.java

Lines changed: 3 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -10,51 +10,19 @@
1010
package org.elasticsearch.entitlement.initialization;
1111

1212
import org.elasticsearch.core.Booleans;
13-
import org.elasticsearch.core.Strings;
1413
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
1514
import org.elasticsearch.entitlement.bridge.EntitlementChecker;
1615
import org.elasticsearch.entitlement.runtime.api.ElasticsearchEntitlementChecker;
17-
import org.elasticsearch.entitlement.runtime.policy.FileAccessTree;
1816
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
1917
import org.elasticsearch.entitlement.runtime.policy.Policy;
2018
import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
21-
import org.elasticsearch.entitlement.runtime.policy.PolicyUtils;
22-
import org.elasticsearch.entitlement.runtime.policy.Scope;
23-
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
24-
import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
25-
import org.elasticsearch.entitlement.runtime.policy.entitlements.ExitVMEntitlement;
26-
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
27-
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.FileData;
28-
import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkEntitlement;
29-
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
30-
import org.elasticsearch.entitlement.runtime.policy.entitlements.ManageThreadsEntitlement;
31-
import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
32-
import org.elasticsearch.entitlement.runtime.policy.entitlements.ReadStoreAttributesEntitlement;
33-
import org.elasticsearch.entitlement.runtime.policy.entitlements.SetHttpsConnectionPropertiesEntitlement;
34-
import org.elasticsearch.entitlement.runtime.policy.entitlements.WriteSystemPropertiesEntitlement;
3519

3620
import java.lang.instrument.Instrumentation;
3721
import java.lang.reflect.Constructor;
3822
import java.lang.reflect.InvocationTargetException;
39-
import java.nio.file.Path;
40-
import java.util.ArrayList;
41-
import java.util.Collections;
42-
import java.util.HashSet;
43-
import java.util.List;
4423
import java.util.Map;
4524
import java.util.Set;
4625

47-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
48-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.DATA;
49-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LIB;
50-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LOGS;
51-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.MODULES;
52-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.PLUGINS;
53-
import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.SHARED_REPO;
54-
import static org.elasticsearch.entitlement.runtime.policy.Platform.LINUX;
55-
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ;
56-
import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE;
57-
5826
/**
5927
* Called by the agent during {@code agentmain} to configure the entitlement system,
6028
* instantiate and configure an {@link EntitlementChecker},
@@ -108,149 +76,11 @@ private static PolicyManager createPolicyManager() {
10876
Map<String, Policy> pluginPolicies = bootstrapArgs.pluginPolicies();
10977
PathLookup pathLookup = bootstrapArgs.pathLookup();
11078

111-
List<Scope> serverScopes = new ArrayList<>();
112-
List<FileData> serverModuleFileDatas = new ArrayList<>();
113-
Collections.addAll(
114-
serverModuleFileDatas,
115-
// Base ES directories
116-
FileData.ofBaseDirPath(PLUGINS, READ),
117-
FileData.ofBaseDirPath(MODULES, READ),
118-
FileData.ofBaseDirPath(CONFIG, READ),
119-
FileData.ofBaseDirPath(LOGS, READ_WRITE),
120-
FileData.ofBaseDirPath(LIB, READ),
121-
FileData.ofBaseDirPath(DATA, READ_WRITE),
122-
FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
123-
// exclusive settings file
124-
FileData.ofRelativePath(Path.of("operator/settings.json"), CONFIG, READ_WRITE).withExclusive(true),
125-
126-
// OS release on Linux
127-
FileData.ofPath(Path.of("/etc/os-release"), READ).withPlatform(LINUX),
128-
FileData.ofPath(Path.of("/etc/system-release"), READ).withPlatform(LINUX),
129-
FileData.ofPath(Path.of("/usr/lib/os-release"), READ).withPlatform(LINUX),
130-
// read max virtual memory areas
131-
FileData.ofPath(Path.of("/proc/sys/vm/max_map_count"), READ).withPlatform(LINUX),
132-
FileData.ofPath(Path.of("/proc/meminfo"), READ).withPlatform(LINUX),
133-
// load averages on Linux
134-
FileData.ofPath(Path.of("/proc/loadavg"), READ).withPlatform(LINUX),
135-
// control group stats on Linux. cgroup v2 stats are in an unpredicable
136-
// location under `/sys/fs/cgroup`, so unfortunately we have to allow
137-
// read access to the entire directory hierarchy.
138-
FileData.ofPath(Path.of("/proc/self/cgroup"), READ).withPlatform(LINUX),
139-
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ).withPlatform(LINUX),
140-
// // io stats on Linux
141-
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ).withPlatform(LINUX),
142-
FileData.ofPath(Path.of("/proc/diskstats"), READ).withPlatform(LINUX)
143-
);
144-
if (pathLookup.pidFile() != null) {
145-
serverModuleFileDatas.add(FileData.ofPath(pathLookup.pidFile(), READ_WRITE));
146-
}
147-
148-
Collections.addAll(
149-
serverScopes,
150-
new Scope(
151-
"org.elasticsearch.base",
152-
List.of(
153-
new CreateClassLoaderEntitlement(),
154-
new FilesEntitlement(
155-
List.of(
156-
// TODO: what in es.base is accessing shared repo?
157-
FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
158-
FileData.ofBaseDirPath(DATA, READ_WRITE)
159-
)
160-
)
161-
)
162-
),
163-
new Scope("org.elasticsearch.xcontent", List.of(new CreateClassLoaderEntitlement())),
164-
new Scope(
165-
"org.elasticsearch.server",
166-
List.of(
167-
new ExitVMEntitlement(),
168-
new ReadStoreAttributesEntitlement(),
169-
new CreateClassLoaderEntitlement(),
170-
new InboundNetworkEntitlement(),
171-
new LoadNativeLibrariesEntitlement(),
172-
new ManageThreadsEntitlement(),
173-
new FilesEntitlement(serverModuleFileDatas)
174-
)
175-
),
176-
new Scope("java.desktop", List.of(new LoadNativeLibrariesEntitlement())),
177-
new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
178-
new Scope(
179-
"org.apache.lucene.core",
180-
List.of(
181-
new LoadNativeLibrariesEntitlement(),
182-
new ManageThreadsEntitlement(),
183-
new FilesEntitlement(List.of(FileData.ofBaseDirPath(CONFIG, READ), FileData.ofBaseDirPath(DATA, READ_WRITE)))
184-
)
185-
),
186-
new Scope("org.apache.lucene.misc", List.of(new FilesEntitlement(List.of(FileData.ofBaseDirPath(DATA, READ_WRITE))))),
187-
new Scope(
188-
"org.apache.logging.log4j.core",
189-
List.of(new ManageThreadsEntitlement(), new FilesEntitlement(List.of(FileData.ofBaseDirPath(LOGS, READ_WRITE))))
190-
),
191-
new Scope(
192-
"org.elasticsearch.nativeaccess",
193-
List.of(new LoadNativeLibrariesEntitlement(), new FilesEntitlement(List.of(FileData.ofBaseDirPath(DATA, READ_WRITE))))
194-
)
195-
);
196-
197-
// conditionally add FIPS entitlements if FIPS only functionality is enforced
198-
if (Booleans.parseBoolean(System.getProperty("org.bouncycastle.fips.approved_only"), false)) {
199-
// if custom trust store is set, grant read access to its location, otherwise use the default JDK trust store
200-
String trustStore = System.getProperty("javax.net.ssl.trustStore");
201-
Path trustStorePath = trustStore != null
202-
? Path.of(trustStore)
203-
: Path.of(System.getProperty("java.home")).resolve("lib/security/jssecacerts");
204-
205-
Collections.addAll(
206-
serverScopes,
207-
new Scope(
208-
"org.bouncycastle.fips.tls",
209-
List.of(
210-
new FilesEntitlement(List.of(FileData.ofPath(trustStorePath, READ))),
211-
new ManageThreadsEntitlement(),
212-
new OutboundNetworkEntitlement()
213-
)
214-
),
215-
new Scope(
216-
"org.bouncycastle.fips.core",
217-
// read to lib dir is required for checksum validation
218-
List.of(new FilesEntitlement(List.of(FileData.ofBaseDirPath(LIB, READ))), new ManageThreadsEntitlement())
219-
)
220-
);
221-
}
222-
223-
var serverPolicy = new Policy(
224-
"server",
225-
bootstrapArgs.serverPolicyPatch() == null
226-
? serverScopes
227-
: PolicyUtils.mergeScopes(serverScopes, bootstrapArgs.serverPolicyPatch().scopes())
228-
);
229-
230-
// agents run without a module, so this is a special hack for the apm agent
231-
// this should be removed once https://github.com/elastic/elasticsearch/issues/109335 is completed
232-
// See also modules/apm/src/main/plugin-metadata/entitlement-policy.yaml
233-
List<Entitlement> agentEntitlements = List.of(
234-
new CreateClassLoaderEntitlement(),
235-
new ManageThreadsEntitlement(),
236-
new SetHttpsConnectionPropertiesEntitlement(),
237-
new OutboundNetworkEntitlement(),
238-
new WriteSystemPropertiesEntitlement(Set.of("AsyncProfiler.safemode")),
239-
new LoadNativeLibrariesEntitlement(),
240-
new FilesEntitlement(
241-
List.of(
242-
FileData.ofBaseDirPath(LOGS, READ_WRITE),
243-
FileData.ofPath(Path.of("/proc/meminfo"), READ),
244-
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ)
245-
)
246-
)
247-
);
248-
249-
validateFilesEntitlements(pluginPolicies, pathLookup);
79+
FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);
25080

25181
return new PolicyManager(
252-
serverPolicy,
253-
agentEntitlements,
82+
HardcodedEntitlements.serverPolicy(pathLookup.pidFile(), bootstrapArgs.serverPolicyPatch()),
83+
HardcodedEntitlements.agentEntitlements(),
25484
pluginPolicies,
25585
EntitlementBootstrap.bootstrapArgs().scopeResolver(),
25686
EntitlementBootstrap.bootstrapArgs().sourcePaths(),
@@ -260,74 +90,6 @@ private static PolicyManager createPolicyManager() {
26090
);
26191
}
26292

263-
// package visible for tests
264-
static void validateFilesEntitlements(Map<String, Policy> pluginPolicies, PathLookup pathLookup) {
265-
Set<Path> readAccessForbidden = new HashSet<>();
266-
pathLookup.getBaseDirPaths(PLUGINS).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
267-
pathLookup.getBaseDirPaths(MODULES).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
268-
pathLookup.getBaseDirPaths(LIB).forEach(p -> readAccessForbidden.add(p.toAbsolutePath().normalize()));
269-
Set<Path> writeAccessForbidden = new HashSet<>();
270-
pathLookup.getBaseDirPaths(CONFIG).forEach(p -> writeAccessForbidden.add(p.toAbsolutePath().normalize()));
271-
for (var pluginPolicy : pluginPolicies.entrySet()) {
272-
for (var scope : pluginPolicy.getValue().scopes()) {
273-
var filesEntitlement = scope.entitlements()
274-
.stream()
275-
.filter(x -> x instanceof FilesEntitlement)
276-
.map(x -> ((FilesEntitlement) x))
277-
.findFirst();
278-
if (filesEntitlement.isPresent()) {
279-
var fileAccessTree = FileAccessTree.withoutExclusivePaths(filesEntitlement.get(), pathLookup, null);
280-
validateReadFilesEntitlements(pluginPolicy.getKey(), scope.moduleName(), fileAccessTree, readAccessForbidden);
281-
validateWriteFilesEntitlements(pluginPolicy.getKey(), scope.moduleName(), fileAccessTree, writeAccessForbidden);
282-
}
283-
}
284-
}
285-
}
286-
287-
private static IllegalArgumentException buildValidationException(
288-
String componentName,
289-
String moduleName,
290-
Path forbiddenPath,
291-
FilesEntitlement.Mode mode
292-
) {
293-
return new IllegalArgumentException(
294-
Strings.format(
295-
"policy for module [%s] in [%s] has an invalid file entitlement. Any path under [%s] is forbidden for mode [%s].",
296-
moduleName,
297-
componentName,
298-
forbiddenPath,
299-
mode
300-
)
301-
);
302-
}
303-
304-
private static void validateReadFilesEntitlements(
305-
String componentName,
306-
String moduleName,
307-
FileAccessTree fileAccessTree,
308-
Set<Path> readForbiddenPaths
309-
) {
310-
311-
for (Path forbiddenPath : readForbiddenPaths) {
312-
if (fileAccessTree.canRead(forbiddenPath)) {
313-
throw buildValidationException(componentName, moduleName, forbiddenPath, READ);
314-
}
315-
}
316-
}
317-
318-
private static void validateWriteFilesEntitlements(
319-
String componentName,
320-
String moduleName,
321-
FileAccessTree fileAccessTree,
322-
Set<Path> writeForbiddenPaths
323-
) {
324-
for (Path forbiddenPath : writeForbiddenPaths) {
325-
if (fileAccessTree.canWrite(forbiddenPath)) {
326-
throw buildValidationException(componentName, moduleName, forbiddenPath, READ_WRITE);
327-
}
328-
}
329-
}
330-
33193
/**
33294
* If bytecode verification is enabled, ensure these classes get loaded before transforming/retransforming them.
33395
* For these classes, the order in which we transform and verify them matters. Verification during class transformation is at least an

0 commit comments

Comments
 (0)