Skip to content
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

Enforce Transport TLS check on all licenses. #79602

Merged
merged 9 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -16,7 +16,6 @@
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.component.Lifecycle;
Expand All @@ -25,7 +24,6 @@
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateFormatter;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.discovery.DiscoveryModule;
import org.elasticsearch.env.Environment;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
Expand Down Expand Up @@ -243,15 +241,7 @@ public void registerLicense(final PutLicenseRequest request, final ActionListene
// because the defaults there mean that security can be "off", even if the setting is "on"
// BUT basic licenses are explicitly excluded earlier in this method, so we don't need to worry
if (XPackSettings.SECURITY_ENABLED.get(settings)) {
// TODO we should really validate that all nodes have xpack installed and are consistently configured but this
// should happen on a different level and not in this code
if (XPackLicenseState.isTransportTlsRequired(newLicense, settings)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to check TLS transport and security when installing a new license. If transport TLS is not enabled when security is enabled, then we'd have failed to start the node in the first place ( or we will fail when this moves to production mode - but it is not an effect of the license, as the check applies to all licenses now ) .

&& XPackSettings.TRANSPORT_SSL_ENABLED.get(settings) == false
&& isProductionMode(settings, clusterService.localNode())) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also remove isProductionMode and isBoundToLoopback from this class as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes we should, thanks!

// security is on but TLS is not configured we gonna fail the entire request and throw an exception
throw new IllegalStateException("Cannot install a [" + newLicense.operationMode() +
"] license unless TLS is configured or security is disabled");
} else if (XPackSettings.FIPS_MODE_ENABLED.get(settings)
if (XPackSettings.FIPS_MODE_ENABLED.get(settings)
&& false == XPackLicenseState.isFipsAllowedForOperationMode(newLicense.operationMode())) {
throw new IllegalStateException("Cannot install a [" + newLicense.operationMode() +
"] license unless FIPS mode is disabled");
Expand Down Expand Up @@ -583,15 +573,6 @@ static License getLicense(final LicensesMetadata metadata) {
return null;
}

private static boolean isProductionMode(Settings settings, DiscoveryNode localNode) {
final boolean singleNodeDisco = "single-node".equals(DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings));
return singleNodeDisco == false && isBoundToLoopback(localNode) == false;
}

private static boolean isBoundToLoopback(DiscoveryNode localNode) {
return localNode.getAddress().address().getAddress().isLoopbackAddress();
}

private static List<License.LicenseType> getAllowableUploadTypes() {
return Stream.of(License.LicenseType.values())
.filter(t -> t != License.LicenseType.BASIC)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.HeaderWarning;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.license.License.OperationMode;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.XPackSettings;

import java.util.Collections;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -461,25 +459,6 @@ public static boolean isFipsAllowedForOperationMode(final OperationMode operatio
return isAllowedByOperationMode(operationMode, OperationMode.PLATINUM);
}

public static boolean isTransportTlsRequired(License license, Settings settings) {
if (license == null) {
return false;
}
switch (license.operationMode()) {
case STANDARD:
case GOLD:
case PLATINUM:
case ENTERPRISE:
case BASIC:
return XPackSettings.SECURITY_ENABLED.get(settings);
case MISSING:
case TRIAL:
return false;
default:
throw new AssertionError("unknown operation mode [" + license.operationMode() + "]");
}
}

public static boolean isCcrAllowedForOperationMode(final OperationMode operationMode) {
return isAllowedByOperationMode(operationMode, OperationMode.PLATINUM);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.core.ssl;

import org.elasticsearch.bootstrap.BootstrapCheck;
import org.elasticsearch.bootstrap.BootstrapContext;
import org.elasticsearch.xpack.core.XPackSettings;

/**
* Bootstrap check to ensure that if we are starting up with security enabled, transport TLS is enabled
*/
public final class TransportTLSBootstrapCheck implements BootstrapCheck {
@Override
public BootstrapCheckResult check(BootstrapContext context) {
jkakavas marked this conversation as resolved.
Show resolved Hide resolved
assert XPackSettings.SECURITY_ENABLED.get(context.settings())
: "Bootstrap check should not be installed unless security is enabled";
if (XPackSettings.TRANSPORT_SSL_ENABLED.get(context.settings()) == false) {
return BootstrapCheckResult.failure(
"Transport SSL must be enabled if security is enabled. "
+ "Please set [xpack.security.transport.ssl.enabled] to [true] or disable security by setting "
+ "[xpack.security.enabled] to [false]"
);
}
return BootstrapCheckResult.success();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -56,43 +55,6 @@ public void testApplyLicenseInDevMode() throws Exception {
verify(clusterService, times(2)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
}

public void testApplyLicenseInProdMode() throws Exception {
final String licenseType = randomFrom("GOLD", "PLATINUM");
License newLicense = TestUtils.generateSignedLicense(licenseType, TimeValue.timeValueHours(24L));
PutLicenseRequest request = new PutLicenseRequest();
request.acknowledge(true);
request.license(newLicense);
Settings settings = Settings.builder().put("xpack.security.enabled", true).build();
XPackLicenseState licenseState = new XPackLicenseState(() -> 0);
inetAddress = TransportAddress.META_ADDRESS;

setInitialState(null, licenseState, settings);
licenseService.start();
PlainActionFuture<PutLicenseResponse> responseFuture = new PlainActionFuture<>();
IllegalStateException e = expectThrows(IllegalStateException.class, () -> licenseService.registerLicense(request, responseFuture));
assertThat(e.getMessage(),
containsString("Cannot install a [" + licenseType + "] license unless TLS is configured or security is disabled"));

settings = Settings.builder().put("xpack.security.enabled", false).build();
licenseService.stop();
licenseState = new XPackLicenseState(() -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
licenseService.registerLicense(request, responseFuture);
verify(clusterService).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));

settings = Settings.builder()
.put("xpack.security.enabled", true)
.put("xpack.security.transport.ssl.enabled", true)
.build();
licenseService.stop();
licenseState = new XPackLicenseState(() -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
licenseService.registerLicense(request, responseFuture);
verify(clusterService, times(2)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
}

@Override
protected DiscoveryNode getLocalNode() {
return new DiscoveryNode("localnode", new TransportAddress(inetAddress, randomIntBetween(9300, 9399)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,58 +42,6 @@ public void testAcknowledgment() throws Exception {
verify(clusterService, times(1)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
}

public void testRejectUpgradeToProductionWithoutTLS() throws Exception {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
setInitialState(TestUtils.generateSignedLicense("trial", timeValueHours(2)), licenseState, Settings.EMPTY);
licenseService.start();
// try installing a signed license
License signedLicense = TestUtils.generateSignedLicense("platinum", timeValueHours(10));
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(signedLicense);
// ensure acknowledgement message was part of the response
IllegalStateException ise = expectThrows(IllegalStateException.class, () ->
licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(false, LicensesStatus.VALID, true)));
assertEquals("Cannot install a [PLATINUM] license unless TLS is configured or security is disabled", ise.getMessage());
}

public void testUpgradeToProductionWithoutTLSAndSecurityDisabled() throws Exception {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
setInitialState(TestUtils.generateSignedLicense("trial", timeValueHours(2)), licenseState, Settings.builder()
.put("xpack.security.enabled", false).build());
licenseService.start();
// try installing a signed license
License signedLicense = TestUtils.generateSignedLicense("platinum", timeValueHours(10));
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(signedLicense);
licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(false, LicensesStatus.VALID, true));
assertThat(licenseService.getLicense(), not(signedLicense));
verify(clusterService, times(1)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));

// try installing a signed license with acknowledgement
putLicenseRequest = new PutLicenseRequest().license(signedLicense).acknowledge(true);
// ensure license was installed and no acknowledgment message was returned
licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(true, LicensesStatus.VALID, false));
verify(clusterService, times(2)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
}

public void testUpgradeToProductionWithTLSAndSecurity() throws Exception {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
setInitialState(TestUtils.generateSignedLicense("trial", timeValueHours(2)), licenseState, Settings.builder()
.put("xpack.security.enabled", true)
.put("xpack.security.transport.ssl.enabled", true).build());
licenseService.start();
// try installing a signed license
License signedLicense = TestUtils.generateSignedLicense("platinum", timeValueHours(10));
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(signedLicense);
licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(false, LicensesStatus.VALID, true));
assertThat(licenseService.getLicense(), not(signedLicense));
verify(clusterService, times(1)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));

// try installing a signed license with acknowledgement
putLicenseRequest = new PutLicenseRequest().license(signedLicense).acknowledge(true);
// ensure license was installed and no acknowledgment message was returned
licenseService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(true, LicensesStatus.VALID, false));
verify(clusterService, times(2)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
}

private static class AssertingLicensesUpdateResponse implements ActionListener<PutLicenseResponse> {
private final boolean expectedAcknowledgement;
private final LicensesStatus expectedStatus;
Expand Down
Loading