Prevent licenses to be upgraded to production unless TLS is configured (elastic/x-pack-elasticsearch#2502)
if a user tries to upgrade a license to a production license and has security enabled we prevent the upgrade unless TLS is setup. This is a requirement now if a cluster with security is running in prodcution. Relates to elastic/x-pack-elasticsearch#2463 Original commit: elastic/x-pack-elasticsearch@d61ef3bcb1
This commit is contained in:
parent
91b57ee63f
commit
1e14e14571
|
@ -30,6 +30,7 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.gateway.GatewayService;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.scheduler.SchedulerEngine;
|
||||
|
||||
import java.time.Clock;
|
||||
|
@ -207,20 +208,31 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
|
|||
}
|
||||
}
|
||||
}
|
||||
clusterService.submitStateUpdateTask("register license [" + newLicense.uid() + "]", new
|
||||
AckedClusterStateUpdateTask<PutLicenseResponse>(request, listener) {
|
||||
@Override
|
||||
protected PutLicenseResponse newResponse(boolean acknowledged) {
|
||||
return new PutLicenseResponse(acknowledged, LicensesStatus.VALID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterState execute(ClusterState currentState) throws Exception {
|
||||
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
||||
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(newLicense));
|
||||
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
||||
}
|
||||
});
|
||||
if (newLicense.isProductionLicense()
|
||||
&& XPackSettings.SECURITY_ENABLED.get(settings)
|
||||
&& XPackSettings.TRANSPORT_SSL_ENABLED.get(settings) == false) {
|
||||
// security is on but TLS is not configured we gonna fail the entire request and throw an exception
|
||||
throw new IllegalStateException("Can not upgrade to a production license unless TLS is configured or " +
|
||||
"security is disabled");
|
||||
// TODO we should really validate that all nodes have xpack in stalled and are consistently configured but this
|
||||
// should happen on a different level and not in this code
|
||||
} else {
|
||||
clusterService.submitStateUpdateTask("register license [" + newLicense.uid() + "]", new
|
||||
AckedClusterStateUpdateTask<PutLicenseResponse>(request, listener) {
|
||||
@Override
|
||||
protected PutLicenseResponse newResponse(boolean acknowledged) {
|
||||
return new PutLicenseResponse(acknowledged, LicensesStatus.VALID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterState execute(ClusterState currentState) throws Exception {
|
||||
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
||||
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(newLicense));
|
||||
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,11 +48,11 @@ public abstract class AbstractLicenseServiceTestCase extends ESTestCase {
|
|||
environment = mock(Environment.class);
|
||||
}
|
||||
|
||||
protected void setInitialState(License license, XPackLicenseState licenseState) {
|
||||
protected void setInitialState(License license, XPackLicenseState licenseState, Settings settings) {
|
||||
Path tempDir = createTempDir();
|
||||
when(environment.configFile()).thenReturn(tempDir);
|
||||
licenseType = randomBoolean() ? "trial" : "basic";
|
||||
Settings settings = Settings.builder().put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), licenseType).build();
|
||||
settings = Settings.builder().put(settings).put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), licenseType).build();
|
||||
licenseService = new LicenseService(settings, clusterService, clock, environment, resourceWatcherService, licenseState);
|
||||
ClusterState state = mock(ClusterState.class);
|
||||
final ClusterBlocks noBlock = ClusterBlocks.builder().build();
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
|||
import org.elasticsearch.cluster.metadata.MetaData;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -33,7 +34,7 @@ public class LicenseClusterChangeTests extends AbstractLicenseServiceTestCase {
|
|||
@Before
|
||||
public void setup() {
|
||||
licenseState = new TestUtils.AssertingLicenseState();
|
||||
setInitialState(null, licenseState);
|
||||
setInitialState(null, licenseState, Settings.EMPTY);
|
||||
licenseService.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.license;
|
|||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
|
@ -19,7 +20,7 @@ public class LicenseRegistrationTests extends AbstractLicenseServiceTestCase {
|
|||
|
||||
public void testTrialLicenseRequestOnEmptyLicenseState() throws Exception {
|
||||
XPackLicenseState licenseState = new XPackLicenseState();
|
||||
setInitialState(null, licenseState);
|
||||
setInitialState(null, licenseState, Settings.EMPTY);
|
||||
when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(true);
|
||||
licenseService.start();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.license;
|
|||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -20,7 +21,7 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
|
|||
public void testAcknowledgment() throws Exception {
|
||||
|
||||
XPackLicenseState licenseState = new XPackLicenseState();
|
||||
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)), licenseState);
|
||||
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)), licenseState, Settings.EMPTY);
|
||||
licenseService.start();
|
||||
// try installing a signed license
|
||||
License signedLicense = TestUtils.generateSignedLicense("basic", TimeValue.timeValueHours(10));
|
||||
|
@ -37,6 +38,58 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
|
|||
verify(clusterService, times(1)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
|
||||
}
|
||||
|
||||
public void testRejectUpgradeToProductionWithoutTLS() throws Exception {
|
||||
XPackLicenseState licenseState = new XPackLicenseState();
|
||||
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)), licenseState, Settings.EMPTY);
|
||||
licenseService.start();
|
||||
// try installing a signed license
|
||||
License signedLicense = TestUtils.generateSignedLicense("platinum", TimeValue.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("Can not upgrade to a production license unless TLS is configured or security is disabled", ise.getMessage());
|
||||
}
|
||||
|
||||
public void testUpgradeToProductionWithoutTLSAndSecurityDisabled() throws Exception {
|
||||
XPackLicenseState licenseState = new XPackLicenseState();
|
||||
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)), licenseState, Settings.builder()
|
||||
.put("xpack.security.enabled", false).build());
|
||||
licenseService.start();
|
||||
// try installing a signed license
|
||||
License signedLicense = TestUtils.generateSignedLicense("platinum", TimeValue.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 = new XPackLicenseState();
|
||||
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.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", TimeValue.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;
|
||||
|
|
Loading…
Reference in New Issue