diff --git a/core/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java b/core/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java index 1781744c090f..43af643854e5 100644 --- a/core/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java +++ b/core/src/main/java/org/elasticsearch/plugins/InstallPluginCommand.java @@ -142,29 +142,31 @@ class InstallPluginCommand extends SettingCommand { private final OptionSpec batchOption; private final OptionSpec arguments; - - static final Set DIR_AND_EXECUTABLE_PERMS; - static final Set FILE_PERMS; + static final Set BIN_DIR_PERMS; + static final Set BIN_FILES_PERMS; + static final Set CONFIG_DIR_PERMS; + static final Set CONFIG_FILES_PERMS; + static final Set PLUGIN_DIR_PERMS; + static final Set PLUGIN_FILES_PERMS; static { - Set dirAndExecutablePerms = new HashSet<>(7); - // Directories and executables get chmod 755 - dirAndExecutablePerms.add(PosixFilePermission.OWNER_EXECUTE); - dirAndExecutablePerms.add(PosixFilePermission.OWNER_READ); - dirAndExecutablePerms.add(PosixFilePermission.OWNER_WRITE); - dirAndExecutablePerms.add(PosixFilePermission.GROUP_EXECUTE); - dirAndExecutablePerms.add(PosixFilePermission.GROUP_READ); - dirAndExecutablePerms.add(PosixFilePermission.OTHERS_READ); - dirAndExecutablePerms.add(PosixFilePermission.OTHERS_EXECUTE); - DIR_AND_EXECUTABLE_PERMS = Collections.unmodifiableSet(dirAndExecutablePerms); + // Bin directory get chmod 755 + BIN_DIR_PERMS = Collections.unmodifiableSet(PosixFilePermissions.fromString("rwxr-xr-x")); - Set filePerms = new HashSet<>(4); - // Files get chmod 644 - filePerms.add(PosixFilePermission.OWNER_READ); - filePerms.add(PosixFilePermission.OWNER_WRITE); - filePerms.add(PosixFilePermission.GROUP_READ); - filePerms.add(PosixFilePermission.OTHERS_READ); - FILE_PERMS = Collections.unmodifiableSet(filePerms); + // Bin files also get chmod 755 + BIN_FILES_PERMS = BIN_DIR_PERMS; + + // Config directory get chmod 750 + CONFIG_DIR_PERMS = Collections.unmodifiableSet(PosixFilePermissions.fromString("rwxr-x---")); + + // Config files get chmod 660 + CONFIG_FILES_PERMS = Collections.unmodifiableSet(PosixFilePermissions.fromString("rw-rw----")); + + // Plugin directory get chmod 755 + PLUGIN_DIR_PERMS = BIN_DIR_PERMS; + + // Plugins files get chmod 644 + PLUGIN_FILES_PERMS = Collections.unmodifiableSet(PosixFilePermissions.fromString("rw-r--r--")); } InstallPluginCommand() { @@ -387,7 +389,7 @@ class InstallPluginCommand extends SettingCommand { private Path stagingDirectory(Path pluginsDir) throws IOException { try { - return Files.createTempDirectory(pluginsDir, ".installing-", PosixFilePermissions.asFileAttribute(DIR_AND_EXECUTABLE_PERMS)); + return Files.createTempDirectory(pluginsDir, ".installing-", PosixFilePermissions.asFileAttribute(PLUGIN_DIR_PERMS)); } catch (IllegalArgumentException e) { // Jimfs throws an IAE where it should throw an UOE // remove when google/jimfs#30 is integrated into Jimfs @@ -494,9 +496,9 @@ class InstallPluginCommand extends SettingCommand { try (DirectoryStream stream = Files.newDirectoryStream(destination)) { for (Path pluginFile : stream) { if (Files.isDirectory(pluginFile)) { - setFileAttributes(pluginFile, DIR_AND_EXECUTABLE_PERMS); + setFileAttributes(pluginFile, PLUGIN_DIR_PERMS); } else { - setFileAttributes(pluginFile, FILE_PERMS); + setFileAttributes(pluginFile, PLUGIN_FILES_PERMS); } } } @@ -518,7 +520,7 @@ class InstallPluginCommand extends SettingCommand { throw new UserException(ExitCodes.IO_ERROR, "bin in plugin " + info.getName() + " is not a directory"); } Files.createDirectory(destBinDir); - setFileAttributes(destBinDir, DIR_AND_EXECUTABLE_PERMS); + setFileAttributes(destBinDir, BIN_DIR_PERMS); try (DirectoryStream stream = Files.newDirectoryStream(tmpBinDir)) { for (Path srcFile : stream) { @@ -530,7 +532,7 @@ class InstallPluginCommand extends SettingCommand { Path destFile = destBinDir.resolve(tmpBinDir.relativize(srcFile)); Files.copy(srcFile, destFile); - setFileAttributes(destFile, DIR_AND_EXECUTABLE_PERMS); + setFileAttributes(destFile, BIN_FILES_PERMS); } } IOUtils.rm(tmpBinDir); // clean up what we just copied @@ -546,7 +548,7 @@ class InstallPluginCommand extends SettingCommand { } Files.createDirectories(destConfigDir); - setFileAttributes(destConfigDir, DIR_AND_EXECUTABLE_PERMS); + setFileAttributes(destConfigDir, CONFIG_DIR_PERMS); final PosixFileAttributeView destConfigDirAttributesView = Files.getFileAttributeView(destConfigDir.getParent(), PosixFileAttributeView.class); final PosixFileAttributes destConfigDirAttributes = @@ -564,7 +566,7 @@ class InstallPluginCommand extends SettingCommand { Path destFile = destConfigDir.resolve(tmpConfigDir.relativize(srcFile)); if (Files.exists(destFile) == false) { Files.copy(srcFile, destFile); - setFileAttributes(destFile, FILE_PERMS); + setFileAttributes(destFile, CONFIG_FILES_PERMS); if (destConfigDirAttributes != null) { setOwnerGroup(destFile, destConfigDirAttributes); } diff --git a/distribution/build.gradle b/distribution/build.gradle index fe172620b5ba..42b696d9cce6 100644 --- a/distribution/build.gradle +++ b/distribution/build.gradle @@ -200,6 +200,8 @@ configure(subprojects.findAll { ['zip', 'tar', 'integ-test-zip'].contains(it.nam into("elasticsearch-${version}") { with libFiles into('config') { + dirMode 0750 + fileMode 0660 with configFiles } into('bin') { @@ -242,6 +244,12 @@ configure(subprojects.findAll { ['zip', 'tar', 'integ-test-zip'].contains(it.nam * 3. ospackage really wants to suck up some of the debian control scripts * directly from the filesystem. It doesn't want to process them through * MavenFilteringHack or any other copy-style action. + * + * The following commands are useful when it comes to check the user/group + * and files permissions set within the RPM and DEB packages: + * + * rpm -qlp --dump path/to/elasticsearch.rpm + * dpkg -c path/to/elasticsearch.deb */ configure(subprojects.findAll { ['deb', 'rpm'].contains(it.name) }) { integTest.enabled = Os.isFamily(Os.FAMILY_WINDOWS) == false @@ -276,8 +284,6 @@ configure(subprojects.findAll { ['deb', 'rpm'].contains(it.name) }) { dependsOn createEtc, createEtcScripts with configFiles into "${packagingFiles}/etc/elasticsearch" - fileMode 0640 - dirMode 0750 /* Explicitly declare the output files so this task doesn't consider itself up to date when the directory is created, which it would by default. And that'll happen when createEtc runs. */ @@ -365,7 +371,8 @@ configure(subprojects.findAll { ['deb', 'rpm'].contains(it.name) }) { configurationFile '/etc/elasticsearch/jvm.options' configurationFile '/etc/elasticsearch/log4j2.properties' into('/etc/elasticsearch') { - fileMode 0750 + dirMode 0750 + fileMode 0660 permissionGroup 'elasticsearch' includeEmptyDirs true createDirectoryEntry true @@ -387,35 +394,35 @@ configure(subprojects.findAll { ['deb', 'rpm'].contains(it.name) }) { } configurationFile '/etc/init.d/elasticsearch' into('/etc/init.d') { - fileMode 0755 + fileMode 0750 fileType CONFIG | NOREPLACE from "${packagingFiles}/init.d/elasticsearch" } configurationFile project.expansions['path.env'] into(new File(project.expansions['path.env']).getParent()) { - fileMode 0644 - dirMode 0755 fileType CONFIG | NOREPLACE + fileMode 0660 from "${project.packagingFiles}/env/elasticsearch" } /** * Suck up all the empty directories that we need to install into the path. */ - Closure suckUpEmptyDirectories = { path, u, g -> + Closure suckUpEmptyDirectories = { path, u, g, mode -> into(path) { - fileMode 0755 from "${packagingFiles}/${path}" includeEmptyDirs true createDirectoryEntry true user u permissionGroup g + dirMode mode + fileMode mode } } - suckUpEmptyDirectories('/var/run', 'elasticsearch', 'elasticsearch') - suckUpEmptyDirectories('/var/log', 'elasticsearch', 'elasticsearch') - suckUpEmptyDirectories('/var/lib', 'elasticsearch', 'elasticsearch') - suckUpEmptyDirectories('/usr/share/elasticsearch', 'root', 'root') + suckUpEmptyDirectories('/var/run', 'elasticsearch', 'elasticsearch', 0755) + suckUpEmptyDirectories('/var/log', 'elasticsearch', 'elasticsearch', 0750) + suckUpEmptyDirectories('/var/lib', 'elasticsearch', 'elasticsearch', 0750) + suckUpEmptyDirectories('/usr/share/elasticsearch', 'root', 'root', 0755) } } diff --git a/distribution/src/main/packaging/scripts/postinst b/distribution/src/main/packaging/scripts/postinst index 451ec3457d36..6d19e5f33c73 100644 --- a/distribution/src/main/packaging/scripts/postinst +++ b/distribution/src/main/packaging/scripts/postinst @@ -103,7 +103,7 @@ chmod 0750 /etc/elasticsearch chmod 0750 /etc/elasticsearch/scripts if [ -f /etc/sysconfig/elasticsearch ]; then - chmod 0644 /etc/sysconfig/elasticsearch + chmod 0660 /etc/sysconfig/elasticsearch fi ${scripts.footer} diff --git a/distribution/src/main/resources/bin/elasticsearch b/distribution/src/main/resources/bin/elasticsearch index 7b3d0ea19815..efac6fc4b634 100755 --- a/distribution/src/main/resources/bin/elasticsearch +++ b/distribution/src/main/resources/bin/elasticsearch @@ -47,7 +47,7 @@ if echo '${project.name}' | grep project.name > /dev/null ; then cat >&2 << EOF -Error: You must build the project with Maven or download a pre-built package +Error: You must build the project with Gradle or download a pre-built package before you can run Elasticsearch. See 'Building from Source' in README.textile or visit https://www.elastic.co/download to get a pre-built package. EOF diff --git a/qa/evil-tests/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java b/qa/evil-tests/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java index 6b930c171116..3bed3350f0f7 100644 --- a/qa/evil-tests/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java +++ b/qa/evil-tests/src/test/java/org/elasticsearch/plugins/InstallPluginCommandTests.java @@ -54,9 +54,11 @@ import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.GroupPrincipal; import java.nio.file.attribute.PosixFileAttributeView; import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.UserPrincipal; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -253,7 +255,7 @@ public class InstallPluginCommandTests extends ESTestCase { assertFalse("not a dir", Files.isDirectory(file)); if (isPosix) { PosixFileAttributes attributes = Files.readAttributes(file, PosixFileAttributes.class); - assertEquals(InstallPluginCommand.DIR_AND_EXECUTABLE_PERMS, attributes.permissions()); + assertEquals(InstallPluginCommand.BIN_FILES_PERMS, attributes.permissions()); } } } @@ -263,18 +265,33 @@ public class InstallPluginCommandTests extends ESTestCase { assertTrue("config dir exists", Files.exists(configDir)); assertTrue("config is a dir", Files.isDirectory(configDir)); + UserPrincipal user = null; + GroupPrincipal group = null; + if (isPosix) { - Path configRoot = env.configFile(); PosixFileAttributes configAttributes = - Files.getFileAttributeView(configRoot, PosixFileAttributeView.class).readAttributes(); + Files.getFileAttributeView(env.configFile(), PosixFileAttributeView.class).readAttributes(); + user = configAttributes.owner(); + group = configAttributes.group(); + PosixFileAttributes attributes = Files.getFileAttributeView(configDir, PosixFileAttributeView.class).readAttributes(); - assertThat(attributes.owner(), equalTo(configAttributes.owner())); - assertThat(attributes.group(), equalTo(configAttributes.group())); + assertThat(attributes.owner(), equalTo(user)); + assertThat(attributes.group(), equalTo(group)); } try (DirectoryStream stream = Files.newDirectoryStream(configDir)) { for (Path file : stream) { assertFalse("not a dir", Files.isDirectory(file)); + + if (isPosix) { + PosixFileAttributes attributes = Files.readAttributes(file, PosixFileAttributes.class); + if (user != null) { + assertThat(attributes.owner(), equalTo(user)); + } + if (group != null) { + assertThat(attributes.group(), equalTo(group)); + } + } } } } diff --git a/qa/vagrant/src/test/resources/packaging/scripts/30_deb_package.bats b/qa/vagrant/src/test/resources/packaging/scripts/30_deb_package.bats index 52f3de34a974..d0361339bf6d 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/30_deb_package.bats +++ b/qa/vagrant/src/test/resources/packaging/scripts/30_deb_package.bats @@ -94,6 +94,11 @@ setup() { run_elasticsearch_tests } +@test "[DEB] verify package installation after start" { + # Checks that the startup scripts didn't change the permissions + verify_package_installation +} + ################################## # Uninstall DEB package ################################## diff --git a/qa/vagrant/src/test/resources/packaging/scripts/40_rpm_package.bats b/qa/vagrant/src/test/resources/packaging/scripts/40_rpm_package.bats index 50c6849e92e0..5535d1a67cef 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/40_rpm_package.bats +++ b/qa/vagrant/src/test/resources/packaging/scripts/40_rpm_package.bats @@ -89,6 +89,11 @@ setup() { run_elasticsearch_tests } +@test "[RPM] verify package installation after start" { + # Checks that the startup scripts didn't change the permissions + verify_package_installation +} + @test "[RPM] remove package" { # User installed scripts aren't removed so we'll just get them ourselves rm -rf $ESSCRIPTS @@ -145,6 +150,10 @@ setup() { rpm -qe 'elasticsearch' } +@test "[RPM] verify package reinstallation" { + verify_package_installation +} + @test "[RPM] reremove package" { echo "# ping" >> "/etc/elasticsearch/elasticsearch.yml" echo "# ping" >> "/etc/elasticsearch/jvm.options" diff --git a/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash b/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash index 1060aa78849a..4948862d6ab4 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/os_package.bash @@ -80,13 +80,17 @@ verify_package_installation() { assert_file "$ESHOME" d root root 755 assert_file "$ESHOME/bin" d root root 755 + assert_file "$ESHOME/bin/elasticsearch" f root root 755 + assert_file "$ESHOME/bin/elasticsearch-plugin" f root root 755 + assert_file "$ESHOME/bin/elasticsearch-translog" f root root 755 assert_file "$ESHOME/lib" d root root 755 assert_file "$ESCONFIG" d root elasticsearch 750 - assert_file "$ESCONFIG/elasticsearch.yml" f root elasticsearch 750 - assert_file "$ESCONFIG/log4j2.properties" f root elasticsearch 750 + assert_file "$ESCONFIG/elasticsearch.yml" f root elasticsearch 660 + assert_file "$ESCONFIG/jvm.options" f root elasticsearch 660 + assert_file "$ESCONFIG/log4j2.properties" f root elasticsearch 660 assert_file "$ESSCRIPTS" d root elasticsearch 750 - assert_file "$ESDATA" d elasticsearch elasticsearch 755 - assert_file "$ESLOG" d elasticsearch elasticsearch 755 + assert_file "$ESDATA" d elasticsearch elasticsearch 750 + assert_file "$ESLOG" d elasticsearch elasticsearch 750 assert_file "$ESPLUGINS" d root root 755 assert_file "$ESMODULES" d root root 755 assert_file "$ESPIDDIR" d elasticsearch elasticsearch 755 @@ -95,7 +99,7 @@ verify_package_installation() { if is_dpkg; then # Env file - assert_file "/etc/default/elasticsearch" f root root 644 + assert_file "/etc/default/elasticsearch" f root root 660 # Doc files assert_file "/usr/share/doc/elasticsearch" d root root 755 @@ -104,7 +108,7 @@ verify_package_installation() { if is_rpm; then # Env file - assert_file "/etc/sysconfig/elasticsearch" f root root 644 + assert_file "/etc/sysconfig/elasticsearch" f root root 660 # License file assert_file "/usr/share/elasticsearch/LICENSE.txt" f root root 644 fi @@ -114,4 +118,15 @@ verify_package_installation() { assert_file "/usr/lib/tmpfiles.d/elasticsearch.conf" f root root 644 assert_file "/usr/lib/sysctl.d/elasticsearch.conf" f root root 644 fi + + if is_sysvinit; then + assert_file "/etc/init.d/elasticsearch" f root root 750 + fi + + run sudo -E -u vagrant LANG="en_US.UTF-8" cat "$ESCONFIG/elasticsearch.yml" + [ $status = 1 ] + [[ "$output" == *"Permission denied"* ]] || { + echo "Expected permission denied but found $output:" + false + } } diff --git a/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash b/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash index afae74390571..02cae2aeecb5 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/plugins.bash @@ -83,7 +83,6 @@ install_jvm_example() { #just make sure that everything is the same as the parent bin dir, which was properly set up during install bin_user=$(find "$ESHOME/bin" -maxdepth 0 -printf "%u") bin_owner=$(find "$ESHOME/bin" -maxdepth 0 -printf "%g") - bin_privileges=$(find "$ESHOME/bin" -maxdepth 0 -printf "%m") assert_file "$ESHOME/bin/jvm-example" d $bin_user $bin_owner 755 assert_file "$ESHOME/bin/jvm-example/test" f $bin_user $bin_owner 755 @@ -92,8 +91,15 @@ install_jvm_example() { config_user=$(find "$ESCONFIG" -maxdepth 0 -printf "%u") config_owner=$(find "$ESCONFIG" -maxdepth 0 -printf "%g") # directories should user the user file-creation mask - assert_file "$ESCONFIG/jvm-example" d $config_user $config_owner 755 - assert_file "$ESCONFIG/jvm-example/example.yaml" f $config_user $config_owner 644 + assert_file "$ESCONFIG/jvm-example" d $config_user $config_owner 750 + assert_file "$ESCONFIG/jvm-example/example.yaml" f $config_user $config_owner 660 + + run sudo -E -u vagrant LANG="en_US.UTF-8" cat "$ESCONFIG/jvm-example/example.yaml" + [ $status = 1 ] + [[ "$output" == *"Permission denied"* ]] || { + echo "Expected permission denied but found $output:" + false + } echo "Running jvm-example's bin script...." "$ESHOME/bin/jvm-example/test" | grep test diff --git a/qa/vagrant/src/test/resources/packaging/scripts/tar.bash b/qa/vagrant/src/test/resources/packaging/scripts/tar.bash index 0ea86ddcc6eb..3d6210a2ea3d 100644 --- a/qa/vagrant/src/test/resources/packaging/scripts/tar.bash +++ b/qa/vagrant/src/test/resources/packaging/scripts/tar.bash @@ -79,16 +79,18 @@ export_elasticsearch_paths() { # Checks that all directories & files are correctly installed # after a archive (tar.gz/zip) install verify_archive_installation() { - assert_file "$ESHOME" d - assert_file "$ESHOME/bin" d - assert_file "$ESHOME/bin/elasticsearch" f - assert_file "$ESHOME/bin/elasticsearch.in.sh" f - assert_file "$ESHOME/bin/elasticsearch-plugin" f - assert_file "$ESCONFIG" d - assert_file "$ESCONFIG/elasticsearch.yml" f - assert_file "$ESCONFIG/log4j2.properties" f - assert_file "$ESHOME/lib" d - assert_file "$ESHOME/NOTICE.txt" f - assert_file "$ESHOME/LICENSE.txt" f - assert_file "$ESHOME/README.textile" f + assert_file "$ESHOME" d elasticsearch elasticsearch 755 + assert_file "$ESHOME/bin" d elasticsearch elasticsearch 755 + assert_file "$ESHOME/bin/elasticsearch" f elasticsearch elasticsearch 755 + assert_file "$ESHOME/bin/elasticsearch.in.sh" f elasticsearch elasticsearch 755 + assert_file "$ESHOME/bin/elasticsearch-plugin" f elasticsearch elasticsearch 755 + assert_file "$ESHOME/bin/elasticsearch-translog" f elasticsearch elasticsearch 755 + assert_file "$ESCONFIG" d elasticsearch elasticsearch 755 + assert_file "$ESCONFIG/elasticsearch.yml" f elasticsearch elasticsearch 660 + assert_file "$ESCONFIG/jvm.options" f elasticsearch elasticsearch 660 + assert_file "$ESCONFIG/log4j2.properties" f elasticsearch elasticsearch 660 + assert_file "$ESHOME/lib" d elasticsearch elasticsearch 755 + assert_file "$ESHOME/NOTICE.txt" f elasticsearch elasticsearch 644 + assert_file "$ESHOME/LICENSE.txt" f elasticsearch elasticsearch 644 + assert_file "$ESHOME/README.textile" f elasticsearch elasticsearch 644 }