-
Notifications
You must be signed in to change notification settings - Fork 24.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add passphrase support to elasticsearch-keystore (#38498)
This change adds support for keystore passphrases to all subcommands of the elasticsearch-keystore cli tool and adds a subcommand for changing the passphrase of an existing keystore. The work to read the passphrase in Elasticsearch when loading, which will be addressed in a different PR. Subcommands of elasticsearch-keystore can handle (open and create) passphrase protected keystores When reading a keystore, a user is only prompted for a passphrase only if the keystore is passphrase protected. When creating a keystore, a user is allowed (default behavior) to create one with an empty passphrase Passphrase can be set to be empty when changing/setting it for an existing keystore Relates to: #32691 Supersedes: #37472
- Loading branch information
Showing
20 changed files
with
557 additions
and
245 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
115 changes: 115 additions & 0 deletions
115
...ols/keystore-cli/src/main/java/org/elasticsearch/common/settings/BaseKeyStoreCommand.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,115 @@ | ||
/* | ||
* 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.EnvironmentAwareCommand; | ||
import org.elasticsearch.cli.ExitCodes; | ||
import org.elasticsearch.cli.Terminal; | ||
import org.elasticsearch.cli.UserException; | ||
import org.elasticsearch.env.Environment; | ||
|
||
import java.nio.file.Path; | ||
import java.util.Arrays; | ||
|
||
public abstract class BaseKeyStoreCommand extends EnvironmentAwareCommand { | ||
|
||
private KeyStoreWrapper keyStore; | ||
private SecureString keyStorePassword; | ||
private final boolean keyStoreMustExist; | ||
|
||
public BaseKeyStoreCommand(String description, boolean keyStoreMustExist) { | ||
super(description); | ||
this.keyStoreMustExist = keyStoreMustExist; | ||
} | ||
|
||
@Override | ||
protected final void execute(Terminal terminal, OptionSet options, Environment env) throws Exception { | ||
try { | ||
final Path configFile = env.configFile(); | ||
keyStore = KeyStoreWrapper.load(configFile); | ||
if (keyStore == null) { | ||
if (keyStoreMustExist) { | ||
throw new UserException(ExitCodes.DATA_ERROR, "Elasticsearch keystore not found at [" + | ||
KeyStoreWrapper.keystorePath(env.configFile()) + "]. Use 'create' command to create one."); | ||
} else { | ||
if (terminal.promptYesNo("The elasticsearch keystore does not exist. Do you want to create it?", false) == false) { | ||
terminal.println("Exiting without creating keystore."); | ||
return; | ||
} | ||
} | ||
keyStorePassword = new SecureString(new char[0]); | ||
keyStore = KeyStoreWrapper.create(); | ||
keyStore.save(configFile, keyStorePassword.getChars()); | ||
} else { | ||
keyStorePassword = keyStore.hasPassword() ? readPassword(terminal, false) : new SecureString(new char[0]); | ||
keyStore.decrypt(keyStorePassword.getChars()); | ||
} | ||
executeCommand(terminal, options, env); | ||
} catch (SecurityException e) { | ||
throw new UserException(ExitCodes.DATA_ERROR, e.getMessage()); | ||
} finally { | ||
if (keyStorePassword != null) { | ||
keyStorePassword.close(); | ||
} | ||
} | ||
} | ||
|
||
protected KeyStoreWrapper getKeyStore() { | ||
return keyStore; | ||
} | ||
|
||
protected SecureString getKeyStorePassword() { | ||
return keyStorePassword; | ||
} | ||
|
||
/** | ||
* Reads the keystore password from the {@link Terminal}, prompting for verification where applicable and returns it as a | ||
* {@link SecureString}. | ||
* | ||
* @param terminal the terminal to use for user inputs | ||
* @param withVerification whether the user should be prompted for password verification | ||
* @return a SecureString with the password the user entered | ||
* @throws UserException If the user is prompted for verification and enters a different password | ||
*/ | ||
static SecureString readPassword(Terminal terminal, boolean withVerification) throws UserException { | ||
final char[] passwordArray; | ||
if (withVerification) { | ||
passwordArray = terminal.readSecret("Enter new password for the elasticsearch keystore (empty for no password): "); | ||
char[] passwordVerification = terminal.readSecret("Enter same password again: "); | ||
if (Arrays.equals(passwordArray, passwordVerification) == false) { | ||
throw new UserException(ExitCodes.DATA_ERROR, "Passwords are not equal, exiting."); | ||
} | ||
Arrays.fill(passwordVerification, '\u0000'); | ||
} else { | ||
passwordArray = terminal.readSecret("Enter password for the elasticsearch keystore : "); | ||
} | ||
final SecureString password = new SecureString(passwordArray); | ||
return password; | ||
} | ||
|
||
/** | ||
* This is called after the keystore password has been read from the stdin and the keystore is decrypted and | ||
* loaded. The keystore and keystore passwords are available to classes extending {@link BaseKeyStoreCommand} | ||
* using {@link BaseKeyStoreCommand#getKeyStore()} and {@link BaseKeyStoreCommand#getKeyStorePassword()} | ||
* respectively. | ||
*/ | ||
protected abstract void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception; | ||
} |
47 changes: 47 additions & 0 deletions
47
...re-cli/src/main/java/org/elasticsearch/common/settings/ChangeKeyStorePasswordCommand.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,47 @@ | ||
/* | ||
* 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.ExitCodes; | ||
import org.elasticsearch.cli.Terminal; | ||
import org.elasticsearch.cli.UserException; | ||
import org.elasticsearch.env.Environment; | ||
|
||
/** | ||
* A sub-command for the keystore cli which changes the password. | ||
*/ | ||
class ChangeKeyStorePasswordCommand extends BaseKeyStoreCommand { | ||
|
||
ChangeKeyStorePasswordCommand() { | ||
super("Changes the password of a keystore", true); | ||
} | ||
|
||
@Override | ||
protected void executeCommand(Terminal terminal, OptionSet options, Environment env) throws Exception { | ||
try (SecureString newPassword = readPassword(terminal, true)) { | ||
final KeyStoreWrapper keyStore = getKeyStore(); | ||
keyStore.save(env.configFile(), newPassword.getChars()); | ||
terminal.println("Elasticsearch keystore password changed successfully."); | ||
} catch (SecurityException e) { | ||
throw new UserException(ExitCodes.DATA_ERROR, e.getMessage()); | ||
} | ||
} | ||
} |
Oops, something went wrong.