diff --git a/distribution/src/bin/elasticsearch-env b/distribution/src/bin/elasticsearch-env index 6cb41da4ba40..7bc3ba6d2b51 100644 --- a/distribution/src/bin/elasticsearch-env +++ b/distribution/src/bin/elasticsearch-env @@ -111,7 +111,7 @@ if [[ "$ES_DISTRIBUTION_TYPE" == "docker" ]]; then # Parse Docker env vars to customize Elasticsearch # - # e.g. Setting the env var cluster.name=testcluster + # e.g. Setting the env var cluster.name=testcluster or ES_CLUSTER_NAME=testcluster # # will cause Elasticsearch to be invoked with -Ecluster.name=testcluster # @@ -122,11 +122,35 @@ if [[ "$ES_DISTRIBUTION_TYPE" == "docker" ]]; then while IFS='=' read -r envvar_key envvar_value do # Elasticsearch settings need to have at least two dot separated lowercase - # words, e.g. `cluster.name` - if [[ "$envvar_key" =~ ^[a-z0-9_]+\.[a-z0-9_]+ ]]; then - if [[ ! -z $envvar_value ]]; then + # words, e.g. `cluster.name`, or uppercased with underscore separators and + # prefixed with `ES_`, e.g. `ES_CLUSTER_NAME`. Underscores in setting names + # are escaped by writing them as a double-underscore e.g. "__" + if [[ ! -z "$envvar_value" ]]; then + if [[ "$envvar_key" =~ ^[a-z0-9_]+\.[a-z0-9_]+ ]]; then es_opt="-E${envvar_key}=${envvar_value}" es_arg_array+=("${es_opt}") + elif [[ "$envvar_key" =~ ^ES(_{1,2}[A-Z]+)+$ ]]; then + case "$envvar_key" in + # Do nothing for these. Not all of these are actually exported into the environment by our scripts, + # and so don't appear in the output of the `env` command, but it's better to be safe than sorry + # in case a user exported them in their own shell for some reason. + ES_DISTRIBUTION_FLAVOR) ;; + ES_DISTRIBUTION_TYPE) ;; + ES_HOME) ;; + ES_JAVA_HOME) ;; + ES_JAVA_OPTS) ;; + ES_KEYSTORE_PASSPHRASE_FILE) ;; + ES_LOG_STYLE) ;; + ES_PATH_CONF) ;; + ES_SD_NOTIFY) ;; + ES_TMPDIR) ;; + *) + # The long-hand sed `y` command works in any sed variant. + envvar_key="$(echo "$envvar_key" | sed -e 's/^ES_//; s/_/./g ; s/\.\./_/g; y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' )" + es_opt="-E${envvar_key}=${envvar_value}" + es_arg_array+=("${es_opt}") + ;; + esac fi fi done <<< "$(env)" diff --git a/docs/reference/setup/install/docker.asciidoc b/docs/reference/setup/install/docker.asciidoc index a19bacb47fa4..f15189789881 100644 --- a/docs/reference/setup/install/docker.asciidoc +++ b/docs/reference/setup/install/docker.asciidoc @@ -339,7 +339,19 @@ over the configuration files in the image. You can set individual {es} configuration parameters using Docker environment variables. The <> and the -<> use this method. +<> use this method. You can +use the setting name directly as the environment variable name. If +you cannot do this, for example because your orchestration platform forbids +periods in environment variable names, then you can use an alternative +style by converting the setting name as follows. + +. Change the setting name to uppercase +. Prefix it with `ES_` +. Escape any underscores (`_`) by duplicating them +. Convert all periods (`.`) to underscores (`_`) + +For example, `-e bootstrap.memory_lock=true` becomes +`-e ES_BOOTSTRAP_MEMORY__LOCK=true`. To use the contents of a file to set an environment variable, suffix the environment variable name with `_FILE`. This is useful for passing secrets such as passwords to {es} diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java b/qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java index d6ea55f7b110..d173613391fe 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java @@ -486,6 +486,50 @@ public class DockerTests extends PackagingTestCase { assertThat(result.stdout, containsString("java.net.UnknownHostException: this.is.not.valid")); } + /** + * Check that settings are applied when they are supplied as environment variables with names that are: + *
    + *
  • Prefixed with {@code ES_}
  • + *
  • All uppercase
  • + *
  • Dots (periods) are converted to underscores
  • + *
  • Underscores in setting names are escaped by doubling them
  • + *
+ */ + public void test086EnvironmentVariablesInSnakeCaseAreTranslated() { + // Note the double-underscore in the var name here, which retains the underscore in translation + installation = runContainer(distribution(), builder().envVars(Map.of("ES_XPACK_SECURITY_FIPS__MODE_ENABLED", "false"))); + + final Optional commandLine = sh.run("bash -c 'COLUMNS=2000 ps ax'").stdout.lines() + .filter(line -> line.contains("org.elasticsearch.bootstrap.Elasticsearch")) + .findFirst(); + + assertThat(commandLine.isPresent(), equalTo(true)); + + assertThat(commandLine.get(), containsString("-Expack.security.fips_mode.enabled=false")); + } + + /** + * Check that environment variables that do not match the criteria for translation to settings are ignored. + */ + public void test087EnvironmentVariablesInIncorrectFormatAreIgnored() { + final Map envVars = new HashMap<>(); + // No ES_ prefix + envVars.put("XPACK_SECURITY_FIPS__MODE_ENABLED", "false"); + // Not underscore-separated + envVars.put("ES.XPACK.SECURITY.FIPS_MODE.ENABLED", "false"); + // Not uppercase + envVars.put("es_xpack_security_fips__mode_enabled", "false"); + installation = runContainer(distribution(), builder().envVars(envVars)); + + final Optional commandLine = sh.run("bash -c 'COLUMNS=2000 ps ax'").stdout.lines() + .filter(line -> line.contains("org.elasticsearch.bootstrap.Elasticsearch")) + .findFirst(); + + assertThat(commandLine.isPresent(), equalTo(true)); + + assertThat(commandLine.get(), not(containsString("-Expack.security.fips_mode.enabled=false"))); + } + /** * Check whether the elasticsearch-certutil tool has been shipped correctly, * and if present then it can execute.