forked from elastic/elasticsearch
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Elasticsearch keystore passphrase for startup scripts (elastic#44775)
This commit allows a user to provide a keystore password on Elasticsearch startup, but only prompts when the keystore exists and is encrypted. The entrypoint in Java code is standard input. When the Bootstrap class is checking for secure keystore settings, it checks whether or not the keystore is encrypted. If so, we read one line from standard input and use this as the password. For simplicity's sake, we allow a maximum passphrase length of 128 characters. (This is an arbitrary limit and could be increased or eliminated. It is also enforced in the keystore tools, so that a user can't create a password that's too long to enter at startup.) In order to provide a password on standard input, we have to account for four different ways of starting Elasticsearch: the bash startup script, the Windows batch startup script, systemd startup, and docker startup. We use wrapper scripts to reduce systemd and docker to the bash case: in both cases, a wrapper script can read a passphrase from the filesystem and pass it to the bash script. In order to simplify testing the need for a passphrase, I have added a has-passwd command to the keystore tool. This command can run silently, and exit with status 0 when the keystore has a password. It exits with status 1 if the keystore doesn't exist or exists and is unencrypted. A good deal of the code-change in this commit has to do with refactoring packaging tests to cleanly use the same tests for both the "archive" and the "package" cases. This required not only moving tests around, but also adding some convenience methods for an abstraction layer over distribution-specific commands. I will write some user-facing documentation for these changes in a follow-up commit.
- Loading branch information
1 parent
6bb0e45
commit fafaead
Showing
31 changed files
with
1,125 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
distribution/packages/src/common/systemd/systemd-entrypoint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/bin/sh | ||
|
||
# This wrapper script allows SystemD to feed a file containing a passphrase into | ||
# the main Elasticsearch startup script | ||
|
||
if [ -n "$ES_KEYSTORE_PASSPHRASE_FILE" ] ; then | ||
exec /usr/share/elasticsearch/bin/elasticsearch "$@" < "$ES_KEYSTORE_PASSPHRASE_FILE" | ||
else | ||
exec /usr/share/elasticsearch/bin/elasticsearch "$@" | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
...store-cli/src/main/java/org/elasticsearch/common/settings/HasPasswordKeyStoreCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* 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.common.settings; | ||
|
||
import joptsimple.OptionSet; | ||
import org.elasticsearch.cli.KeyStoreAwareCommand; | ||
import org.elasticsearch.cli.Terminal; | ||
import org.elasticsearch.cli.UserException; | ||
import org.elasticsearch.env.Environment; | ||
|
||
import java.nio.file.Path; | ||
|
||
public class HasPasswordKeyStoreCommand extends KeyStoreAwareCommand { | ||
|
||
static final int NO_PASSWORD_EXIT_CODE = 1; | ||
|
||
HasPasswordKeyStoreCommand() { | ||
super("Succeeds if the keystore exists and is password-protected, " + | ||
"fails with exit code " + NO_PASSWORD_EXIT_CODE + " otherwise."); | ||
} | ||
|
||
@Override | ||
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception { | ||
final Path configFile = env.configFile(); | ||
final KeyStoreWrapper keyStore = KeyStoreWrapper.load(configFile); | ||
|
||
// We handle error printing here so we can respect the "--silent" flag | ||
// We have to throw an exception to get a nonzero exit code | ||
if (keyStore == null) { | ||
terminal.errorPrintln(Terminal.Verbosity.NORMAL, "ERROR: Elasticsearch keystore not found"); | ||
throw new UserException(NO_PASSWORD_EXIT_CODE, null); | ||
} | ||
if (keyStore.hasPassword() == false) { | ||
terminal.errorPrintln(Terminal.Verbosity.NORMAL, "ERROR: Keystore is not password-protected"); | ||
throw new UserException(NO_PASSWORD_EXIT_CODE, null); | ||
} | ||
|
||
terminal.println(Terminal.Verbosity.NORMAL, "Keystore is password-protected"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
...-cli/src/test/java/org/elasticsearch/common/settings/HasPasswordKeyStoreCommandTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* 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.common.settings; | ||
|
||
import org.elasticsearch.cli.Command; | ||
import org.elasticsearch.cli.UserException; | ||
import org.elasticsearch.env.Environment; | ||
|
||
import java.util.Map; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.Matchers.containsString; | ||
import static org.hamcrest.Matchers.emptyString; | ||
import static org.hamcrest.Matchers.nullValue; | ||
|
||
public class HasPasswordKeyStoreCommandTests extends KeyStoreCommandTestCase { | ||
@Override | ||
protected Command newCommand() { | ||
return new HasPasswordKeyStoreCommand() { | ||
@Override | ||
protected Environment createEnv(Map<String, String> settings) throws UserException { | ||
return env; | ||
} | ||
}; | ||
} | ||
|
||
public void testFailsWithNoKeystore() throws Exception { | ||
UserException e = expectThrows(UserException.class, this::execute); | ||
assertEquals("Exit code should be 1", HasPasswordKeyStoreCommand.NO_PASSWORD_EXIT_CODE, e.exitCode); | ||
assertThat("Exception should have null message", e.getMessage(), is(nullValue())); | ||
} | ||
|
||
public void testFailsWhenKeystoreLacksPassword() throws Exception { | ||
createKeystore(""); | ||
UserException e = expectThrows(UserException.class, this::execute); | ||
assertEquals("Exit code should be 1", HasPasswordKeyStoreCommand.NO_PASSWORD_EXIT_CODE, e.exitCode); | ||
assertThat("Exception should have null message", e.getMessage(), is(nullValue())); | ||
} | ||
|
||
public void testSucceedsWhenKeystoreHasPassword() throws Exception { | ||
createKeystore("password"); | ||
String output = execute(); | ||
assertThat(output, containsString("Keystore is password-protected")); | ||
} | ||
|
||
public void testSilentSucceedsWhenKeystoreHasPassword() throws Exception { | ||
createKeystore("password"); | ||
String output = execute("--silent"); | ||
assertThat(output, is(emptyString())); | ||
} | ||
} |
Oops, something went wrong.