Fallback to `keystore.seed` as a bootstrap password if actual password is not present (elastic/x-pack-elasticsearch#2295)
Today we require the `bootstrap.password` to be present in the keystore in order to bootstrap xpack. With the addition of `keystore.seed` we have a randomly generated password per node to do the bootstrapping. This will improve the initial user experience significantly since the user doesn't need to create a keystore and add a password, they keystore is created automatically unless already present and is always created with this random seed. Relates to elastic/elasticsearch#26253 Original commit: elastic/x-pack-elasticsearch@5a984b4fd8
This commit is contained in:
parent
2ae5634dc9
commit
724325f161
|
@ -9,6 +9,7 @@ import org.apache.logging.log4j.message.ParameterizedMessage;
|
|||
import org.apache.logging.log4j.util.Supplier;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.settings.KeyStoreWrapper;
|
||||
import org.elasticsearch.common.settings.SecureSetting;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
|
@ -53,7 +54,8 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
public static final Setting<Boolean> ACCEPT_DEFAULT_PASSWORD_SETTING = Setting.boolSetting(
|
||||
Security.setting("authc.accept_default_password"), true, Setting.Property.NodeScope, Setting.Property.Filtered,
|
||||
Setting.Property.Deprecated);
|
||||
public static final Setting<SecureString> BOOTSTRAP_ELASTIC_PASSWORD = SecureSetting.secureString("bootstrap.password", null);
|
||||
public static final Setting<SecureString> BOOTSTRAP_ELASTIC_PASSWORD = SecureSetting.secureString("bootstrap.password",
|
||||
KeyStoreWrapper.SEED_SETTING);
|
||||
|
||||
private final NativeUsersStore nativeUsersStore;
|
||||
private final AnonymousUser anonymousUser;
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.common.Booleans;
|
|||
import org.elasticsearch.common.CheckedFunction;
|
||||
import org.elasticsearch.common.settings.KeyStoreWrapper;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
@ -191,15 +192,16 @@ public class SetupPasswordTool extends MultiCommand {
|
|||
|
||||
void setupOptions(OptionSet options, Environment env) throws Exception {
|
||||
client = clientFunction.apply(env);
|
||||
KeyStoreWrapper keyStore = keyStoreFunction.apply(env);
|
||||
String providedUrl = urlOption.value(options);
|
||||
url = providedUrl == null ? client.getDefaultURL() : providedUrl;
|
||||
setShouldPrompt(options);
|
||||
try (KeyStoreWrapper keyStore = keyStoreFunction.apply(env)) {
|
||||
String providedUrl = urlOption.value(options);
|
||||
url = providedUrl == null ? client.getDefaultURL() : providedUrl;
|
||||
setShouldPrompt(options);
|
||||
|
||||
// TODO: We currently do not support keystore passwords
|
||||
keyStore.decrypt(new char[0]);
|
||||
|
||||
elasticUserPassword = keyStore.getString(ReservedRealm.BOOTSTRAP_ELASTIC_PASSWORD.getKey());
|
||||
// TODO: We currently do not support keystore passwords
|
||||
keyStore.decrypt(new char[0]);
|
||||
Settings build = Settings.builder().setSecureSettings(keyStore).build();
|
||||
elasticUserPassword = ReservedRealm.BOOTSTRAP_ELASTIC_PASSWORD.get(build);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParser() {
|
||||
|
@ -232,7 +234,7 @@ public class SetupPasswordTool extends MultiCommand {
|
|||
|
||||
try {
|
||||
String route = url + "/_xpack/security/user/" + user + "/_password";
|
||||
String response = client.postURL("PUT", route, elasticUser, elasticUserPassword, buildPayload(password));
|
||||
client.postURL("PUT", route, elasticUser, elasticUserPassword, buildPayload(password));
|
||||
callback.accept(user, password);
|
||||
if (isSuperUser) {
|
||||
elasticUserPassword = password;
|
||||
|
|
|
@ -28,6 +28,9 @@ import org.mockito.Mockito;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
@ -41,7 +44,7 @@ import static org.mockito.Mockito.when;
|
|||
public class SetupPasswordToolTests extends CommandTestCase {
|
||||
|
||||
private final String pathHomeParameter = "-Epath.home=" + createTempDir();
|
||||
private SecureString bootstrapPassword = new SecureString("bootstrap-password".toCharArray());
|
||||
private SecureString bootstrapPassword;
|
||||
private final String ep = "elastic-password";
|
||||
private final String kp = "kibana-password";
|
||||
private final String lp = "logstash-password";
|
||||
|
@ -50,9 +53,21 @@ public class SetupPasswordToolTests extends CommandTestCase {
|
|||
|
||||
@Before
|
||||
public void setSecretsAndKeyStore() throws GeneralSecurityException {
|
||||
// sometimes we fall back to the keystore seed as this is the default when a new node starts
|
||||
boolean useFallback = randomBoolean();
|
||||
bootstrapPassword = useFallback ? new SecureString("0xCAFEBABE".toCharArray()) :
|
||||
new SecureString("bootstrap-password".toCharArray());
|
||||
this.keyStore = mock(KeyStoreWrapper.class);
|
||||
this.httpClient = mock(CommandLineHttpClient.class);
|
||||
when(keyStore.getString(ReservedRealm.BOOTSTRAP_ELASTIC_PASSWORD.getKey())).thenReturn(bootstrapPassword);
|
||||
when(keyStore.isLoaded()).thenReturn(true);
|
||||
if (useFallback) {
|
||||
when(keyStore.getSettingNames()).thenReturn(new HashSet<>(Arrays.asList(ReservedRealm.BOOTSTRAP_ELASTIC_PASSWORD.getKey(),
|
||||
KeyStoreWrapper.SEED_SETTING.getKey())));
|
||||
when(keyStore.getString(ReservedRealm.BOOTSTRAP_ELASTIC_PASSWORD.getKey())).thenReturn(bootstrapPassword);
|
||||
} else {
|
||||
when(keyStore.getSettingNames()).thenReturn(Collections.singleton(KeyStoreWrapper.SEED_SETTING.getKey()));
|
||||
when(keyStore.getString(KeyStoreWrapper.SEED_SETTING.getKey())).thenReturn(bootstrapPassword);
|
||||
}
|
||||
when(httpClient.getDefaultURL()).thenReturn("http://localhost:9200");
|
||||
|
||||
terminal.addSecretInput(ep);
|
||||
|
|
|
@ -12,7 +12,6 @@ integTestRunner {
|
|||
|
||||
integTestCluster {
|
||||
plugin ':x-pack-elasticsearch:plugin'
|
||||
keystoreSetting 'bootstrap.password', 'x-pack-test-password'
|
||||
setupCommand 'setupTestAdmin',
|
||||
'bin/x-pack/users', 'useradd', "test_admin", '-p', 'x-pack-test-password', '-r', "superuser"
|
||||
waitCondition = { node, ant ->
|
||||
|
|
Loading…
Reference in New Issue