Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor environment variable processing for Docker #49612

Merged

Conversation

pugnascotia
Copy link
Contributor

@pugnascotia pugnascotia commented Nov 26, 2019

Closes #45223.

The current Docker entrypoint script picks up environment variables and
translates them into -E command line arguments. However, since any tool
executed via docker exec doesn't run the entrypoint, it results in
a poorer user experience.

This PR refactors the env var handling so that the -E options are
generated in elasticsearch-env. These have to be appended to any
existing command arguments, since some CLI tools have subcommands and
-E arguments must come after the subcommand.

Also extract the support for _FILE env vars into a separate script, so
that it can be called from more than once place (the behaviour is
idempotent).

Finally, add noop -E handling to CronEvalTool for parity, and support -E in MultiCommand before subcommands.

Closes elastic#45223.

The current Docker entrypoint script picks up environment variables and
translates them into -E command line arguments. However, since any tool
executes via `docker exec` doesn't run the entrypoint, it results in
a poorer user experience.

Therefore, refactor the env var handling so that the -E options are
generated in `elasticsearch-env`. These have to be appended to any
existing command arguments, since some CLI tools have subcommands and
-E arguments must come after the subcommand.

Also extract the support for `_FILE` env vars into a separate script, so
that it can be called from more than once place (the behaviour is
idempotent).

Finally, change `CronEvalTool` to extend `EnvironmentAwareCommand`, so
that it can allow (but ignore) -E commands. This also brings the tool in
line with our other CLI tools.
@pugnascotia pugnascotia added :Delivery/Packaging RPM and deb packaging, tar and zip archives, shell and batch scripts v8.0.0 labels Nov 26, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (:Core/Infra/Packaging)

Copy link
Contributor

@dliappis dliappis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Left a minor comment.

distribution/docker/src/docker/Dockerfile Show resolved Hide resolved
distribution/src/bin/elasticsearch-env Outdated Show resolved Hide resolved
Changing `CronEvalTool` to extend `EnvironmentAwareCommand` broke the
unit tests, and after further reflection I decided that this change was
lazy. Actually, the tool should just accept `-E` params but do nothing
with them, instead of pulling in all the reset of the env code.
@pugnascotia
Copy link
Contributor Author

So changing CronEvalTool to extend EnvironmentAwareCommand broke the unit tests, and after further reflection I decided that this change was lazy. Actually, the tool should just accept -E params but do nothing with them, instead of pulling in all the reset of the env code. This also means that the tool's help text documents the fact that the `-E options are unused, instead of implying that they do something.

@pugnascotia
Copy link
Contributor Author

I've updated MultiCommand to also accept -E arguments, since otherwise e.g. ./elasticsearch-node --help fails when it has -E args appends. The extra handling does nothing, and does not prevent -E` arguments later in the command line from being picked up correctly.

@pugnascotia pugnascotia requested a review from dliappis November 28, 2019 14:24
@pugnascotia
Copy link
Contributor Author

@tvernum I'd appreciate your thoughts on these changes if have capacity.

