Merge pull request #10844 from rmuir/sm_cleanup
Security manager cleanups
This commit is contained in:
commit
10f2e0e2ba
|
@ -59,7 +59,6 @@ public class Bootstrap {
|
|||
private static Bootstrap bootstrap;
|
||||
|
||||
private void setup(boolean addShutdownHook, Settings settings, Environment environment) throws Exception {
|
||||
setupSecurity(settings, environment);
|
||||
if (settings.getAsBoolean("bootstrap.mlockall", false)) {
|
||||
Natives.tryMlockall();
|
||||
}
|
||||
|
@ -90,6 +89,8 @@ public class Bootstrap {
|
|||
}
|
||||
});
|
||||
}
|
||||
// install SM after natives, JNA can require strange permissions
|
||||
setupSecurity(settings, environment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,8 +29,6 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Initializes securitymanager with necessary permissions.
|
||||
|
@ -68,55 +66,42 @@ class Security {
|
|||
try (InputStream in = new BufferedInputStream(template)) {
|
||||
ByteStreams.copy(in, output);
|
||||
}
|
||||
|
||||
// add permissions for all configured paths.
|
||||
Set<Path> paths = new HashSet<>();
|
||||
paths.add(environment.homeFile());
|
||||
paths.add(environment.configFile());
|
||||
paths.add(environment.logsFile());
|
||||
paths.add(environment.pluginsFile());
|
||||
for (Path path : environment.dataFiles()) {
|
||||
paths.add(path);
|
||||
|
||||
// all policy files are UTF-8:
|
||||
// https://docs.oracle.com/javase/7/docs/technotes/guides/security/PolicyFiles.html
|
||||
try (Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
|
||||
writer.write(System.lineSeparator());
|
||||
writer.write("grant {");
|
||||
writer.write(System.lineSeparator());
|
||||
|
||||
// add permissions for all configured paths.
|
||||
// TODO: improve test infra so we can reduce permissions where read/write
|
||||
// is not really needed...
|
||||
addPath(writer, environment.homeFile(), "read,readlink,write,delete");
|
||||
addPath(writer, environment.configFile(), "read,readlink,write,delete");
|
||||
addPath(writer, environment.logsFile(), "read,readlink,write,delete");
|
||||
addPath(writer, environment.pluginsFile(), "read,readlink,write,delete");
|
||||
for (Path path : environment.dataFiles()) {
|
||||
addPath(writer, path, "read,readlink,write,delete");
|
||||
}
|
||||
for (Path path : environment.dataWithClusterFiles()) {
|
||||
addPath(writer, path, "read,readlink,write,delete");
|
||||
}
|
||||
|
||||
writer.write("};");
|
||||
writer.write(System.lineSeparator());
|
||||
}
|
||||
for (Path path : environment.dataWithClusterFiles()) {
|
||||
paths.add(path);
|
||||
}
|
||||
output.write(createPermissions(paths));
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
// package private for testing
|
||||
static byte[] createPermissions(Set<Path> paths) throws IOException {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
|
||||
// all policy files are UTF-8:
|
||||
// https://docs.oracle.com/javase/7/docs/technotes/guides/security/PolicyFiles.html
|
||||
try (Writer writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) {
|
||||
writer.write(System.lineSeparator());
|
||||
writer.write("grant {");
|
||||
writer.write(System.lineSeparator());
|
||||
for (Path path : paths) {
|
||||
// data paths actually may not exist yet.
|
||||
Files.createDirectories(path);
|
||||
// add each path twice: once for itself, again for files underneath it
|
||||
addPath(writer, encode(path), "read,readlink,write,delete");
|
||||
addRecursivePath(writer, encode(path), "read,readlink,write,delete");
|
||||
}
|
||||
writer.write("};");
|
||||
writer.write(System.lineSeparator());
|
||||
}
|
||||
|
||||
return stream.toByteArray();
|
||||
}
|
||||
|
||||
static void addPath(Writer writer, String path, String permissions) throws IOException {
|
||||
writer.write("permission java.io.FilePermission \"" + path + "\", \"" + permissions + "\";");
|
||||
static void addPath(Writer writer, Path path, String permissions) throws IOException {
|
||||
// paths may not exist yet
|
||||
Files.createDirectories(path);
|
||||
// add each path twice: once for itself, again for files underneath it
|
||||
writer.write("permission java.io.FilePermission \"" + encode(path) + "\", \"" + permissions + "\";");
|
||||
writer.write(System.lineSeparator());
|
||||
}
|
||||
|
||||
static void addRecursivePath(Writer writer, String path, String permissions) throws IOException {
|
||||
writer.write("permission java.io.FilePermission \"" + path + "${/}-\", \"" + permissions + "\";");
|
||||
writer.write("permission java.io.FilePermission \"" + encode(path) + "${/}-\", \"" + permissions + "\";");
|
||||
writer.write(System.lineSeparator());
|
||||
}
|
||||
|
||||
|
@ -124,10 +109,6 @@ class Security {
|
|||
// See "Note Regarding File Path Specifications on Windows Systems".
|
||||
// https://docs.oracle.com/javase/7/docs/technotes/guides/security/PolicyFiles.html
|
||||
static String encode(Path path) {
|
||||
return encode(path.toString());
|
||||
}
|
||||
|
||||
static String encode(String path) {
|
||||
return path.replace("\\", "\\\\");
|
||||
return path.toString().replace("\\", "\\\\");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,9 +37,6 @@ grant {
|
|||
permission java.io.FilePermission "${project.basedir}${/}lib/sigar{/}-", "read";
|
||||
// mvn custom ./m2/repository for dependency jars
|
||||
permission java.io.FilePermission "${m2.repository}${/}-", "read";
|
||||
// per-jvm directory
|
||||
permission java.io.FilePermission "${junit4.childvm.cwd}${/}temp", "read,write";
|
||||
permission java.io.FilePermission "${junit4.childvm.cwd}${/}temp${/}-", "read,write,delete";
|
||||
|
||||
permission java.nio.file.LinkPermission "symbolic";
|
||||
permission groovy.security.GroovyCodeSourcePermission "/groovy/script";
|
||||
|
@ -86,7 +83,10 @@ grant {
|
|||
|
||||
// needed for natives calls
|
||||
permission java.lang.RuntimePermission "loadLibrary.*";
|
||||
|
||||
// needed for testing access rules etc
|
||||
permission java.lang.RuntimePermission "createSecurityManager";
|
||||
permission java.security.SecurityPermission "createPolicy.JavaPolicy";
|
||||
|
||||
// reflection hacks:
|
||||
// needed for Striped64 (what is this doing), also enables unmap hack
|
||||
|
|
|
@ -19,30 +19,77 @@
|
|||
|
||||
package org.elasticsearch.bootstrap;
|
||||
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilePermission;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.URIParameter;
|
||||
|
||||
public class SecurityTests extends ElasticsearchTestCase {
|
||||
|
||||
/** backslash escaping (e.g. windows paths) */
|
||||
public void testEncode() {
|
||||
assertEquals("c:\\\\foobar", Security.encode("c:\\foobar"));
|
||||
}
|
||||
|
||||
/** test template processing */
|
||||
public void testTemplateProcessing() throws Exception {
|
||||
/** test generated permissions */
|
||||
public void testGeneratedPermissions() throws Exception {
|
||||
Path path = createTempDir();
|
||||
|
||||
byte results[] = Security.createPermissions(Collections.singleton(path));
|
||||
String unicode = new String(results, StandardCharsets.UTF_8);
|
||||
// try not to make this test too fragile or useless
|
||||
assertTrue(unicode.contains("grant {"));
|
||||
assertTrue(unicode.contains(Security.encode(path)));
|
||||
assertTrue(unicode.contains("read"));
|
||||
assertTrue(unicode.contains("write"));
|
||||
// make a fake ES home and ensure we only grant permissions to that.
|
||||
Path esHome = path.resolve("esHome");
|
||||
ImmutableSettings.Builder settingsBuilder = ImmutableSettings.builder();
|
||||
settingsBuilder.put("path.home", esHome.toString());
|
||||
Settings settings = settingsBuilder.build();
|
||||
|
||||
Environment environment = new Environment(settings);
|
||||
Path policyFile = Security.processTemplate(new ByteArrayInputStream(new byte[0]), environment);
|
||||
|
||||
ProtectionDomain domain = getClass().getProtectionDomain();
|
||||
Policy policy = Policy.getInstance("JavaPolicy", new URIParameter(policyFile.toUri()));
|
||||
// the fake es home
|
||||
assertTrue(policy.implies(domain, new FilePermission(esHome.toString(), "read")));
|
||||
// its parent
|
||||
assertFalse(policy.implies(domain, new FilePermission(path.toString(), "read")));
|
||||
// some other sibling
|
||||
assertFalse(policy.implies(domain, new FilePermission(path.resolve("other").toString(), "read")));
|
||||
}
|
||||
|
||||
/** test generated permissions for all configured paths */
|
||||
public void testEnvironmentPaths() throws Exception {
|
||||
Path path = createTempDir();
|
||||
|
||||
ImmutableSettings.Builder settingsBuilder = ImmutableSettings.builder();
|
||||
settingsBuilder.put("path.home", path.resolve("home").toString());
|
||||
settingsBuilder.put("path.conf", path.resolve("conf").toString());
|
||||
settingsBuilder.put("path.plugins", path.resolve("plugins").toString());
|
||||
settingsBuilder.putArray("path.data", path.resolve("data1").toString(), path.resolve("data2").toString());
|
||||
settingsBuilder.put("path.logs", path.resolve("logs").toString());
|
||||
Settings settings = settingsBuilder.build();
|
||||
|
||||
Environment environment = new Environment(settings);
|
||||
Path policyFile = Security.processTemplate(new ByteArrayInputStream(new byte[0]), environment);
|
||||
|
||||
ProtectionDomain domain = getClass().getProtectionDomain();
|
||||
Policy policy = Policy.getInstance("JavaPolicy", new URIParameter(policyFile.toUri()));
|
||||
|
||||
// check that all directories got permissions:
|
||||
// homefile: this is needed unless we break out rules for "lib" dir.
|
||||
// TODO: make read-only
|
||||
assertTrue(policy.implies(domain, new FilePermission(environment.homeFile().toString(), "read,readlink,write,delete")));
|
||||
// config file
|
||||
// TODO: make read-only
|
||||
assertTrue(policy.implies(domain, new FilePermission(environment.configFile().toString(), "read,readlink,write,delete")));
|
||||
// plugins: r/w, TODO: can this be minimized?
|
||||
assertTrue(policy.implies(domain, new FilePermission(environment.pluginsFile().toString(), "read,readlink,write,delete")));
|
||||
// data paths: r/w
|
||||
for (Path dataPath : environment.dataFiles()) {
|
||||
assertTrue(policy.implies(domain, new FilePermission(dataPath.toString(), "read,readlink,write,delete")));
|
||||
}
|
||||
for (Path dataPath : environment.dataWithClusterFiles()) {
|
||||
assertTrue(policy.implies(domain, new FilePermission(dataPath.toString(), "read,readlink,write,delete")));
|
||||
}
|
||||
// logs: r/w
|
||||
assertTrue(policy.implies(domain, new FilePermission(environment.logsFile().toString(), "read,readlink,write,delete")));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue