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.
Startup check for security implicit behavior change (elastic#76879)
In the security ON by default project, we introduced a breaking change for the xpack.security.enabled setting. While we do expose necessary deprecation warnings and release notes, there might still be a case where a deployment that is - On basic or trial license with `xpack.security.enabled` not set - A single node cluster or a multi-node, single-host cluster gets upgraded to 8.x in place without using the Upgrade Assistant or consulting the release notes. In this case, we elect to stop the node from starting via a newly introduced BootstrapCheck, so that we can notify the user that the implicit behavior for security has changed. If we don't do that, the upgrade can seemingly succeed but the user will have no way to interact with the upgraded cluster as security is enabled and they have no credentials. This is a best effort check in the sense that: - LicenseState might not be correct that early in the node lifecycle, so we might not be able to know if this node was on basic/trial - A grow-and-shrink upgrade would bypass this check since new nodes start with empty state on disk - A user might change the configuration and remove the explicit xpack.security.enabled configuration _while_ upgrading the node to 8.x
- Loading branch information
Showing
8 changed files
with
221 additions
and
19 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
58 changes: 58 additions & 0 deletions
58
...rc/main/java/org/elasticsearch/xpack/security/SecurityImplicitBehaviorBootstrapCheck.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,58 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.security; | ||
|
||
import org.elasticsearch.Version; | ||
import org.elasticsearch.bootstrap.BootstrapCheck; | ||
import org.elasticsearch.bootstrap.BootstrapContext; | ||
import org.elasticsearch.env.NodeMetadata; | ||
import org.elasticsearch.license.License; | ||
import org.elasticsearch.license.LicenseService; | ||
import org.elasticsearch.xpack.core.XPackSettings; | ||
|
||
public class SecurityImplicitBehaviorBootstrapCheck implements BootstrapCheck { | ||
|
||
private final NodeMetadata nodeMetadata; | ||
|
||
public SecurityImplicitBehaviorBootstrapCheck(NodeMetadata nodeMetadata) { | ||
this.nodeMetadata = nodeMetadata; | ||
} | ||
|
||
@Override | ||
public BootstrapCheckResult check(BootstrapContext context) { | ||
if (nodeMetadata == null) { | ||
return BootstrapCheckResult.success(); | ||
} | ||
final License license = LicenseService.getLicense(context.metadata()); | ||
final Version lastKnownVersion = nodeMetadata.previousNodeVersion(); | ||
// pre v7.2.0 nodes have Version.EMPTY and its id is 0, so Version#before handles this successfully | ||
if (lastKnownVersion.before(Version.V_8_0_0) | ||
&& XPackSettings.SECURITY_ENABLED.exists(context.settings()) == false | ||
&& (license.operationMode() == License.OperationMode.BASIC || license.operationMode() == License.OperationMode.TRIAL)) { | ||
return BootstrapCheckResult.failure( | ||
"The default value for [" | ||
+ XPackSettings.SECURITY_ENABLED.getKey() | ||
+ "] has changed in the current version. " | ||
+ " Security features were implicitly disabled for this node but they would now be enabled, possibly" | ||
+ " preventing access to the node. " | ||
+ "See https://www.elastic.co/guide/en/elasticsearch/reference/" | ||
+ Version.CURRENT.major | ||
+ "." | ||
+ Version.CURRENT.minor | ||
+ "/security-minimal-setup.html to configure security, or explicitly disable security by " | ||
+ "setting [xpack.security.enabled] to \"false\" in elasticsearch.yml before restarting the node." | ||
); | ||
} else { | ||
return BootstrapCheckResult.success(); | ||
} | ||
} | ||
|
||
public boolean alwaysEnforce() { | ||
return true; | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
...st/java/org/elasticsearch/xpack/security/SecurityImplicitBehaviorBootstrapCheckTests.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,104 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.security; | ||
|
||
import org.elasticsearch.Version; | ||
import org.elasticsearch.bootstrap.BootstrapCheck; | ||
import org.elasticsearch.cluster.metadata.Metadata; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.core.TimeValue; | ||
import org.elasticsearch.env.NodeMetadata; | ||
import org.elasticsearch.license.License; | ||
import org.elasticsearch.license.LicensesMetadata; | ||
import org.elasticsearch.license.TestUtils; | ||
import org.elasticsearch.test.AbstractBootstrapCheckTestCase; | ||
import org.elasticsearch.test.VersionUtils; | ||
import org.elasticsearch.xpack.core.XPackSettings; | ||
|
||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.is; | ||
|
||
public class SecurityImplicitBehaviorBootstrapCheckTests extends AbstractBootstrapCheckTestCase { | ||
|
||
public void testFailureUpgradeFrom7xWithImplicitSecuritySettings() throws Exception { | ||
final Version previousVersion = VersionUtils.randomVersionBetween(random(), Version.V_7_2_0, Version.V_7_16_0); | ||
NodeMetadata nodeMetadata = new NodeMetadata(randomAlphaOfLength(10), previousVersion); | ||
nodeMetadata = nodeMetadata.upgradeToCurrentVersion(); | ||
BootstrapCheck.BootstrapCheckResult result = new SecurityImplicitBehaviorBootstrapCheck(nodeMetadata).check( | ||
createTestContext(Settings.EMPTY, createLicensesMetadata(previousVersion, randomFrom("basic", "trial"))) | ||
); | ||
assertThat(result.isFailure(), is(true)); | ||
assertThat( | ||
result.getMessage(), | ||
equalTo( | ||
"The default value for [" | ||
+ XPackSettings.SECURITY_ENABLED.getKey() | ||
+ "] has changed in the current version. " | ||
+ " Security features were implicitly disabled for this node but they would now be enabled, possibly" | ||
+ " preventing access to the node. " | ||
+ "See https://www.elastic.co/guide/en/elasticsearch/reference/" | ||
+ Version.CURRENT.major | ||
+ "." | ||
+ Version.CURRENT.minor | ||
+ "/security-minimal-setup.html to configure security, or explicitly disable security by " | ||
+ "setting [xpack.security.enabled] to \"false\" in elasticsearch.yml before restarting the node." | ||
) | ||
); | ||
} | ||
|
||
public void testUpgradeFrom7xWithImplicitSecuritySettingsOnGoldPlus() throws Exception { | ||
final Version previousVersion = VersionUtils.randomVersionBetween(random(), Version.V_7_2_0, Version.V_7_16_0); | ||
NodeMetadata nodeMetadata = new NodeMetadata(randomAlphaOfLength(10), previousVersion); | ||
nodeMetadata = nodeMetadata.upgradeToCurrentVersion(); | ||
BootstrapCheck.BootstrapCheckResult result = new SecurityImplicitBehaviorBootstrapCheck(nodeMetadata).check( | ||
createTestContext(Settings.EMPTY, createLicensesMetadata(previousVersion, randomFrom("gold", "platinum"))) | ||
); | ||
assertThat(result.isSuccess(), is(true)); | ||
} | ||
|
||
public void testUpgradeFrom7xWithExplicitSecuritySettings() throws Exception { | ||
final Version previousVersion = VersionUtils.randomVersionBetween(random(), Version.V_7_2_0, Version.V_7_16_0); | ||
NodeMetadata nodeMetadata = new NodeMetadata(randomAlphaOfLength(10), previousVersion); | ||
nodeMetadata = nodeMetadata.upgradeToCurrentVersion(); | ||
BootstrapCheck.BootstrapCheckResult result = new SecurityImplicitBehaviorBootstrapCheck(nodeMetadata).check( | ||
createTestContext( | ||
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build(), | ||
createLicensesMetadata(previousVersion, randomFrom("basic", "trial")) | ||
) | ||
); | ||
assertThat(result.isSuccess(), is(true)); | ||
} | ||
|
||
public void testUpgradeFrom8xWithImplicitSecuritySettings() throws Exception { | ||
final Version previousVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_0_0, null); | ||
NodeMetadata nodeMetadata = new NodeMetadata(randomAlphaOfLength(10), previousVersion); | ||
nodeMetadata = nodeMetadata.upgradeToCurrentVersion(); | ||
BootstrapCheck.BootstrapCheckResult result = new SecurityImplicitBehaviorBootstrapCheck(nodeMetadata).check( | ||
createTestContext(Settings.EMPTY, createLicensesMetadata(previousVersion, randomFrom("basic", "trial"))) | ||
); | ||
assertThat(result.isSuccess(), is(true)); | ||
} | ||
|
||
public void testUpgradeFrom8xWithExplicitSecuritySettings() throws Exception { | ||
final Version previousVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_0_0, null); | ||
NodeMetadata nodeMetadata = new NodeMetadata(randomAlphaOfLength(10), previousVersion); | ||
nodeMetadata = nodeMetadata.upgradeToCurrentVersion(); | ||
BootstrapCheck.BootstrapCheckResult result = new SecurityImplicitBehaviorBootstrapCheck(nodeMetadata).check( | ||
createTestContext( | ||
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build(), | ||
createLicensesMetadata(previousVersion, randomFrom("basic", "trial")) | ||
) | ||
); | ||
assertThat(result.isSuccess(), is(true)); | ||
} | ||
|
||
private Metadata createLicensesMetadata(Version version, String licenseMode) throws Exception { | ||
License license = TestUtils.generateSignedLicense(licenseMode, TimeValue.timeValueHours(2)); | ||
return Metadata.builder().putCustom(LicensesMetadata.TYPE, new LicensesMetadata(license, version)).build(); | ||
} | ||
} |
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