@@ -45,6 +45,9 @@
*/
public MultiCommand(final String description, final Runnable beforeMain) {
super(description, beforeMain);
// Accepting -E here does not prevent subcommands receiving -E arguments, since we also set `posixlyCorrect` below.
// This stops option parsing when the first non-option is encountered.
parser.accepts("E", "Unused. Pass to a subcommand instead").withRequiredArg();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a problem.
As you know, it's natural for people to expect that passing -E as the first argument to a multi-command will behave correctly. Currently they get an error, and have to work out what they've done wrong.

With this change they will no longer get an error, they will just get something that silently ignores their parameter. This is surprising and trappy behaviour.

If we want to do this, then I think we need to either:

  1. make it an error to pass -E and also call a subcommand (so --help -E var.from.docker=true works, but -E var=true auto does not); OR
  2. actually pass the -E values into the subcommand like people expect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm misunderstanding the behaviour here, and this already does (2), in which case can we make the comment more explicit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you're quite right. I was thinking primarily of the Docker case, but it would be much better if -E was respected wherever it is supplied. I'll look at this again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tvernum I've addressed this in 31e4679 by passing along -E args to subcommands.

Having MultiCommand silently accept and ignore -E arguments could be
confusing, so instead pass those arguments along to subcommands.
@pugnascotia pugnascotia requested a review from tvernum November 29, 2019 10:30
@pugnascotia
Copy link
Contributor Author

@elasticmachine run elasticsearch-ci/packaging-matrix

Although most environment variable handling related to Docker has
already been moved from the entrypoint script to `elasticsearch-env`,
there still remaining the setting of `ES_JAVA_OPTS` to override the
cgroup hierarchy setting. Move this to the env script as well, so that
Docker env var handling is done in one place.
Copy link
Contributor

@dliappis dliappis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for the change in e43283e

@pugnascotia pugnascotia requested a review from jkakavas December 3, 2019 13:59
@pugnascotia
Copy link
Contributor Author

@jkakavas would you have time to look over the Java parts of this PR from a security POV?

@dliappis
Copy link
Contributor

dliappis commented Dec 3, 2019

@pugnascotia It dawned on me that with this PR we should adjust also the instructions in step 4. of configuring-tls-on-docker. It runs elasticsearch-setup-passwords via docker exec so as they are now they explicitly execute the command with -E ....

In a separate PR we can adjust the same instructions in step 3 of the stack-docs.

Copy link
Contributor

@tvernum tvernum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@pugnascotia
Copy link
Contributor Author

@dliappis I updated the docs in 35487e9.

@pugnascotia pugnascotia requested review from dliappis and removed request for jkakavas December 5, 2019 12:01
Copy link
Contributor

@dliappis dliappis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! While digging into this I realized there are some changes in the images (UBI) which make one docker-compose file in this doc file non functional.

At some point we need docs tests for this, but I left a comment that IMHO we should bundle unzip in all our images (given the need to deal with artifacts from cli tools) and simplify the create-certs.yml compose file in the docs.

@@ -206,9 +206,6 @@ WARNING: Windows users not running PowerShell will need to remove `\` and join l
----
docker exec es01 /bin/bash -c "bin/elasticsearch-setup-passwords \
auto --batch \
-Expack.security.http.ssl.certificate=certificates/es01/es01.crt \
-Expack.security.http.ssl.certificate_authorities=certificates/ca/ca.crt \
-Expack.security.http.ssl.key=certificates/es01/es01.key \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This works, however -- at least this PR -- includes the UBI work and earlier in this file we rely on yum install unzip. In order to simply things, given that unzip is a fairly common requirement for handling certs, what if we include unzip in our Dockerfile i.e.bundle it in all Elasticsearch images and remove it from the the mentioned line above, so that examples and users don't have to pull it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me, and we already include gzip.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. Maybe, esp. given that we have abstracted the package manager invocation now, we could test for the present of unzip / zip in the path in our test cases, if it's not too complex?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call on the test - I was installing the CLI tools in the wrong part of the Dockefile!

@pugnascotia pugnascotia requested a review from dliappis December 9, 2019 09:55
Copy link
Contributor

@dliappis dliappis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@pugnascotia pugnascotia requested a review from dliappis December 12, 2019 14:33
Copy link
Contributor

@dliappis dliappis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! Left a comment

// These are installed to help users who are working with certificates.
Stream.of("zip", "unzip").forEach(cliTool -> {
// `which` isn't installed in our image, so instead just try to call the command.
final Shell.Result result = dockerShell.runIgnoreExitCode(cliTool + " -h");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In bash you can also rely on type -P <thefile> if you don't have which to ensure the file is in $PATH:

e.g. on the Ubi image:

[elasticsearch@0f6edc7f150a ~]$ type -P zip
[elasticsearch@0f6edc7f150a ~]$ echo $?
1
[elasticsearch@0f6edc7f150a ~]$ type -P ls
/usr/bin/ls
[elasticsearch@0f6edc7f150a ~]$ echo $?
0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type -P would work, but as it's a bash builtin, I'd have to run it through bash. That's a actually a bit cumbersome, because we're already running "bash -c 'docker blah blah commmand'". Instead, I'm now using rpm to check if the package is installed.

@pugnascotia pugnascotia requested a review from dliappis December 13, 2019 10:23
@pugnascotia pugnascotia merged commit 9f069f7 into elastic:master Dec 16, 2019
@pugnascotia pugnascotia deleted the 45223-refactor-env-var-handling branch December 16, 2019 09:57
pugnascotia added a commit to pugnascotia/elasticsearch that referenced this pull request Dec 16, 2019
Closes elastic#45223.

The current Docker entrypoint script picks up environment variables and
translates them into -E command line arguments. However, since any tool
executes via `docker exec` doesn't run the entrypoint, it results in
a poorer user experience.

Therefore, refactor the env var handling so that the -E options are
generated in `elasticsearch-env`. These have to be appended to any
existing command arguments, since some CLI tools have subcommands and
-E arguments must come after the subcommand.

Also extract the support for `_FILE` env vars into a separate script, so
that it can be called from more than once place (the behaviour is
idempotent).

Finally, add noop -E handling to CronEvalTool for parity, and support
`-E` in MultiCommand before subcommands.
pugnascotia added a commit that referenced this pull request Dec 16, 2019
Backport of #49612.

The current Docker entrypoint script picks up environment variables and
translates them into -E command line arguments. However, since any tool
executes via `docker exec` doesn't run the entrypoint, it results in
a poorer user experience.

Therefore, refactor the env var handling so that the -E options are
generated in `elasticsearch-env`. These have to be appended to any
existing command arguments, since some CLI tools have subcommands and
-E arguments must come after the subcommand.

Also extract the support for `_FILE` env vars into a separate script, so
that it can be called from more than once place (the behaviour is
idempotent).

Finally, add noop -E handling to CronEvalTool for parity, and support
`-E` in MultiCommand before subcommands.
SivagurunathanV pushed a commit to SivagurunathanV/elasticsearch that referenced this pull request Jan 23, 2020
Closes elastic#45223.

The current Docker entrypoint script picks up environment variables and
translates them into -E command line arguments. However, since any tool
executes via `docker exec` doesn't run the entrypoint, it results in
a poorer user experience.

Therefore, refactor the env var handling so that the -E options are
generated in `elasticsearch-env`. These have to be appended to any
existing command arguments, since some CLI tools have subcommands and
-E arguments must come after the subcommand.

Also extract the support for `_FILE` env vars into a separate script, so
that it can be called from more than once place (the behaviour is
idempotent).

Finally, add noop -E handling to CronEvalTool for parity, and support
`-E` in MultiCommand before subcommands.
@mark-vieira mark-vieira added the Team:Delivery Meta label for Delivery team label Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Delivery/Packaging RPM and deb packaging, tar and zip archives, shell and batch scripts Team:Delivery Meta label for Delivery team v7.6.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make docker environment variable parsing available in CLI tools
7 participants