Skip to content

Commit

Permalink
Limit _FILE env var support to specific vars (#52647)
Browse files Browse the repository at this point in the history
Backport of #52525.

Closes #52503. Implement a list of `_FILE` env vars that will be used to
populate env vars with file content, instead of processing all `_FILE`
vars in the environment.
  • Loading branch information
pugnascotia authored Feb 21, 2020
1 parent 09b8a1f commit 0206b7c
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 50 deletions.
8 changes: 6 additions & 2 deletions distribution/src/bin/elasticsearch-env-from-file
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ set -e -o pipefail
# point to it. This can be used to provide secrets to a container, without
# the values being specified explicitly when running the container.
#
# Note that only supported environment variables are processed, in order
# to avoid unexpected failures when an environment sets a "*_FILE" variable
# that doesn't contain a filename.
#
# This script is intended to be sourced, not executed, and modifies the
# environment.

for VAR_NAME_FILE in $(env | cut -f1 -d= | grep '_FILE$'); do
if [[ -n "$VAR_NAME_FILE" ]]; then
for VAR_NAME_FILE in ELASTIC_PASSWORD_FILE KEYSTORE_PASSWORD_FILE ; do
if [[ -n "${!VAR_NAME_FILE}" ]]; then
VAR_NAME="${VAR_NAME_FILE%_FILE}"

if env | grep "^${VAR_NAME}="; then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import static org.elasticsearch.packaging.util.FileUtils.append;
import static org.elasticsearch.packaging.util.FileUtils.getTempDir;
import static org.elasticsearch.packaging.util.FileUtils.rm;
import static org.elasticsearch.packaging.util.ServerUtils.makeRequest;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
Expand Down Expand Up @@ -270,38 +269,10 @@ public void test071BindMountCustomPathWithDifferentUID() throws Exception {
});
}

/**
* Check that environment variables can be populated by setting variables with the suffix "_FILE",
* which point to files that hold the required values.
*/
public void test080SetEnvironmentVariablesUsingFiles() throws Exception {
final String optionsFilename = "esJavaOpts.txt";

// ES_JAVA_OPTS_FILE
append(tempDir.resolve(optionsFilename), "-XX:-UseCompressedOops\n");

Map<String, String> envVars = singletonMap("ES_JAVA_OPTS_FILE", "/run/secrets/" + optionsFilename);

// File permissions need to be secured in order for the ES wrapper to accept
// them for populating env var values
Files.setPosixFilePermissions(tempDir.resolve(optionsFilename), p600);

final Map<Path, Path> volumes = singletonMap(tempDir, Paths.get("/run/secrets"));

// Restart the container
runContainer(distribution(), volumes, envVars);

waitForElasticsearch(installation);

final String nodesResponse = makeRequest(Request.Get("http://localhost:9200/_nodes"));

assertThat(nodesResponse, containsString("\"using_compressed_ordinary_object_pointers\":\"false\""));
}

