enable securitymanager
This commit is contained in:
parent
b7ab378996
commit
270cb9f349
|
@ -231,6 +231,15 @@
|
|||
#
|
||||
#http.enabled: false
|
||||
|
||||
################################### Security ##################################
|
||||
|
||||
# SecurityManager runs elasticsearch with a lower set of priviledges.
|
||||
# For more information, see
|
||||
# <https://docs.oracle.com/javase/tutorial/essential/environment/security.html>.
|
||||
|
||||
# Disable security completely:
|
||||
#
|
||||
# security.enabled: false
|
||||
|
||||
################################### Gateway ###################################
|
||||
|
||||
|
|
|
@ -17,21 +17,26 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
// Policy file to prevent tests from writing outside the test sandbox directory
|
||||
// PLEASE NOTE: You may need to enable other permissions when new tests are added,
|
||||
// everything not allowed here is forbidden!
|
||||
// Default security policy file.
|
||||
// On startup, BootStrap reads environment and adds additional permissions
|
||||
// for configured paths to these.
|
||||
|
||||
grant {
|
||||
|
||||
// contain read access to only what we need:
|
||||
// system jar resources
|
||||
permission java.io.FilePermission "${java.home}${/}-", "read";
|
||||
|
||||
// temporary files
|
||||
permission java.io.FilePermission "${java.io.tmpdir}", "read,write";
|
||||
permission java.io.FilePermission "${java.io.tmpdir}${/}-", "read,write,delete";
|
||||
|
||||
// paths used for running tests
|
||||
// project base directory
|
||||
permission java.io.FilePermission "${project.basedir}${/}target${/}-", "read";
|
||||
// read permission for lib sigar
|
||||
permission java.io.FilePermission "${project.basedir}${/}lib/sigar{/}-", "read";
|
||||
// mvn custom ./m2/repository for dependency jars
|
||||
permission java.io.FilePermission "${m2.repository}${/}-", "read";
|
||||
// system jar resources
|
||||
permission java.io.FilePermission "${java.home}${/}-", "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";
|
2
pom.xml
2
pom.xml
|
@ -628,7 +628,7 @@
|
|||
<tests.compatibility>${tests.compatibility}</tests.compatibility>
|
||||
<java.awt.headless>true</java.awt.headless>
|
||||
<!-- security manager / test.policy -->
|
||||
<java.security.policy>${basedir}/dev-tools/tests.policy</java.security.policy>
|
||||
<java.security.policy>${basedir}/config/security.policy</java.security.policy>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.elasticsearch.common.SuppressForbidden;
|
|||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.inject.CreationException;
|
||||
import org.elasticsearch.common.inject.spi.Message;
|
||||
import org.elasticsearch.common.io.FileSystemUtils;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.jna.Natives;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
|
@ -40,7 +39,6 @@ import org.elasticsearch.node.Node;
|
|||
import org.elasticsearch.node.NodeBuilder;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -61,6 +59,7 @@ public class Bootstrap {
|
|||
private static Bootstrap bootstrap;
|
||||
|
||||
private void setup(boolean addShutdownHook, Tuple<Settings, Environment> tuple) throws Exception {
|
||||
setupSecurity(tuple.v1(), tuple.v2());
|
||||
if (tuple.v1().getAsBoolean("bootstrap.mlockall", false)) {
|
||||
Natives.tryMlockall();
|
||||
}
|
||||
|
@ -92,6 +91,16 @@ public class Bootstrap {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSecurity(Settings settings, Environment environment) throws Exception {
|
||||
ESLogger logger = Loggers.getLogger(Bootstrap.class);
|
||||
if (settings.getAsBoolean("security.enabled", true)) {
|
||||
Security.configure(environment);
|
||||
logger.info("security enabled");
|
||||
} else {
|
||||
logger.info("security disabled");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "Exception#printStackTrace()")
|
||||
private static void setupLogging(Tuple<Settings, Environment> tuple) {
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.bootstrap;
|
||||
|
||||
import org.apache.lucene.util.Constants;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.env.NodeEnvironment;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Initializes securitymanager with necessary permissions.
|
||||
* <p>
|
||||
* We use a template file (the one we test with), and add additional
|
||||
* permissions based on the environment (data paths, etc)
|
||||
*/
|
||||
class Security {
|
||||
|
||||
/**
|
||||
* Initializes securitymanager for the environment
|
||||
* Can only happen once!
|
||||
*/
|
||||
static void configure(Environment environment) throws IOException {
|
||||
Path newConfig = processTemplate(environment.configFile().resolve("security.policy"), environment);
|
||||
System.setProperty("java.security.policy", newConfig.toString());
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
try {
|
||||
Files.delete(newConfig);
|
||||
} catch (Exception e) {
|
||||
Loggers.getLogger(Security.class).warn("unable to remove temporary file: " + newConfig, e);
|
||||
}
|
||||
}
|
||||
|
||||
// package-private for testing
|
||||
static Path processTemplate(Path template, Environment environment) throws IOException {
|
||||
Path processed = Files.createTempFile(null, null);
|
||||
try (OutputStream output = new BufferedOutputStream(Files.newOutputStream(processed))) {
|
||||
// copy the template as-is.
|
||||
Files.copy(template, 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());
|
||||
paths.add(environment.workFile());
|
||||
paths.add(environment.workWithClusterFile());
|
||||
for (Path path : environment.dataFiles()) {
|
||||
paths.add(path);
|
||||
}
|
||||
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) {
|
||||
// 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");
|
||||
}
|
||||
|
||||
// on *nix, try to grant read perms to file stores / SSD detection
|
||||
if (!Constants.WINDOWS) {
|
||||
Set<String> stores = new HashSet<>();
|
||||
for (FileStore store : PathUtils.getDefaultFileSystem().getFileStores()) {
|
||||
try {
|
||||
String mount = NodeEnvironment.getMountPoint(store);
|
||||
// mount point for fstat() calls against it
|
||||
if (mount.startsWith("/")) {
|
||||
stores.add(mount);
|
||||
}
|
||||
// block device: add it for SSD detection
|
||||
if (store.name().startsWith("/")) {
|
||||
stores.add(store.name());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// these are hacks that are not guaranteed
|
||||
}
|
||||
}
|
||||
for (String store : stores) {
|
||||
addPath(writer, encode(store), "read,readlink");
|
||||
}
|
||||
addRecursivePath(writer, "/sys/block", "read,readlink");
|
||||
addRecursivePath(writer, "/sys/devices", "read,readlink");
|
||||
addRecursivePath(writer, "/dev", "read,readlink");
|
||||
addRecursivePath(writer, "/devices", "read,readlink");
|
||||
}
|
||||
|
||||
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 + "\";");
|
||||
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(System.lineSeparator());
|
||||
}
|
||||
|
||||
// Any backslashes in paths must be escaped, because it is the escape character when parsing.
|
||||
// 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("\\", "\\\\");
|
||||
}
|
||||
}
|
|
@ -295,7 +295,7 @@ public class NodeEnvironment extends AbstractComponent implements Closeable {
|
|||
// NOTE: poached from Lucene's IOUtils:
|
||||
|
||||
/** Files.getFileStore(Path) useless here! Don't complain, just try it yourself. */
|
||||
private static FileStore getFileStore(Path path) throws IOException {
|
||||
public static FileStore getFileStore(Path path) throws IOException {
|
||||
FileStore store = Files.getFileStore(path);
|
||||
|
||||
try {
|
||||
|
@ -317,7 +317,7 @@ public class NodeEnvironment extends AbstractComponent implements Closeable {
|
|||
// NOTE: poached from Lucene's IOUtils:
|
||||
|
||||
// these are hacks that are not guaranteed
|
||||
private static String getMountPoint(FileStore store) {
|
||||
public static String getMountPoint(FileStore store) {
|
||||
String desc = store.toString();
|
||||
return desc.substring(0, desc.lastIndexOf('(') - 1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue