Skip to content

Commit 65b6179

Browse files
tvernumjasontedor
authored andcommitted
Enforce transport TLS on Basic with Security (#42150)
If a basic license enables security, then we should also enforce TLS on the transport interface. This was already the case for Standard/Gold/Platinum licenses. For Basic, security defaults to disabled, so some of the process around checking whether security is actuallY enabled is more complex now that we need to account for basic licenses.
1 parent 6fe747f commit 65b6179

File tree

7 files changed

+174
-67
lines changed

7 files changed

+174
-67
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/license/License.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -772,22 +772,4 @@ public Builder validate() {
772772
}
773773
}
774774

775-
/**
776-
* Returns <code>true</code> iff the license is a production licnese
777-
*/
778-
public boolean isProductionLicense() {
779-
switch (operationMode()) {
780-
case MISSING:
781-
case TRIAL:
782-
case BASIC:
783-
return false;
784-
case STANDARD:
785-
case GOLD:
786-
case PLATINUM:
787-
return true;
788-
default:
789-
throw new AssertionError("unknown operation mode: " + operationMode());
790-
791-
}
792-
}
793775
}

x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicenseService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,13 @@ public void registerLicense(final PutLicenseRequest request, final ActionListene
214214
}
215215
}
216216

217+
// This check would be incorrect if "basic" licenses were allowed here
218+
// because the defaults there mean that security can be "off", even if the setting is "on"
219+
// BUT basic licenses are explicitly excluded earlier in this method, so we don't need to worry
217220
if (XPackSettings.SECURITY_ENABLED.get(settings)) {
218221
// TODO we should really validate that all nodes have xpack installed and are consistently configured but this
219222
// should happen on a different level and not in this code
220-
if (newLicense.isProductionLicense()
223+
if (XPackLicenseState.isTransportTlsRequired(newLicense, settings)
221224
&& XPackSettings.TRANSPORT_SSL_ENABLED.get(settings) == false
222225
&& isProductionMode(settings, clusterService.localNode())) {
223226
// security is on but TLS is not configured we gonna fail the entire request and throw an exception

x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ private static class Status {
276276
}
277277
}
278278

279-
private final Logger logger;
280-
private final DeprecationLogger deprecationLogger;
279+
private static final Logger logger = LogManager.getLogger(XPackLicenseState.class);
280+
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
281281
private final List<LicenseStateListener> listeners;
282282

283283
private final boolean isSecurityEnabled;
@@ -287,8 +287,6 @@ private static class Status {
287287
private boolean isSecurityEnabledByTrialVersion;
288288

289289
public XPackLicenseState(Settings settings) {
290-
this.logger = LogManager.getLogger(getClass());
291-
this.deprecationLogger = new DeprecationLogger(logger);
292290
this.listeners = new CopyOnWriteArrayList<>();
293291
this.isSecurityEnabled = XPackSettings.SECURITY_ENABLED.get(settings);
294292
this.isSecurityExplicitlyEnabled = checkSecurityExplicitlyEnabled(settings);
@@ -301,8 +299,8 @@ public XPackLicenseState(Settings settings) {
301299
* setting is not explicitly set.
302300
* This behaviour is deprecated, and will be removed in 7.0
303301
*/
304-
private boolean checkSecurityExplicitlyEnabled(Settings settings) {
305-
if (isSecurityEnabled) {
302+
private static boolean checkSecurityExplicitlyEnabled(Settings settings) {
303+
if (XPackSettings.SECURITY_ENABLED.get(settings)) {
306304
if (settings.hasValue(XPackSettings.SECURITY_ENABLED.getKey())) {
307305
return true;
308306
}
@@ -324,8 +322,6 @@ private XPackLicenseState(XPackLicenseState xPackLicenseState) {
324322
this.isSecurityExplicitlyEnabled = xPackLicenseState.isSecurityExplicitlyEnabled;
325323
this.status = xPackLicenseState.status;
326324
this.isSecurityEnabledByTrialVersion = xPackLicenseState.isSecurityEnabledByTrialVersion;
327-
this.logger = xPackLicenseState.logger;
328-
this.deprecationLogger = xPackLicenseState.deprecationLogger;
329325
}
330326

331327
/**
@@ -770,6 +766,25 @@ public synchronized boolean isSecurityDisabledByLicenseDefaults() {
770766
return false;
771767
}
772768

769+
public static boolean isTransportTlsRequired(License license, Settings settings) {
770+
if (license == null) {
771+
return false;
772+
}
773+
switch (license.operationMode()) {
774+
case STANDARD:
775+
case GOLD:
776+
case PLATINUM:
777+
return XPackSettings.SECURITY_ENABLED.get(settings);
778+
case BASIC:
779+
return XPackSettings.SECURITY_ENABLED.get(settings) && checkSecurityExplicitlyEnabled(settings);
780+
case MISSING:
781+
case TRIAL:
782+
return false;
783+
default:
784+
throw new AssertionError("unknown operation mode [" + license.operationMode() + "]");
785+
}
786+
}
787+
773788
private static boolean isSecurityEnabled(final OperationMode mode, final boolean isSecurityExplicitlyEnabled,
774789
final boolean isSecurityEnabledByTrialVersion, final boolean isSecurityEnabled) {
775790
switch (mode) {

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/TLSLicenseBootstrapCheck.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.elasticsearch.bootstrap.BootstrapContext;
1010
import org.elasticsearch.license.License;
1111
import org.elasticsearch.license.LicenseService;
12+
import org.elasticsearch.license.XPackLicenseState;
1213
import org.elasticsearch.xpack.core.XPackSettings;
1314

1415
/**
@@ -19,10 +20,11 @@ public final class TLSLicenseBootstrapCheck implements BootstrapCheck {
1920
public BootstrapCheckResult check(BootstrapContext context) {
2021
if (XPackSettings.TRANSPORT_SSL_ENABLED.get(context.settings()) == false) {
2122
License license = LicenseService.getLicense(context.metaData());
22-
if (license != null && license.isProductionLicense()) {
23-
return BootstrapCheckResult.failure("Transport SSL must be enabled for setups with production licenses. Please set " +
24-
"[xpack.security.transport.ssl.enabled] to [true] or disable security by setting [xpack.security.enabled] " +
25-
"to [false]");
23+
if (XPackLicenseState.isTransportTlsRequired(license, context.settings())) {
24+
return BootstrapCheckResult.failure("Transport SSL must be enabled if security is enabled on a [" +
25+
license.operationMode().description() + "] license. " +
26+
"Please set [xpack.security.transport.ssl.enabled] to [true] or disable security by setting " +
27+
"[xpack.security.enabled] to [false]");
2628
}
2729
}
2830
return BootstrapCheckResult.success();

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ssl/TLSLicenseBootstrapCheckTests.java

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,115 @@
55
*/
66
package org.elasticsearch.xpack.core.ssl;
77

8+
import org.elasticsearch.bootstrap.BootstrapCheck;
9+
import org.elasticsearch.bootstrap.BootstrapContext;
810
import org.elasticsearch.cluster.metadata.MetaData;
911
import org.elasticsearch.common.settings.Settings;
1012
import org.elasticsearch.common.unit.TimeValue;
1113
import org.elasticsearch.license.License;
14+
import org.elasticsearch.license.License.OperationMode;
1215
import org.elasticsearch.license.TestUtils;
1316
import org.elasticsearch.test.AbstractBootstrapCheckTestCase;
1417

15-
import java.util.EnumSet;
16-
1718
public class TLSLicenseBootstrapCheckTests extends AbstractBootstrapCheckTestCase {
18-
public void testBootstrapCheck() throws Exception {
19+
public void testBootstrapCheckOnEmptyMetadata() {
1920
assertTrue(new TLSLicenseBootstrapCheck().check(emptyContext).isSuccess());
2021
assertTrue(new TLSLicenseBootstrapCheck().check(createTestContext(Settings.builder().put("xpack.security.transport.ssl.enabled"
21-
, randomBoolean()).build(), MetaData.EMPTY_META_DATA)).isSuccess());
22-
int numIters = randomIntBetween(1,10);
23-
for (int i = 0; i < numIters; i++) {
24-
License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24));
25-
EnumSet<License.OperationMode> productionModes = EnumSet.of(License.OperationMode.GOLD, License.OperationMode.PLATINUM,
26-
License.OperationMode.STANDARD);
27-
MetaData.Builder builder = MetaData.builder();
28-
TestUtils.putLicense(builder, license);
29-
MetaData build = builder.build();
30-
if (productionModes.contains(license.operationMode()) == false) {
31-
assertTrue(new TLSLicenseBootstrapCheck().check(createTestContext(
32-
Settings.builder().put("xpack.security.transport.ssl.enabled", true).build(), build)).isSuccess());
33-
} else {
34-
assertTrue(new TLSLicenseBootstrapCheck().check(createTestContext(
35-
Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(), build)).isFailure());
36-
assertEquals("Transport SSL must be enabled for setups with production licenses. Please set " +
37-
"[xpack.security.transport.ssl.enabled] to [true] or disable security by setting " +
38-
"[xpack.security.enabled] to [false]",
39-
new TLSLicenseBootstrapCheck().check(createTestContext(
40-
Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(), build)).getMessage());
41-
}
22+
, randomBoolean()).build(), MetaData.EMPTY_META_DATA)).isSuccess());
23+
}
24+
25+
public void testBootstrapCheckFailureOnPremiumLicense() throws Exception {
26+
final OperationMode mode = randomFrom(OperationMode.PLATINUM, OperationMode.GOLD, OperationMode.STANDARD);
27+
final Settings.Builder settings = Settings.builder();
28+
if (randomBoolean()) {
29+
// randomise between default-false & explicit-false
30+
settings.put("xpack.security.transport.ssl.enabled", false);
31+
}
32+
if (randomBoolean()) {
33+
// randomise between default-true & explicit-true
34+
settings.put("xpack.security.enabled", true);
35+
}
36+
37+
final BootstrapCheck.BootstrapCheckResult result = runBootstrapCheck(mode, settings);
38+
assertTrue("Expected bootstrap failure", result.isFailure());
39+
assertEquals("Transport SSL must be enabled if security is enabled on a [" + mode.description() + "] license. Please set " +
40+
"[xpack.security.transport.ssl.enabled] to [true] or disable security by setting " +
41+
"[xpack.security.enabled] to [false]",
42+
result.getMessage());
43+
}
44+
45+
public void testBootstrapCheckSucceedsWithTlsEnabledOnPremiumLicense() throws Exception {
46+
final OperationMode mode = randomFrom(OperationMode.PLATINUM, OperationMode.GOLD, OperationMode.STANDARD);
47+
final Settings.Builder settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true);
48+
final BootstrapCheck.BootstrapCheckResult result = runBootstrapCheck(mode, settings);
49+
assertSuccess(result);
50+
}
51+
52+
public void testBootstrapCheckFailureOnBasicLicense() throws Exception {
53+
final Settings.Builder settings = Settings.builder().put("xpack.security.enabled", true);
54+
if (randomBoolean()) {
55+
// randomise between default-false & explicit-false
56+
settings.put("xpack.security.transport.ssl.enabled", false);
57+
}
58+
final BootstrapCheck.BootstrapCheckResult result = runBootstrapCheck(OperationMode.BASIC, settings);
59+
assertTrue("Expected bootstrap failure", result.isFailure());
60+
assertEquals("Transport SSL must be enabled if security is enabled on a [basic] license. Please set " +
61+
"[xpack.security.transport.ssl.enabled] to [true] or disable security by setting " +
62+
"[xpack.security.enabled] to [false]",
63+
result.getMessage());
64+
}
65+
66+
public void testBootstrapSucceedsIfSecurityIsNotEnabledOnBasicLicense() throws Exception {
67+
final Settings.Builder settings = Settings.builder();
68+
if (randomBoolean()) {
69+
// randomise between default-false & explicit-false
70+
settings.put("xpack.security.enabled", false);
71+
}
72+
if (randomBoolean()) {
73+
// it does not matter whether or not this is set, as security is not enabled.
74+
settings.put("xpack.security.transport.ssl.enabled", randomBoolean());
4275
}
76+
final BootstrapCheck.BootstrapCheckResult result = runBootstrapCheck(OperationMode.BASIC, settings);
77+
assertSuccess(result);
4378
}
79+
80+
public void testBootstrapSucceedsIfTlsIsEnabledOnBasicLicense() throws Exception {
81+
final Settings.Builder settings = Settings.builder().put("xpack.security.transport.ssl.enabled", true);
82+
if (randomBoolean()) {
83+
// it does not matter whether or not this is set, as TLS is enabled.
84+
settings.put("xpack.security.enabled", randomBoolean());
85+
}
86+
final BootstrapCheck.BootstrapCheckResult result = runBootstrapCheck(OperationMode.BASIC, settings);
87+
assertSuccess(result);
88+
}
89+
90+
public void testBootstrapCheckAlwaysSucceedsOnTrialLicense() throws Exception {
91+
final Settings.Builder settings = Settings.builder();
92+
if (randomBoolean()) {
93+
// it does not matter whether this is set, or to which value.
94+
settings.put("xpack.security.enabled", randomBoolean());
95+
}
96+
if (randomBoolean()) {
97+
// it does not matter whether this is set, or to which value.
98+
settings.put("xpack.security.transport.ssl.enabled", randomBoolean());
99+
}
100+
final BootstrapCheck.BootstrapCheckResult result = runBootstrapCheck(OperationMode.TRIAL, settings);
101+
assertSuccess(result);
102+
}
103+
104+
public BootstrapCheck.BootstrapCheckResult runBootstrapCheck(OperationMode mode, Settings.Builder settings) throws Exception {
105+
final License license = TestUtils.generateSignedLicense(mode.description(), TimeValue.timeValueHours(24));
106+
MetaData.Builder builder = MetaData.builder();
107+
TestUtils.putLicense(builder, license);
108+
MetaData metaData = builder.build();
109+
final BootstrapContext context = createTestContext(settings.build(), metaData);
110+
return new TLSLicenseBootstrapCheck().check(context);
111+
}
112+
113+
public void assertSuccess(BootstrapCheck.BootstrapCheckResult result) {
114+
if (result.isFailure()) {
115+
fail("Bootstrap check failed unexpectedly: " + result.getMessage());
116+
}
117+
}
118+
44119
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,7 @@ public Function<String, Predicate<String>> getFieldFilter() {
11801180
public BiConsumer<DiscoveryNode, ClusterState> getJoinValidator() {
11811181
if (enabled) {
11821182
return new ValidateTLSOnJoin(XPackSettings.TRANSPORT_SSL_ENABLED.get(settings),
1183-
DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings))
1183+
DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings), settings)
11841184
.andThen(new ValidateUpgradedSecurityIndex())
11851185
.andThen(new ValidateLicenseCanBeDeserialized())
11861186
.andThen(new ValidateLicenseForFIPS(XPackSettings.FIPS_MODE_ENABLED.get(settings)));
@@ -1191,18 +1191,21 @@ public BiConsumer<DiscoveryNode, ClusterState> getJoinValidator() {
11911191
static final class ValidateTLSOnJoin implements BiConsumer<DiscoveryNode, ClusterState> {
11921192
private final boolean isTLSEnabled;
11931193
private final String discoveryType;
1194+
private final Settings settings;
11941195

1195-
ValidateTLSOnJoin(boolean isTLSEnabled, String discoveryType) {
1196+
ValidateTLSOnJoin(boolean isTLSEnabled, String discoveryType, Settings settings) {
11961197
this.isTLSEnabled = isTLSEnabled;
11971198
this.discoveryType = discoveryType;
1199+
this.settings = settings;
11981200
}
11991201

12001202
@Override
12011203
public void accept(DiscoveryNode node, ClusterState state) {
12021204
License license = LicenseService.getLicense(state.metaData());
1203-
if (license != null && license.isProductionLicense() &&
1204-
isTLSEnabled == false && "single-node".equals(discoveryType) == false) {
1205-
throw new IllegalStateException("TLS setup is required for license type [" + license.operationMode().name() + "]");
1205+
if (isTLSEnabled == false && "single-node".equals(discoveryType) == false
1206+
&& XPackLicenseState.isTransportTlsRequired(license, settings)) {
1207+
throw new IllegalStateException("Transport TLS ([" + XPackSettings.TRANSPORT_SSL_ENABLED.getKey() +
1208+
"]) is required for license type [" + license.operationMode().description() + "] when security is enabled");
12061209
}
12071210
}
12081211
}

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
import java.util.Arrays;
5858
import java.util.Collection;
5959
import java.util.Collections;
60-
import java.util.EnumSet;
6160
import java.util.HashMap;
6261
import java.util.HashSet;
6362
import java.util.List;
@@ -276,17 +275,45 @@ public void testTLSJoinValidator() throws Exception {
276275
int numIters = randomIntBetween(1,10);
277276
for (int i = 0; i < numIters; i++) {
278277
boolean tlsOn = randomBoolean();
278+
boolean securityExplicitlyEnabled = randomBoolean();
279279
String discoveryType = randomFrom("single-node", "zen", randomAlphaOfLength(4));
280-
Security.ValidateTLSOnJoin validator = new Security.ValidateTLSOnJoin(tlsOn, discoveryType);
280+
281+
final Settings settings;
282+
if (securityExplicitlyEnabled) {
283+
settings = Settings.builder().put("xpack.security.enabled", true).build();
284+
} else {
285+
settings = Settings.EMPTY;
286+
}
287+
Security.ValidateTLSOnJoin validator = new Security.ValidateTLSOnJoin(tlsOn, discoveryType, settings);
281288
MetaData.Builder builder = MetaData.builder();
282-
License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24));
289+
License.OperationMode licenseMode = randomFrom(License.OperationMode.values());
290+
License license = TestUtils.generateSignedLicense(licenseMode.description(), TimeValue.timeValueHours(24));
283291
TestUtils.putLicense(builder, license);
284292
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(builder.build()).build();
285-
EnumSet<License.OperationMode> productionModes = EnumSet.of(License.OperationMode.GOLD, License.OperationMode.PLATINUM,
286-
License.OperationMode.STANDARD);
287-
if (productionModes.contains(license.operationMode()) && tlsOn == false && "single-node".equals(discoveryType) == false) {
293+
294+
final boolean expectFailure;
295+
switch (licenseMode) {
296+
case PLATINUM:
297+
case GOLD:
298+
case STANDARD:
299+
expectFailure = tlsOn == false && "single-node".equals(discoveryType) == false;
300+
break;
301+
case BASIC:
302+
expectFailure = tlsOn == false && "single-node".equals(discoveryType) == false && securityExplicitlyEnabled;
303+
break;
304+
case MISSING:
305+
case TRIAL:
306+
expectFailure = false;
307+
break;
308+
default:
309+
throw new AssertionError("unknown operation mode [" + license.operationMode() + "]");
310+
}
311+
logger.info("Test TLS join; Lic:{} TLS:{} Disco:{} Settings:{} ; Expect Failure: {}",
312+
licenseMode, tlsOn, discoveryType, settings.toDelimitedString(','), expectFailure);
313+
if (expectFailure) {
288314
IllegalStateException ise = expectThrows(IllegalStateException.class, () -> validator.accept(node, state));
289-
assertEquals("TLS setup is required for license type [" + license.operationMode().name() + "]", ise.getMessage());
315+
assertEquals("Transport TLS ([xpack.security.transport.ssl.enabled]) is required for license type ["
316+
+ license.operationMode().description() + "] when security is enabled", ise.getMessage());
290317
} else {
291318
validator.accept(node, state);
292319
}

0 commit comments

Comments
 (0)