/**
* Check that the elastic user's password can be configured via a file and the ELASTIC_PASSWORD_FILE environment variable.
*/
public void test081ConfigurePasswordThroughEnvironmentVariableFile() throws Exception {
public void test080ConfigurePasswordThroughEnvironmentVariableFile() throws Exception {
// Test relies on configuring security
assumeTrue(distribution.isDefault());

Expand Down Expand Up @@ -344,7 +315,7 @@ public void test081ConfigurePasswordThroughEnvironmentVariableFile() throws Exce
* Check that when verifying the file permissions of _FILE environment variables, symlinks
* are followed.
*/
public void test082SymlinksAreFollowedWithEnvironmentVariableFiles() throws Exception {
public void test081SymlinksAreFollowedWithEnvironmentVariableFiles() throws Exception {
// Test relies on configuring security
assumeTrue(distribution.isDefault());
// Test relies on symlinks
Expand Down Expand Up @@ -381,44 +352,43 @@ public void test082SymlinksAreFollowedWithEnvironmentVariableFiles() throws Exce
/**
* Check that environment variables cannot be used with _FILE environment variables.
*/
public void test083CannotUseEnvVarsAndFiles() throws Exception {
final String optionsFilename = "esJavaOpts.txt";
public void test082CannotUseEnvVarsAndFiles() throws Exception {
final String passwordFilename = "password.txt";

// ES_JAVA_OPTS_FILE
append(tempDir.resolve(optionsFilename), "-XX:-UseCompressedOops\n");
Files.write(tempDir.resolve(passwordFilename), "other_hunter2\n".getBytes(StandardCharsets.UTF_8));

Map<String, String> envVars = new HashMap<>();
envVars.put("ES_JAVA_OPTS", "-XX:+UseCompressedOops");
envVars.put("ES_JAVA_OPTS_FILE", "/run/secrets/" + optionsFilename);
envVars.put("ELASTIC_PASSWORD", "hunter2");
envVars.put("ELASTIC_PASSWORD_FILE", "/run/secrets/" + passwordFilename);

// File permissions need to be secured in order for the ES wrapper to accept
// them for populating env var values
Files.setPosixFilePermissions(tempDir.resolve(optionsFilename), p600);
Files.setPosixFilePermissions(tempDir.resolve(passwordFilename), p600);

final Map<Path, Path> volumes = singletonMap(tempDir, Paths.get("/run/secrets"));

final Result dockerLogs = runContainerExpectingFailure(distribution, volumes, envVars);

assertThat(
dockerLogs.stderr,
containsString("ERROR: Both ES_JAVA_OPTS_FILE and ES_JAVA_OPTS are set. These are mutually " + "exclusive.")
containsString("ERROR: Both ELASTIC_PASSWORD_FILE and ELASTIC_PASSWORD are set. These are mutually exclusive.")
);
}

/**
* Check that when populating environment variables by setting variables with the suffix "_FILE",
* the files' permissions are checked.
*/
public void test084EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws Exception {
final String optionsFilename = "esJavaOpts.txt";
public void test083EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws Exception {
final String passwordFilename = "password.txt";

// ES_JAVA_OPTS_FILE
append(tempDir.resolve(optionsFilename), "-XX:-UseCompressedOops\n");
Files.write(tempDir.resolve(passwordFilename), "hunter2\n".getBytes(StandardCharsets.UTF_8));

Map<String, String> envVars = singletonMap("ES_JAVA_OPTS_FILE", "/run/secrets/" + optionsFilename);
Map<String, String> envVars = new HashMap<>();
envVars.put("ELASTIC_PASSWORD_FILE", "/run/secrets/" + passwordFilename);

// Set invalid file permissions
Files.setPosixFilePermissions(tempDir.resolve(optionsFilename), p660);
Files.setPosixFilePermissions(tempDir.resolve(passwordFilename), p660);

final Map<Path, Path> volumes = singletonMap(tempDir, Paths.get("/run/secrets"));

Expand All @@ -428,7 +398,7 @@ public void test084EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws
assertThat(
dockerLogs.stderr,
containsString(
"ERROR: File /run/secrets/" + optionsFilename + " from ES_JAVA_OPTS_FILE must have " + "file permissions 400 or 600"
"ERROR: File /run/secrets/" + passwordFilename + " from ELASTIC_PASSWORD_FILE must have file permissions 400 or 600"
)
);
}
Expand All @@ -437,7 +407,7 @@ public void test084EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws
* Check that when verifying the file permissions of _FILE environment variables, symlinks
* are followed, and that invalid target permissions are detected.
*/
public void test085SymlinkToFileWithInvalidPermissionsIsRejected() throws Exception {
public void test084SymlinkToFileWithInvalidPermissionsIsRejected() throws Exception {
// Test relies on configuring security
assumeTrue(distribution.isDefault());
// Test relies on symlinks
Expand Down Expand Up @@ -483,7 +453,7 @@ public void test085SymlinkToFileWithInvalidPermissionsIsRejected() throws Except
* Check that environment variables are translated to -E options even for commands invoked under
* `docker exec`, where the Docker image's entrypoint is not executed.
*/
public void test086EnvironmentVariablesAreRespectedUnderDockerExec() {
public void test085EnvironmentVariablesAreRespectedUnderDockerExec() {
// This test relies on a CLI tool attempting to connect to Elasticsearch, and the
// tool in question is only in the default distribution.
assumeTrue(distribution.isDefault());
Expand Down

0 comments on commit 0206b7c

Please sign in to comment.