Skip to content

Add passphrase support to elasticsearch-keystore #37472

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

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,68 @@ class AddFileKeyStoreCommand extends EnvironmentAwareCommand {

@Override
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
KeyStoreWrapper keystore = KeyStoreWrapper.load(env.configFile());
if (keystore == null) {
if (options.has(forceOption) == false &&
terminal.promptYesNo("The elasticsearch keystore does not exist. Do you want to create it?", false) == false) {
terminal.println("Exiting without creating keystore.");
return;
char[] password = null;
char[] passwordVerification = null;
try {
KeyStoreWrapper keystore = KeyStoreWrapper.load(env.configFile());
if (keystore == null) {
if (options.has(forceOption) == false &&
terminal.promptYesNo("The elasticsearch keystore does not exist. Do you want to create it?", false) == false) {
terminal.println("Exiting without creating keystore.");
return;
}
password = terminal.readSecret("Enter passphrase for the elasticsearch keystore (empty for no passphrase): ");
passwordVerification = terminal.readSecret("Enter same passphrase again: ");
if (Arrays.equals(password, passwordVerification) == false) {
throw new UserException(ExitCodes.DATA_ERROR, "Passphrases are not equal, exiting.");
}
keystore = KeyStoreWrapper.create();
keystore.save(env.configFile(), password);
terminal.println("Created elasticsearch keystore in " + env.configFile());
} else {
if (keystore.hasPassword()) {
password = terminal.readSecret("Enter passphrase for the elasticsearch keystore: ");
} else {
password = new char[0];
}
keystore.decrypt(password);
}
keystore = KeyStoreWrapper.create();
keystore.save(env.configFile(), new char[0] /* always use empty passphrase for auto created keystore */);
terminal.println("Created elasticsearch keystore in " + env.configFile());
} else {
keystore.decrypt(new char[0] /* TODO: prompt for password when they are supported */);
}

List<String> argumentValues = arguments.values(options);
if (argumentValues.size() == 0) {
throw new UserException(ExitCodes.USAGE, "Missing setting name");
}
String setting = argumentValues.get(0);
if (keystore.getSettingNames().contains(setting) && options.has(forceOption) == false) {
if (terminal.promptYesNo("Setting " + setting + " already exists. Overwrite?", false) == false) {
terminal.println("Exiting without modifying keystore.");
return;
List<String> argumentValues = arguments.values(options);
if (argumentValues.size() == 0) {
throw new UserException(ExitCodes.USAGE, "Missing setting name");
}
String setting = argumentValues.get(0);
if (keystore.getSettingNames().contains(setting) && options.has(forceOption) == false) {
if (terminal.promptYesNo("Setting " + setting + " already exists. Overwrite?", false) == false) {
terminal.println("Exiting without modifying keystore.");
return;
}
}
}

if (argumentValues.size() == 1) {
throw new UserException(ExitCodes.USAGE, "Missing file name");
}
Path file = getPath(argumentValues.get(1));
if (Files.exists(file) == false) {
throw new UserException(ExitCodes.IO_ERROR, "File [" + file.toString() + "] does not exist");
}
if (argumentValues.size() > 2) {
throw new UserException(ExitCodes.USAGE, "Unrecognized extra arguments [" +
String.join(", ", argumentValues.subList(2, argumentValues.size())) + "] after filepath");
if (argumentValues.size() == 1) {
throw new UserException(ExitCodes.USAGE, "Missing file name");
}
Path file = getPath(argumentValues.get(1));
if (Files.exists(file) == false) {
throw new UserException(ExitCodes.IO_ERROR, "File [" + file.toString() + "] does not exist");
}
if (argumentValues.size() > 2) {
throw new UserException(ExitCodes.USAGE, "Unrecognized extra arguments [" +
String.join(", ", argumentValues.subList(2, argumentValues.size())) + "] after filepath");
}
keystore.setFile(setting, Files.readAllBytes(file));
keystore.save(env.configFile(), password);
} catch (SecurityException e) {
throw new UserException(ExitCodes.DATA_ERROR, "Failed to access the keystore. Please make sure the passphrase was correct.");
} finally {
if (null != password) {
Arrays.fill(password, '\u0000');
}
if (null != passwordVerification) {
Arrays.fill(passwordVerification, '\u0000');
}
}
keystore.setFile(setting, Files.readAllBytes(file));
keystore.save(env.configFile(), new char[0]);
}

@SuppressForbidden(reason="file arg for cli")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,67 @@ InputStream getStdin() {

@Override
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
KeyStoreWrapper keystore = KeyStoreWrapper.load(env.configFile());
if (keystore == null) {
if (options.has(forceOption) == false &&
terminal.promptYesNo("The elasticsearch keystore does not exist. Do you want to create it?", false) == false) {
terminal.println("Exiting without creating keystore.");
return;
char[] password = null;
char[] passwordVerification = null;
try {
KeyStoreWrapper keystore = KeyStoreWrapper.load(env.configFile());
if (keystore == null) {
if (options.has(forceOption) == false &&
terminal.promptYesNo("The elasticsearch keystore does not exist. Do you want to create it?", false) == false) {
terminal.println("Exiting without creating keystore.");
return;
}
password = terminal.readSecret("Enter passphrase for the elasticsearch keystore (empty for no passphrase): ");
passwordVerification = terminal.readSecret("Enter same passphrase again: ");
if (Arrays.equals(password, passwordVerification) == false) {
throw new UserException(ExitCodes.DATA_ERROR, "Passphrases are not equal, exiting.");
}
keystore = KeyStoreWrapper.create();
keystore.save(env.configFile(), password);
terminal.println("Created elasticsearch keystore in " + env.configFile());
} else {
if (keystore.hasPassword()) {
password = terminal.readSecret("Enter passphrase for the elasticsearch keystore: ");
} else {
password = new char[0];
}
keystore.decrypt(password);
}
keystore = KeyStoreWrapper.create();
keystore.save(env.configFile(), new char[0] /* always use empty passphrase for auto created keystore */);
terminal.println("Created elasticsearch keystore in " + env.configFile());
} else {
keystore.decrypt(new char[0] /* TODO: prompt for password when they are supported */);
}

String setting = arguments.value(options);
if (setting == null) {
throw new UserException(ExitCodes.USAGE, "The setting name can not be null");
}
if (keystore.getSettingNames().contains(setting) && options.has(forceOption) == false) {
if (terminal.promptYesNo("Setting " + setting + " already exists. Overwrite?", false) == false) {
terminal.println("Exiting without modifying keystore.");
return;
String setting = arguments.value(options);
if (setting == null) {
throw new UserException(ExitCodes.USAGE, "The setting name can not be null");
}
if (keystore.getSettingNames().contains(setting) && options.has(forceOption) == false) {
if (terminal.promptYesNo("Setting " + setting + " already exists. Overwrite?", false) == false) {
terminal.println("Exiting without modifying keystore.");
return;
}
}
}

final char[] value;
if (options.has(stdinOption)) {
BufferedReader stdinReader = new BufferedReader(new InputStreamReader(getStdin(), StandardCharsets.UTF_8));
value = stdinReader.readLine().toCharArray();
} else {
value = terminal.readSecret("Enter value for " + setting + ": ");
}
final char[] value;
if (options.has(stdinOption)) {
BufferedReader stdinReader = new BufferedReader(new InputStreamReader(getStdin(), StandardCharsets.UTF_8));
value = stdinReader.readLine().toCharArray();
} else {
value = terminal.readSecret("Enter value for " + setting + ": ");
}

try {
keystore.setString(setting, value);
} catch (IllegalArgumentException e) {
throw new UserException(ExitCodes.DATA_ERROR, "String value must contain only ASCII");
try {
keystore.setString(setting, value);
} catch (IllegalArgumentException e) {
throw new UserException(ExitCodes.DATA_ERROR, "String value must contain only ASCII");
}
keystore.save(env.configFile(), password);
} catch (SecurityException e) {
throw new UserException(ExitCodes.DATA_ERROR, "Failed to access the keystore. Please make sure the passphrase was correct.");
} finally {
if (null != password) {
Arrays.fill(password, '\u0000');
}
if (null != passwordVerification) {
Arrays.fill(passwordVerification, '\u0000');
}
}
keystore.save(env.configFile(), new char[0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;

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;

/**
Expand All @@ -38,24 +41,33 @@ class CreateKeyStoreCommand extends EnvironmentAwareCommand {

@Override
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
Path keystoreFile = KeyStoreWrapper.keystorePath(env.configFile());
if (Files.exists(keystoreFile)) {
if (terminal.promptYesNo("An elasticsearch keystore already exists. Overwrite?", false) == false) {
terminal.println("Exiting without creating keystore.");
return;
char[] password = null;
char[] passwordVerification = null;
try {
Path keystoreFile = KeyStoreWrapper.keystorePath(env.configFile());
if (Files.exists(keystoreFile)) {
if (terminal.promptYesNo("An elasticsearch keystore already exists. Overwrite?", false) == false) {
terminal.println("Exiting without creating keystore.");
return;
}
}
password = terminal.readSecret("Enter passphrase (empty for no passphrase): ");
passwordVerification = terminal.readSecret("Enter same passphrase again: ");
if (Arrays.equals(password, passwordVerification) == false) {
throw new UserException(ExitCodes.DATA_ERROR, "Passphrases are not equal, exiting.");
}
KeyStoreWrapper keystore = KeyStoreWrapper.create();
keystore.save(env.configFile(), password);
terminal.println("Created elasticsearch keystore in " + env.configFile());
} catch (SecurityException e) {
throw new UserException(ExitCodes.IO_ERROR, "Error creating the elasticsearch keystore.", e);
} finally {
if (null != password) {
Arrays.fill(password, '\u0000');
}
if (null != passwordVerification) {
Arrays.fill(passwordVerification, '\u0000');
}
}


char[] password = new char[0];// terminal.readSecret("Enter passphrase (empty for no passphrase): ");
/* TODO: uncomment when entering passwords on startup is supported
char[] passwordRepeat = terminal.readSecret("Enter same passphrase again: ");
if (Arrays.equals(password, passwordRepeat) == false) {
throw new UserException(ExitCodes.DATA_ERROR, "Passphrases are not equal, exiting.");
}*/

KeyStoreWrapper keystore = KeyStoreWrapper.create();
keystore.save(env.configFile(), password);
terminal.println("Created elasticsearch keystore in " + env.configFile());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

Expand All @@ -46,13 +47,23 @@ protected void execute(Terminal terminal, OptionSet options, Environment env) th
if (keystore == null) {
throw new UserException(ExitCodes.DATA_ERROR, "Elasticsearch keystore not found. Use 'create' command to create one.");
}

keystore.decrypt(new char[0] /* TODO: prompt for password when they are supported */);

List<String> sortedEntries = new ArrayList<>(keystore.getSettingNames());
Collections.sort(sortedEntries);
for (String entry : sortedEntries) {
terminal.println(entry);
char[] password;
if (keystore.hasPassword()) {
password = terminal.readSecret("Enter elasticsearch keystore passphrase (empty for no passphrase): ");
} else {
password = new char[0];
}
try {
keystore.decrypt(password);
List<String> sortedEntries = new ArrayList<>(keystore.getSettingNames());
Collections.sort(sortedEntries);
for (String entry : sortedEntries) {
terminal.println(entry);
}
} catch (SecurityException e) {
throw new UserException(ExitCodes.DATA_ERROR, "Failed to access the keystore. Please make sure the passphrase was correct.");
} finally {
Arrays.fill(password, '\u0000');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.elasticsearch.common.settings;

import java.util.Arrays;
import java.util.List;

import joptsimple.OptionSet;
Expand Down Expand Up @@ -52,15 +53,28 @@ protected void execute(Terminal terminal, OptionSet options, Environment env) th
if (keystore == null) {
throw new UserException(ExitCodes.DATA_ERROR, "Elasticsearch keystore not found. Use 'create' command to create one.");
}
char[] password = null;
try {
if (keystore.hasPassword()) {
password = terminal.readSecret("Enter passphrase for the elasticsearch keystore: ");
} else {
password = new char[0];
}
keystore.decrypt(password);

keystore.decrypt(new char[0] /* TODO: prompt for password when they are supported */);

for (String setting : arguments.values(options)) {
if (keystore.getSettingNames().contains(setting) == false) {
throw new UserException(ExitCodes.CONFIG, "Setting [" + setting + "] does not exist in the keystore.");
for (String setting : arguments.values(options)) {
if (keystore.getSettingNames().contains(setting) == false) {
throw new UserException(ExitCodes.CONFIG, "Setting [" + setting + "] does not exist in the keystore.");
}
keystore.remove(setting);
}
keystore.save(env.configFile(), password);
} catch (SecurityException e) {
throw new UserException(ExitCodes.DATA_ERROR, "Failed to access the keystore. Please make sure the passphrase was correct.");
} finally {
if (null != password) {
Arrays.fill(password, '\u0000');
}
keystore.remove(setting);
}
keystore.save(env.configFile(), new char[0]);
}
}
Loading