From 0680e41f36b3a179b5a2238a03c85f4118e4524a Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Wed, 13 Sep 2017 20:40:35 +0200 Subject: [PATCH 1/9] Prevent nodes from joining a non-TLS enabled cluster with a production license (elastic/x-pack-elasticsearch#2484) This change prevents a node from joining a cluster with a production license (gold, platinum, standard) iff the cluster doesn't have TLS setup. This is mainly a BWC oriented change that prevents joining old 5.x clusters without a TLS setup. Relates to elastic/x-pack-elasticsearch#2463 Original commit: elastic/x-pack-elasticsearch@21f5a584728de5e55601c1a918965ba8d05964d6 --- .../elasticsearch/license/LicenseService.java | 9 +++- .../org/elasticsearch/xpack/XPackPlugin.java | 10 +++- .../elasticsearch/xpack/XPackSettings.java | 2 +- .../xpack/security/Security.java | 50 ++++++++++++++++++- .../license/LicensesManagerServiceTests.java | 6 +-- .../xpack/security/SecurityTests.java | 41 +++++++++++++++ 6 files changed, 109 insertions(+), 9 deletions(-) diff --git a/plugin/src/main/java/org/elasticsearch/license/LicenseService.java b/plugin/src/main/java/org/elasticsearch/license/LicenseService.java index 189e7922483..271bd642b76 100644 --- a/plugin/src/main/java/org/elasticsearch/license/LicenseService.java +++ b/plugin/src/main/java/org/elasticsearch/license/LicenseService.java @@ -271,7 +271,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste } public License getLicense() { - final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE)); + final License license = getLicense(clusterService.state()); return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license; } @@ -469,7 +469,12 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste }; } - License getLicense(final LicensesMetaData metaData) { + public static License getLicense(final ClusterState state) { + final LicensesMetaData licensesMetaData = state.metaData().custom(LicensesMetaData.TYPE); + return getLicense(licensesMetaData); + } + + static License getLicense(final LicensesMetaData metaData) { if (metaData != null) { License license = metaData.getLicense(); if (license == LicensesMetaData.LICENSE_TOMBSTONE) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index 8f6ffa1f78b..caec0053c30 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -16,6 +16,7 @@ import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; +import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Binder; @@ -43,6 +44,7 @@ import org.elasticsearch.license.Licensing; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.ClusterPlugin; +import org.elasticsearch.plugins.DiscoveryPlugin; import org.elasticsearch.plugins.IngestPlugin; import org.elasticsearch.plugins.NetworkPlugin; import org.elasticsearch.plugins.Plugin; @@ -124,6 +126,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -131,7 +134,7 @@ import java.util.stream.Stream; import static org.elasticsearch.xpack.watcher.Watcher.ENCRYPT_SENSITIVE_DATA_SETTING; -public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin { +public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin, DiscoveryPlugin { public static final String NAME = "x-pack"; @@ -605,4 +608,9 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I public Map> getInitialClusterStateCustomSupplier() { return security.getInitialClusterStateCustomSupplier(); } + + @Override + public BiConsumer getJoinValidator() { + return security.getJoinValidator(); + } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java b/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java index b700eadaed9..d1b2d39f17f 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java @@ -60,7 +60,7 @@ public class XPackSettings { * Legacy setting for enabling or disabling transport ssl. Defaults to true. This is just here to make upgrading easier since the * user needs to set this setting in 5.x to upgrade */ - private static final Setting TRANSPORT_SSL_ENABLED = + public static final Setting TRANSPORT_SSL_ENABLED = new Setting<>("xpack.security.transport.ssl.enabled", (s) -> Boolean.toString(true), (s) -> { final boolean parsed = Booleans.parseBoolean(s); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java index b205683b2bc..9bbe89810e6 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -15,10 +15,10 @@ import org.elasticsearch.action.support.ActionFilter; import org.elasticsearch.action.support.DestructiveOperations; import org.elasticsearch.bootstrap.BootstrapCheck; import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.LocalNodeMasterListener; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; +import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Booleans; @@ -51,9 +51,12 @@ import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.index.IndexModule; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.ingest.Processor; +import org.elasticsearch.license.License; +import org.elasticsearch.license.LicenseService; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.ClusterPlugin; +import org.elasticsearch.plugins.DiscoveryPlugin; import org.elasticsearch.plugins.IngestPlugin; import org.elasticsearch.plugins.NetworkPlugin; import org.elasticsearch.rest.RestController; @@ -194,7 +197,7 @@ import static java.util.Collections.singletonList; import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_TEMPLATE_NAME; -public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin { +public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin, DiscoveryPlugin { private static final Logger logger = Loggers.getLogger(XPackPlugin.class); @@ -900,4 +903,47 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus return Collections.emptyMap(); } } + + @Override + public BiConsumer getJoinValidator() { + return enabled ? new ValidateTLSOnJoin(XPackSettings.TRANSPORT_SSL_ENABLED.get(settings)) : null; + } + + static final class ValidateTLSOnJoin implements BiConsumer { + private final boolean isTLSEnabled; + + ValidateTLSOnJoin(boolean isTLSEnabled) { + this.isTLSEnabled = isTLSEnabled; + } + + @Override + public void accept(DiscoveryNode node, ClusterState state) { + License license = LicenseService.getLicense(state); + validateLicense(license); + } + + void validateLicense(License license) { + if (license != null) { + switch (license.operationMode()) { + case MISSING: + case TRIAL: + case BASIC: + break; + case STANDARD: + case GOLD: + case PLATINUM: + if (isTLSEnabled == false) { + throw new IllegalStateException("TLS setup is required for license type [" + license.operationMode().name() + + "]"); + } + break; + default: + throw new AssertionError("unknown operation mode: " + license.operationMode()); + + } + } + } + } + + } diff --git a/plugin/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java b/plugin/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java index 973a36d1927..3d0c7f94de4 100644 --- a/plugin/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java @@ -77,19 +77,19 @@ public class LicensesManagerServiceTests extends XPackSingleNodeTestCase { // put gold license TestUtils.registerAndAckSignedLicenses(licenseService, goldLicense, LicensesStatus.VALID); LicensesMetaData licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); - assertThat(licenseService.getLicense(licensesMetaData), equalTo(goldLicense)); + assertThat(LicenseService.getLicense(licensesMetaData), equalTo(goldLicense)); License platinumLicense = TestUtils.generateSignedLicense("platinum", TimeValue.timeValueSeconds(3)); // put platinum license TestUtils.registerAndAckSignedLicenses(licenseService, platinumLicense, LicensesStatus.VALID); licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); - assertThat(licenseService.getLicense(licensesMetaData), equalTo(platinumLicense)); + assertThat(LicenseService.getLicense(licensesMetaData), equalTo(platinumLicense)); License basicLicense = TestUtils.generateSignedLicense("basic", TimeValue.timeValueSeconds(3)); // put basic license TestUtils.registerAndAckSignedLicenses(licenseService, basicLicense, LicensesStatus.VALID); licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); - assertThat(licenseService.getLicense(licensesMetaData), equalTo(basicLicense)); + assertThat(LicenseService.getLicense(licensesMetaData), equalTo(basicLicense)); } public void testInvalidLicenseStorage() throws Exception { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index d0c4095a3dd..57c19488702 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -8,18 +8,28 @@ package org.elasticsearch.xpack.security; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BiConsumer; +import org.elasticsearch.Version; import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.env.Environment; +import org.elasticsearch.license.License; +import org.elasticsearch.license.TestUtils; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; @@ -191,4 +201,35 @@ public class SecurityTests extends ESTestCase { assertThat(filter, hasItem(Security.setting("authc.realms.*.ssl.truststore.path"))); assertThat(filter, hasItem(Security.setting("authc.realms.*.ssl.truststore.algorithm"))); } + + public void testTLSJoinValidatorOnDisabledSecurity() throws Exception { + Settings disabledSettings = Settings.builder().put("xpack.security.enabled", false).build(); + createComponents(disabledSettings); + BiConsumer joinValidator = security.getJoinValidator(); + assertNull(joinValidator); + } + + public void testTLSJoinValidator() throws Exception { + createComponents(Settings.EMPTY); + BiConsumer joinValidator = security.getJoinValidator(); + assertNotNull(joinValidator); + ClusterState state = ClusterState.builder(ClusterName.DEFAULT).build(); + joinValidator.accept(new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT), state); + assertTrue(joinValidator instanceof Security.ValidateTLSOnJoin); + int numIters = randomIntBetween(1,10); + for (int i = 0; i < numIters; i++) { + boolean tlsOn = randomBoolean(); + Security.ValidateTLSOnJoin validator = new Security.ValidateTLSOnJoin(tlsOn); + License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24)); + EnumSet productionModes = EnumSet.of(License.OperationMode.GOLD, License.OperationMode.PLATINUM, + License.OperationMode.STANDARD); + if (productionModes.contains(license.operationMode()) && tlsOn == false) { + IllegalStateException ise = expectThrows(IllegalStateException.class, () -> validator.validateLicense(license)); + assertEquals("TLS setup is required for license type [" + license.operationMode().name() + "]", ise.getMessage()); + } else { + validator.validateLicense(license); + } + validator.validateLicense(null); + } + } } From 91b57ee63fa482457d323c4fccef218fc4c6cc43 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 14 Sep 2017 13:52:53 +0200 Subject: [PATCH 2/9] Add bootstrap check that enforces TLS if a production license is in the local clusterstate (elastic/x-pack-elasticsearch#2499) This change will enforce transport SSL to be enforced if security is enabled and the license in the clusterstate is a production license. The cluster state is loaded from local storage such that we don't need to join a cluster to make these checks. Yet, the cluster might have already got a different license if the node got disconnected while the license got downgraded and then TLS got disabled. This corner case requires manual intervention which we consider ok given the simplicity of this change. Relates to elastic/x-pack-elasticsearch#2463 Original commit: elastic/x-pack-elasticsearch@5765b7cd2152c4e344e7a5d63fb423e5044fa0a0 --- .../org/elasticsearch/license/License.java | 19 ++++++++ .../elasticsearch/license/LicenseService.java | 6 +-- .../elasticsearch/xpack/XPackSettings.java | 18 ++------ .../xpack/security/Security.java | 32 +++---------- .../xpack/ssl/TLSLicenseBootstrapCheck.java | 46 +++++++++++++++++++ .../org/elasticsearch/license/TestUtils.java | 5 ++ .../xpack/security/SecurityTests.java | 13 ++++-- .../ssl/TLSLicenseBootstrapCheckTests.java | 44 ++++++++++++++++++ 8 files changed, 134 insertions(+), 49 deletions(-) create mode 100644 plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java create mode 100644 plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java diff --git a/plugin/src/main/java/org/elasticsearch/license/License.java b/plugin/src/main/java/org/elasticsearch/license/License.java index 05d24ff8774..fd7bd648af4 100644 --- a/plugin/src/main/java/org/elasticsearch/license/License.java +++ b/plugin/src/main/java/org/elasticsearch/license/License.java @@ -782,4 +782,23 @@ public class License implements ToXContentObject { } } } + + /** + * Returns true iff the license is a production licnese + */ + public boolean isProductionLicense() { + switch (operationMode()) { + case MISSING: + case TRIAL: + case BASIC: + return false; + case STANDARD: + case GOLD: + case PLATINUM: + return true; + default: + throw new AssertionError("unknown operation mode: " + operationMode()); + + } + } } diff --git a/plugin/src/main/java/org/elasticsearch/license/LicenseService.java b/plugin/src/main/java/org/elasticsearch/license/LicenseService.java index 271bd642b76..84fa4003e3f 100644 --- a/plugin/src/main/java/org/elasticsearch/license/LicenseService.java +++ b/plugin/src/main/java/org/elasticsearch/license/LicenseService.java @@ -271,7 +271,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste } public License getLicense() { - final License license = getLicense(clusterService.state()); + final License license = getLicense(clusterService.state().metaData()); return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license; } @@ -469,8 +469,8 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste }; } - public static License getLicense(final ClusterState state) { - final LicensesMetaData licensesMetaData = state.metaData().custom(LicensesMetaData.TYPE); + public static License getLicense(final MetaData metaData) { + final LicensesMetaData licensesMetaData = metaData.custom(LicensesMetaData.TYPE); return getLicense(licensesMetaData); } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java b/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java index d1b2d39f17f..d29e1cf3f46 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java @@ -5,7 +5,6 @@ */ package org.elasticsearch.xpack; -import org.elasticsearch.common.Booleans; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; @@ -56,20 +55,9 @@ public class XPackSettings { public static final Setting LOGSTASH_ENABLED = Setting.boolSetting("xpack.logstash.enabled", true, Setting.Property.NodeScope); - /** - * Legacy setting for enabling or disabling transport ssl. Defaults to true. This is just here to make upgrading easier since the - * user needs to set this setting in 5.x to upgrade - */ - public static final Setting TRANSPORT_SSL_ENABLED = - new Setting<>("xpack.security.transport.ssl.enabled", (s) -> Boolean.toString(true), - (s) -> { - final boolean parsed = Booleans.parseBoolean(s); - if (parsed == false) { - throw new IllegalArgumentException("transport ssl cannot be disabled. Remove setting [" + - XPackPlugin.featureSettingPrefix(XPackPlugin.SECURITY) + ".transport.ssl.enabled]"); - } - return true; - }, Property.NodeScope, Property.Deprecated); + /** Setting for enabling or disabling TLS. Defaults to false. */ + public static final Setting TRANSPORT_SSL_ENABLED = Setting.boolSetting("xpack.security.transport.ssl.enabled", false, + Property.NodeScope); /** Setting for enabling or disabling http ssl. Defaults to false. */ public static final Setting HTTP_SSL_ENABLED = Setting.boolSetting("xpack.security.http.ssl.enabled", false, diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java index 38189d634ad..5db94a1aae8 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -168,6 +168,7 @@ import org.elasticsearch.xpack.security.user.AnonymousUser; import org.elasticsearch.xpack.ssl.SSLBootstrapCheck; import org.elasticsearch.xpack.ssl.SSLConfigurationSettings; import org.elasticsearch.xpack.ssl.SSLService; +import org.elasticsearch.xpack.ssl.TLSLicenseBootstrapCheck; import org.elasticsearch.xpack.template.TemplateUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -247,7 +248,8 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus checks.addAll(Arrays.asList( new SSLBootstrapCheck(sslService, env), new TokenSSLBootstrapCheck(), - new PkiRealmBootstrapCheck(sslService))); + new PkiRealmBootstrapCheck(sslService), + new TLSLicenseBootstrapCheck())); checks.addAll(InternalRealms.getBootstrapChecks(settings)); this.bootstrapChecks = Collections.unmodifiableList(checks); } else { @@ -918,32 +920,10 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus @Override public void accept(DiscoveryNode node, ClusterState state) { - License license = LicenseService.getLicense(state); - validateLicense(license); - } - - void validateLicense(License license) { - if (license != null) { - switch (license.operationMode()) { - case MISSING: - case TRIAL: - case BASIC: - break; - case STANDARD: - case GOLD: - case PLATINUM: - if (isTLSEnabled == false) { - throw new IllegalStateException("TLS setup is required for license type [" + license.operationMode().name() - + "]"); - } - break; - default: - throw new AssertionError("unknown operation mode: " + license.operationMode()); - - } + License license = LicenseService.getLicense(state.metaData()); + if (license != null && license.isProductionLicense() && isTLSEnabled == false) { + throw new IllegalStateException("TLS setup is required for license type [" + license.operationMode().name() + "]"); } } } - - } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java new file mode 100644 index 00000000000..1b5109901db --- /dev/null +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.ssl; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.bootstrap.BootstrapCheck; +import org.elasticsearch.bootstrap.BootstrapContext; +import org.elasticsearch.common.inject.internal.Nullable; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; +import org.elasticsearch.license.License; +import org.elasticsearch.license.LicenseService; +import org.elasticsearch.xpack.XPackSettings; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * Bootstrap check to ensure that if we are starting up with a production license in the local clusterstate TLS is enabled + */ +public final class TLSLicenseBootstrapCheck implements BootstrapCheck { + @Override + public BootstrapCheckResult check(BootstrapContext context) { + if (XPackSettings.TRANSPORT_SSL_ENABLED.get(context.settings) == false) { + License license = LicenseService.getLicense(context.metaData); + if (license != null && license.isProductionLicense()) { + return BootstrapCheckResult.failure("Transport SSL must be enabled for setups with production licenses. Please set " + + "[xpack.security.transport.ssl.enabled] or disables security via [xpack.security.enabled]"); + } + } + return BootstrapCheckResult.success(); + } +} diff --git a/plugin/src/test/java/org/elasticsearch/license/TestUtils.java b/plugin/src/test/java/org/elasticsearch/license/TestUtils.java index 5e8f48c8588..554246ae1e1 100644 --- a/plugin/src/test/java/org/elasticsearch/license/TestUtils.java +++ b/plugin/src/test/java/org/elasticsearch/license/TestUtils.java @@ -7,6 +7,7 @@ package org.elasticsearch.license; import com.carrotsearch.randomizedtesting.RandomizedTest; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.joda.FormatDateTimeFormatter; @@ -345,4 +346,8 @@ public class TestUtils { super.update(mode, active); } } + + public static void putLicense(MetaData.Builder builder, License license) { + builder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license)); + } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index 57c19488702..32ca63b3354 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -213,23 +213,26 @@ public class SecurityTests extends ESTestCase { createComponents(Settings.EMPTY); BiConsumer joinValidator = security.getJoinValidator(); assertNotNull(joinValidator); - ClusterState state = ClusterState.builder(ClusterName.DEFAULT).build(); - joinValidator.accept(new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT), state); + DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT); + joinValidator.accept(node, ClusterState.builder(ClusterName.DEFAULT).build()); assertTrue(joinValidator instanceof Security.ValidateTLSOnJoin); int numIters = randomIntBetween(1,10); for (int i = 0; i < numIters; i++) { boolean tlsOn = randomBoolean(); Security.ValidateTLSOnJoin validator = new Security.ValidateTLSOnJoin(tlsOn); + MetaData.Builder builder = MetaData.builder(); License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24)); + TestUtils.putLicense(builder, license); + ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(builder.build()).build(); EnumSet productionModes = EnumSet.of(License.OperationMode.GOLD, License.OperationMode.PLATINUM, License.OperationMode.STANDARD); if (productionModes.contains(license.operationMode()) && tlsOn == false) { - IllegalStateException ise = expectThrows(IllegalStateException.class, () -> validator.validateLicense(license)); + IllegalStateException ise = expectThrows(IllegalStateException.class, () -> validator.accept(node, state)); assertEquals("TLS setup is required for license type [" + license.operationMode().name() + "]", ise.getMessage()); } else { - validator.validateLicense(license); + validator.accept(node, state); } - validator.validateLicense(null); + validator.accept(node, ClusterState.builder(ClusterName.DEFAULT).metaData(MetaData.builder().build()).build()); } } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java new file mode 100644 index 00000000000..7b4a3db51d1 --- /dev/null +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.ssl; + +import org.elasticsearch.bootstrap.BootstrapContext; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.license.License; +import org.elasticsearch.license.TestUtils; +import org.elasticsearch.test.ESTestCase; + +import java.util.EnumSet; + +public class TLSLicenseBootstrapCheckTests extends ESTestCase { + public void testBootstrapCheck() throws Exception { + assertTrue(new TLSLicenseBootstrapCheck().check(new BootstrapContext(Settings.EMPTY, MetaData.EMPTY_META_DATA)).isSuccess()); + assertTrue(new TLSLicenseBootstrapCheck().check(new BootstrapContext(Settings.builder().put("xpack.security.transport.ssl.enabled" + , randomBoolean()).build(), MetaData.EMPTY_META_DATA)).isSuccess()); + int numIters = randomIntBetween(1,10); + for (int i = 0; i < numIters; i++) { + License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24)); + EnumSet productionModes = EnumSet.of(License.OperationMode.GOLD, License.OperationMode.PLATINUM, + License.OperationMode.STANDARD); + MetaData.Builder builder = MetaData.builder(); + TestUtils.putLicense(builder, license); + MetaData build = builder.build(); + if (productionModes.contains(license.operationMode()) == false) { + assertTrue(new TLSLicenseBootstrapCheck().check(new BootstrapContext( + Settings.builder().put("xpack.security.transport.ssl.enabled", true).build(), build)).isSuccess()); + } else { + assertTrue(new TLSLicenseBootstrapCheck().check(new BootstrapContext( + Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(), build)).isFailure()); + assertEquals("Transport SSL must be enabled for setups with production licenses." + + " Please set [xpack.security.transport.ssl.enabled] or disables security via [xpack.security.enabled]", + new TLSLicenseBootstrapCheck().check(new BootstrapContext( + Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(), build)).getMessage()); + } + } + } +} From 1e14e14571509d0525e5e93563c71d53364a0172 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 14 Sep 2017 20:14:27 +0200 Subject: [PATCH 3/9] 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@d61ef3bcb1a6056b139782f0772b565847bd834f --- .../elasticsearch/license/LicenseService.java | 38 ++++++++----- .../AbstractLicenseServiceTestCase.java | 4 +- .../license/LicenseClusterChangeTests.java | 3 +- .../license/LicenseRegistrationTests.java | 3 +- .../license/LicensesAcknowledgementTests.java | 55 ++++++++++++++++++- 5 files changed, 85 insertions(+), 18 deletions(-) diff --git a/plugin/src/main/java/org/elasticsearch/license/LicenseService.java b/plugin/src/main/java/org/elasticsearch/license/LicenseService.java index 84fa4003e3f..227293886a9 100644 --- a/plugin/src/main/java/org/elasticsearch/license/LicenseService.java +++ b/plugin/src/main/java/org/elasticsearch/license/LicenseService.java @@ -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(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(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(); + } + }); + } } } diff --git a/plugin/src/test/java/org/elasticsearch/license/AbstractLicenseServiceTestCase.java b/plugin/src/test/java/org/elasticsearch/license/AbstractLicenseServiceTestCase.java index 1acd3012276..dcead1236f2 100644 --- a/plugin/src/test/java/org/elasticsearch/license/AbstractLicenseServiceTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/license/AbstractLicenseServiceTestCase.java @@ -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(); diff --git a/plugin/src/test/java/org/elasticsearch/license/LicenseClusterChangeTests.java b/plugin/src/test/java/org/elasticsearch/license/LicenseClusterChangeTests.java index f258e1d70aa..903cfa4f5fe 100644 --- a/plugin/src/test/java/org/elasticsearch/license/LicenseClusterChangeTests.java +++ b/plugin/src/test/java/org/elasticsearch/license/LicenseClusterChangeTests.java @@ -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(); } diff --git a/plugin/src/test/java/org/elasticsearch/license/LicenseRegistrationTests.java b/plugin/src/test/java/org/elasticsearch/license/LicenseRegistrationTests.java index f96298e3087..8c76a009e40 100644 --- a/plugin/src/test/java/org/elasticsearch/license/LicenseRegistrationTests.java +++ b/plugin/src/test/java/org/elasticsearch/license/LicenseRegistrationTests.java @@ -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(); diff --git a/plugin/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java b/plugin/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java index b439fa4a133..eed19785b1b 100644 --- a/plugin/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java +++ b/plugin/src/test/java/org/elasticsearch/license/LicensesAcknowledgementTests.java @@ -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 { private final boolean expectedAcknowledgement; private final LicensesStatus expectedStatus; From 57de66476c9d7e37f56d0c7ba861134c4485bf1b Mon Sep 17 00:00:00 2001 From: Jay Modi Date: Thu, 14 Sep 2017 12:18:54 -0600 Subject: [PATCH 4/9] Disable TLS by default (elastic/x-pack-elasticsearch#2481) This commit adds back the ability to disable TLS on the transport layer and also disables TLS by default to restore the 5.x behavior. The auto generation of key/cert and bundled CA certificate have also been removed. Relates elastic/x-pack-elasticsearch#2463 Original commit: elastic/x-pack-elasticsearch@abc66ec67d5bf9e2e1957828db870baaefd2eaf1 --- .../security/PkiRealmBootstrapCheck.java | 7 +- .../xpack/security/Security.java | 2 - .../SecurityServerTransportInterceptor.java | 6 +- .../netty4/SecurityNetty4Transport.java | 82 ++++--- .../xpack/ssl/GeneratedKeyConfig.java | 211 ------------------ .../xpack/ssl/SSLBootstrapCheck.java | 99 -------- .../elasticsearch/xpack/ssl/SSLService.java | 70 +----- .../org/elasticsearch/xpack/ssl/ca.pem | 20 -- .../org/elasticsearch/xpack/ssl/private.pem | 27 --- .../org/elasticsearch/xpack/ssl/public.pem | 9 - .../ldap/AbstractAdLdapRealmTestCase.java | 5 +- .../test/SecurityIntegTestCase.java | 12 +- .../test/SecuritySettingsSource.java | 94 ++++---- .../security/PkiRealmBootstrapCheckTests.java | 6 + .../xpack/security/SecurityTribeIT.java | 12 +- .../security/audit/index/AuditTrailTests.java | 3 +- .../audit/index/IndexAuditTrailTests.java | 16 +- .../RemoteIndexAuditTrailStartingTests.java | 10 +- .../xpack/security/authc/RunAsIntegTests.java | 4 +- .../esnative/ESNativeMigrateToolTests.java | 5 +- .../authc/pki/PkiAuthenticationTests.java | 5 +- .../authc/pki/PkiOptionalClientAuthTests.java | 4 +- ...ServerTransportFilterIntegrationTests.java | 8 +- .../DNSOnlyHostnameVerificationTests.java | 4 +- .../netty4/IPHostnameVerificationTests.java | 4 +- .../netty4/SecurityNetty4TransportTests.java | 5 +- .../netty4/SslHostnameVerificationTests.java | 4 +- .../transport/ssl/EllipticCurveSSLTests.java | 4 +- .../transport/ssl/SslIntegrationTests.java | 4 +- .../transport/ssl/SslMultiPortTests.java | 13 +- .../transport/ssl/SslNullCipherTests.java | 6 +- .../xpack/ssl/GeneratedKeyConfigTests.java | 45 ---- .../xpack/ssl/SSLBootstrapCheckTests.java | 93 -------- .../xpack/ssl/SSLClientAuthTests.java | 5 +- .../ssl/SSLConfigurationReloaderTests.java | 14 +- .../xpack/ssl/SSLReloadIntegTests.java | 4 +- .../xpack/ssl/SSLTrustRestrictionsTests.java | 4 +- qa/rolling-upgrade/build.gradle | 2 + qa/smoke-test-plugins-ssl/build.gradle | 2 + 39 files changed, 202 insertions(+), 728 deletions(-) delete mode 100644 plugin/src/main/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfig.java delete mode 100644 plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheck.java delete mode 100644 plugin/src/main/resources/org/elasticsearch/xpack/ssl/ca.pem delete mode 100644 plugin/src/main/resources/org/elasticsearch/xpack/ssl/private.pem delete mode 100644 plugin/src/main/resources/org/elasticsearch/xpack/ssl/public.pem delete mode 100644 plugin/src/test/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfigTests.java delete mode 100644 plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java b/plugin/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java index 9a79333efbe..c9674aa7c8c 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheck.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security; import org.elasticsearch.bootstrap.BootstrapCheck; import org.elasticsearch.bootstrap.BootstrapContext; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.authc.RealmSettings; import org.elasticsearch.xpack.security.authc.pki.PkiRealm; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport; @@ -46,16 +47,18 @@ class PkiRealmBootstrapCheck implements BootstrapCheck { } // Default Transport + final boolean transportSSLEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings); final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); final boolean clientAuthEnabled = sslService.isSSLClientAuthEnabled(transportSSLSettings); - if (clientAuthEnabled) { + if (transportSSLEnabled && clientAuthEnabled) { return BootstrapCheckResult.success(); } // Transport Profiles Map groupedSettings = settings.getGroups("transport.profiles."); for (Map.Entry entry : groupedSettings.entrySet()) { - if (sslService.isSSLClientAuthEnabled(SecurityNetty4Transport.profileSslSettings(entry.getValue()), transportSSLSettings)) { + if (transportSSLEnabled && sslService.isSSLClientAuthEnabled( + SecurityNetty4Transport.profileSslSettings(entry.getValue()), transportSSLSettings)) { return BootstrapCheckResult.success(); } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java index 5db94a1aae8..cb7f76be5ba 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -165,7 +165,6 @@ import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4Transport; import org.elasticsearch.xpack.security.user.AnonymousUser; -import org.elasticsearch.xpack.ssl.SSLBootstrapCheck; import org.elasticsearch.xpack.ssl.SSLConfigurationSettings; import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.ssl.TLSLicenseBootstrapCheck; @@ -246,7 +245,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus // fetched final List checks = new ArrayList<>(); checks.addAll(Arrays.asList( - new SSLBootstrapCheck(sslService, env), new TokenSSLBootstrapCheck(), new PkiRealmBootstrapCheck(sslService), new TLSLicenseBootstrapCheck())); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportInterceptor.java b/plugin/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportInterceptor.java index b658dcc1251..980df9c1185 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportInterceptor.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/transport/SecurityServerTransportInterceptor.java @@ -171,10 +171,12 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem Map profileFilters = new HashMap<>(profileSettingsMap.size() + 1); final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); + final boolean transportSSLEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings); for (Map.Entry entry : profileSettingsMap.entrySet()) { Settings profileSettings = entry.getValue(); final Settings profileSslSettings = SecurityNetty4Transport.profileSslSettings(profileSettings); - final boolean extractClientCert = sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings); + final boolean extractClientCert = transportSSLEnabled && + sslService.isSSLClientAuthEnabled(profileSslSettings, transportSSLSettings); String type = TRANSPORT_TYPE_SETTING_TEMPLATE.apply(TRANSPORT_TYPE_SETTING_KEY).get(entry.getValue()); switch (type) { case "client": @@ -193,7 +195,7 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem } if (!profileFilters.containsKey(TcpTransport.DEFAULT_PROFILE)) { - final boolean extractClientCert = sslService.isSSLClientAuthEnabled(transportSSLSettings); + final boolean extractClientCert = transportSSLEnabled && sslService.isSSLClientAuthEnabled(transportSSLSettings); profileFilters.put(TcpTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService, threadPool.getThreadContext(), extractClientCert, destructiveOperations, reservedRealmEnabled, securityContext)); } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java b/plugin/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java index 444a5c58127..24b3106dd47 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4Transport.java @@ -21,6 +21,7 @@ import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TcpTransport; import org.elasticsearch.transport.netty4.Netty4Transport; +import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.ssl.SSLConfiguration; import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.security.transport.filter.IPFilter; @@ -47,6 +48,7 @@ public class SecurityNetty4Transport extends Netty4Transport { @Nullable private final IPFilter authenticator; private final SSLConfiguration sslConfiguration; private final Map profileConfiguration; + private final boolean sslEnabled; public SecurityNetty4Transport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, NamedWriteableRegistry namedWriteableRegistry, CircuitBreakerService circuitBreakerService, @@ -54,23 +56,28 @@ public class SecurityNetty4Transport extends Netty4Transport { super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService); this.authenticator = authenticator; this.sslService = sslService; + this.sslEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings); final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl.")); - sslConfiguration = sslService.sslConfiguration(transportSSLSettings, Settings.EMPTY); - Map profileSettingsMap = settings.getGroups("transport.profiles.", true); - Map profileConfiguration = new HashMap<>(profileSettingsMap.size() + 1); - for (Map.Entry entry : profileSettingsMap.entrySet()) { - Settings profileSettings = entry.getValue(); - final Settings profileSslSettings = profileSslSettings(profileSettings); - SSLConfiguration configuration = sslService.sslConfiguration(profileSslSettings, transportSSLSettings); - profileConfiguration.put(entry.getKey(), configuration); + if (sslEnabled) { + this.sslConfiguration = sslService.sslConfiguration(transportSSLSettings, Settings.EMPTY); + Map profileSettingsMap = settings.getGroups("transport.profiles.", true); + Map profileConfiguration = new HashMap<>(profileSettingsMap.size() + 1); + for (Map.Entry entry : profileSettingsMap.entrySet()) { + Settings profileSettings = entry.getValue(); + final Settings profileSslSettings = profileSslSettings(profileSettings); + SSLConfiguration configuration = sslService.sslConfiguration(profileSslSettings, transportSSLSettings); + profileConfiguration.put(entry.getKey(), configuration); + } + + if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) { + profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, sslConfiguration); + } + + this.profileConfiguration = Collections.unmodifiableMap(profileConfiguration); + } else { + this.profileConfiguration = Collections.emptyMap(); + this.sslConfiguration = null; } - - if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) { - profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, sslConfiguration); - - } - - this.profileConfiguration = Collections.unmodifiableMap(profileConfiguration); } @Override @@ -83,11 +90,15 @@ public class SecurityNetty4Transport extends Netty4Transport { @Override protected ChannelHandler getServerChannelInitializer(String name) { - SSLConfiguration configuration = profileConfiguration.get(name); - if (configuration == null) { - throw new IllegalStateException("unknown profile: " + name); + if (sslEnabled) { + SSLConfiguration configuration = profileConfiguration.get(name); + if (configuration == null) { + throw new IllegalStateException("unknown profile: " + name); + } + return new SecurityServerChannelInitializer(name, configuration); + } else { + return new IPFilterServerChannelInitializer(name); } - return new SecurityServerChannelInitializer(name, configuration); } @Override @@ -127,13 +138,26 @@ public class SecurityNetty4Transport extends Netty4Transport { } } - class SecurityServerChannelInitializer extends ServerChannelInitializer { + class IPFilterServerChannelInitializer extends ServerChannelInitializer { + IPFilterServerChannelInitializer(String name) { + super(name); + } + + @Override + protected void initChannel(Channel ch) throws Exception { + super.initChannel(ch); + if (authenticator != null) { + ch.pipeline().addFirst("ipfilter", new IpFilterRemoteAddressFilter(authenticator, name)); + } + } + } + + class SecurityServerChannelInitializer extends IPFilterServerChannelInitializer { private final SSLConfiguration configuration; SecurityServerChannelInitializer(String name, SSLConfiguration configuration) { super(name); this.configuration = configuration; - } @Override @@ -141,9 +165,12 @@ public class SecurityNetty4Transport extends Netty4Transport { super.initChannel(ch); SSLEngine serverEngine = sslService.createSSLEngine(configuration, null, -1); serverEngine.setUseClientMode(false); - ch.pipeline().addFirst(new SslHandler(serverEngine)); - if (authenticator != null) { - ch.pipeline().addFirst(new IpFilterRemoteAddressFilter(authenticator, name)); + IpFilterRemoteAddressFilter remoteAddressFilter = ch.pipeline().get(IpFilterRemoteAddressFilter.class); + final SslHandler sslHandler = new SslHandler(serverEngine); + if (remoteAddressFilter == null) { + ch.pipeline().addFirst("sslhandler", sslHandler); + } else { + ch.pipeline().addAfter("ipfilter", "sslhandler", sslHandler); } } } @@ -153,13 +180,15 @@ public class SecurityNetty4Transport extends Netty4Transport { private final boolean hostnameVerificationEnabled; SecurityClientChannelInitializer() { - this.hostnameVerificationEnabled = sslConfiguration.verificationMode().isHostnameVerificationEnabled(); + this.hostnameVerificationEnabled = sslEnabled && sslConfiguration.verificationMode().isHostnameVerificationEnabled(); } @Override protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); - ch.pipeline().addFirst(new ClientSslHandlerInitializer(sslConfiguration, sslService, hostnameVerificationEnabled)); + if (sslEnabled) { + ch.pipeline().addFirst(new ClientSslHandlerInitializer(sslConfiguration, sslService, hostnameVerificationEnabled)); + } } } @@ -197,5 +226,4 @@ public class SecurityNetty4Transport extends Netty4Transport { public static Settings profileSslSettings(Settings profileSettings) { return profileSettings.getByPrefix(setting("ssl.")); } - } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfig.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfig.java deleted file mode 100644 index 81de52b5638..00000000000 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfig.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.ssl; - -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.operator.OperatorCreationException; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.hash.MessageDigests; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.node.Node; - -import javax.net.ssl.X509ExtendedKeyManager; -import javax.net.ssl.X509ExtendedTrustManager; -import javax.security.auth.DestroyFailedException; -import javax.security.auth.x500.X500Principal; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.UncheckedIOException; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.security.KeyPair; -import java.security.KeyStoreException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Represents a {@link KeyConfig} that is automatically generated on node startup if necessary. This helps with the default user experience - * so that the user does not need to have any knowledge about SSL setup to start a node - */ -final class GeneratedKeyConfig extends KeyConfig { - - // these values have been generated using openssl - // For private key: openssl pkcs8 -in private.pem -inform PEM -nocrypt -topk8 -outform DER | openssl dgst -sha256 -hex - // For certificate: openssl x509 -in ca.pem -noout -fingerprint -sha256 - private static final String PRIVATE_KEY_SHA256 = "eec5bdb422c17c75d3850ffc64a724e52a99ec64366677da2fe4e782d7426e9f"; - private static final String CA_CERT_FINGERPRINT_SHA256 = "A147166C71EB8B61DADFC5B19ECAC8443BE2DB32A56FC1A73BC1623250738598"; - - private final X509ExtendedKeyManager keyManager; - private final X509ExtendedTrustManager trustManager; - - GeneratedKeyConfig(Settings settings) throws NoSuchAlgorithmException, IOException, CertificateException, OperatorCreationException, - UnrecoverableKeyException, KeyStoreException { - final KeyPair keyPair = CertUtils.generateKeyPair(2048); - final X500Principal principal = new X500Principal("CN=" + Node.NODE_NAME_SETTING.get(settings)); - final Certificate caCert = readCACert(); - final PrivateKey privateKey = readPrivateKey(); - final GeneralNames generalNames = CertUtils.getSubjectAlternativeNames(false, getLocalAddresses()); - X509Certificate certificate = - CertUtils.generateSignedCertificate(principal, generalNames, keyPair, (X509Certificate) caCert, privateKey, 365); - try { - privateKey.destroy(); - } catch (DestroyFailedException e) { - // best effort attempt. This is known to fail for RSA keys on the oracle JDK but maybe they'll fix it in ten years or so... - } - keyManager = CertUtils.keyManager(new Certificate[] { certificate, caCert }, keyPair.getPrivate(), new char[0]); - trustManager = CertUtils.trustManager(new Certificate[] { caCert }); - } - - @Override - X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { - return trustManager; - } - - @Override - List filesToMonitor(@Nullable Environment environment) { - // no files to watch - return Collections.emptyList(); - } - - @Override - public String toString() { - return "Generated Key Config. DO NOT USE IN PRODUCTION"; - } - - @Override - public boolean equals(Object o) { - return this == o; - } - - @Override - public int hashCode() { - return Objects.hash(keyManager, trustManager); - } - - @Override - X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) { - return keyManager; - } - - @Override - List privateKeys(@Nullable Environment environment) { - try { - return Collections.singletonList(readPrivateKey()); - } catch (IOException e) { - throw new UncheckedIOException("failed to read key", e); - } - } - - /** - * Enumerates all of the loopback and link local addresses so these can be used as SubjectAlternativeNames inside the certificate for - * a good out of the box experience with TLS - */ - private Set getLocalAddresses() throws SocketException { - Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); - Set inetAddresses = new HashSet<>(); - while (networkInterfaces.hasMoreElements()) { - NetworkInterface intf = networkInterfaces.nextElement(); - if (intf.isUp()) { - if (intf.isLoopback()) { - inetAddresses.addAll(Collections.list(intf.getInetAddresses())); - } else { - Enumeration inetAddressEnumeration = intf.getInetAddresses(); - while (inetAddressEnumeration.hasMoreElements()) { - InetAddress inetAddress = inetAddressEnumeration.nextElement(); - if (inetAddress.isLoopbackAddress() || inetAddress.isLinkLocalAddress()) { - inetAddresses.add(inetAddress); - } - } - } - } - } - return inetAddresses; - } - - /** - * Reads the bundled CA private key. This key is used for signing a automatically generated certificate that allows development nodes - * to talk to each other on the same machine. - * - * This private key is the same for every distribution and is only here for a nice out of the box experience. Once in production mode - * this key should not be used! - */ - static PrivateKey readPrivateKey() throws IOException { - try (InputStream inputStream = GeneratedKeyConfig.class.getResourceAsStream("private.pem"); - Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - PrivateKey privateKey = CertUtils.readPrivateKey(reader, () -> null); - MessageDigest md = MessageDigests.sha256(); - final byte[] privateKeyBytes = privateKey.getEncoded(); - try { - final byte[] digest = md.digest(privateKeyBytes); - final byte[] expected = hexStringToByteArray(PRIVATE_KEY_SHA256); - if (Arrays.equals(digest, expected) == false) { - throw new IllegalStateException("private key hash does not match the expected value!"); - } - } finally { - Arrays.fill(privateKeyBytes, (byte) 0); - } - return privateKey; - } - } - - /** - * Reads the bundled CA certificate - */ - static Certificate readCACert() throws IOException, CertificateException { - try (InputStream inputStream = GeneratedKeyConfig.class.getResourceAsStream("ca.pem"); - Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); - List certificateList = new ArrayList<>(1); - CertUtils.readCertificates(reader, certificateList, certificateFactory); - if (certificateList.size() != 1) { - throw new IllegalStateException("expected [1] default CA certificate but found [" + certificateList.size() + "]"); - } - Certificate certificate = certificateList.get(0); - final byte[] encoded = MessageDigests.sha256().digest(certificate.getEncoded()); - final byte[] expected = hexStringToByteArray(CA_CERT_FINGERPRINT_SHA256); - if (Arrays.equals(encoded, expected) == false) { - throw new IllegalStateException("CA certificate fingerprint does not match!"); - } - return certificateList.get(0); - } - } - - private static byte[] hexStringToByteArray(String hexString) { - if (hexString.length() % 2 != 0) { - throw new IllegalArgumentException("String must be an even length"); - } - final int numBytes = hexString.length() / 2; - final byte[] data = new byte[numBytes]; - - for(int i = 0; i < numBytes; i++) { - final int index = i * 2; - final int index2 = index + 1; - data[i] = (byte) ((Character.digit(hexString.charAt(index), 16) << 4) + Character.digit(hexString.charAt(index2), 16)); - } - - return data; - } -} diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheck.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheck.java deleted file mode 100644 index 1cae925f8f8..00000000000 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheck.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.ssl; - -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.bootstrap.BootstrapCheck; -import org.elasticsearch.bootstrap.BootstrapContext; -import org.elasticsearch.common.inject.internal.Nullable; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.XPackSettings; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SignatureException; -import java.security.cert.CertificateException; -import java.util.Arrays; -import java.util.Objects; -import java.util.stream.Stream; - -/** - * Bootstrap check to ensure that we only use the generated key config in non-production situations. This class is currently public because - * {@link org.elasticsearch.xpack.security.Security} is in a different package and we use package private accessors of the - * {@link SSLService} to get the configuration for the node to node transport - */ -public final class SSLBootstrapCheck implements BootstrapCheck { - - private final SSLService sslService; - private final Environment environment; - - public SSLBootstrapCheck(SSLService sslService, @Nullable Environment environment) { - this.sslService = sslService; - this.environment = environment; - } - - @Override - public BootstrapCheckResult check(BootstrapContext context) { - final Settings transportSSLSettings = context.settings.getByPrefix(XPackSettings.TRANSPORT_SSL_PREFIX); - if (sslService.sslConfiguration(transportSSLSettings).keyConfig() == KeyConfig.NONE - || isDefaultCACertificateTrusted() || isDefaultPrivateKeyUsed()) { - return BootstrapCheckResult.failure( - "default SSL key and certificate do not provide security; please generate keys and certificates"); - } else { - return BootstrapCheckResult.success(); - } - } - - /** - * Looks at all of the trusted certificates to ensure the default CA is not being trusted. We cannot let this happen in production mode - */ - private boolean isDefaultCACertificateTrusted() { - final PublicKey publicKey; - try { - publicKey = GeneratedKeyConfig.readCACert().getPublicKey(); - } catch (IOException | CertificateException e) { - throw new ElasticsearchException("failed to check default CA", e); - } - return sslService.getLoadedSSLConfigurations().stream() - .flatMap(config -> Stream.of(config.keyConfig().createTrustManager(environment), - config.trustConfig().createTrustManager(environment))) - .filter(Objects::nonNull) - .flatMap((tm) -> Arrays.stream(tm.getAcceptedIssuers())) - .anyMatch((cert) -> { - try { - cert.verify(publicKey); - return true; - } catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException - | SignatureException e) { - // just ignore these - return false; - } - }); - } - - /** - * Looks at all of the private keys and if there is a key that is equal to the default CA key then we should bail out - */ - private boolean isDefaultPrivateKeyUsed() { - final PrivateKey defaultPrivateKey; - try { - defaultPrivateKey = GeneratedKeyConfig.readPrivateKey(); - } catch (IOException e) { - throw new UncheckedIOException("failed to read key", e); - } - - return sslService.getLoadedSSLConfigurations().stream() - .flatMap(sslConfiguration -> sslConfiguration.keyConfig().privateKeys(environment).stream()) - .anyMatch(defaultPrivateKey::equals); - } - -} diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java index fc35a47de6d..571a013524f 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLService.java @@ -10,7 +10,6 @@ import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; import org.apache.lucene.util.SetOnce; import org.bouncycastle.operator.OperatorCreationException; import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.Nullable; import org.elasticsearch.common.CheckedSupplier; import org.elasticsearch.common.Strings; import org.elasticsearch.common.component.AbstractComponent; @@ -33,7 +32,6 @@ import javax.security.auth.DestroyFailedException; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import java.nio.file.Path; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -447,74 +445,12 @@ public class SSLService extends AbstractComponent { final SSLConfiguration transportSSLConfiguration = new SSLConfiguration(transportSSLSettings, globalSSLConfiguration); this.transportSSLConfiguration.set(transportSSLConfiguration); List profileSettings = getTransportProfileSSLSettings(settings); - - // if no key is provided for transport we can auto-generate a key with a signed certificate for development use only. There is a - // bootstrap check that prevents this configuration from being use in production (SSLBootstrapCheck) - if (transportSSLConfiguration.keyConfig() == KeyConfig.NONE) { - createDevelopmentTLSConfiguration(sslConfigurations, transportSSLConfiguration, profileSettings); - - } else { - sslConfigurations.computeIfAbsent(transportSSLConfiguration, this::createSslContext); - profileSettings.forEach((profileSetting) -> - sslConfigurations.computeIfAbsent(new SSLConfiguration(profileSetting, transportSSLConfiguration), this::createSslContext)); - } + sslConfigurations.computeIfAbsent(transportSSLConfiguration, this::createSslContext); + profileSettings.forEach((profileSetting) -> + sslConfigurations.computeIfAbsent(new SSLConfiguration(profileSetting, transportSSLConfiguration), this::createSslContext)); return Collections.unmodifiableMap(sslConfigurations); } - private void createDevelopmentTLSConfiguration(Map sslConfigurations, - SSLConfiguration transportSSLConfiguration, List profileSettings) - throws NoSuchAlgorithmException, IOException, CertificateException, OperatorCreationException, UnrecoverableKeyException, - KeyStoreException { - // lazily generate key to avoid slowing down startup where we do not need it - final GeneratedKeyConfig generatedKeyConfig = new GeneratedKeyConfig(settings); - final TrustConfig trustConfig = - new TrustConfig.CombiningTrustConfig(Arrays.asList(transportSSLConfiguration.trustConfig(), new TrustConfig() { - @Override - X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) { - return generatedKeyConfig.createTrustManager(environment); - } - - @Override - List filesToMonitor(@Nullable Environment environment) { - return Collections.emptyList(); - } - - @Override - public String toString() { - return "Generated Trust Config. DO NOT USE IN PRODUCTION"; - } - - @Override - public boolean equals(Object o) { - return this == o; - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - })); - X509ExtendedTrustManager extendedTrustManager = trustConfig.createTrustManager(env); - ReloadableTrustManager trustManager = new ReloadableTrustManager(extendedTrustManager, trustConfig); - ReloadableX509KeyManager keyManager = - new ReloadableX509KeyManager(generatedKeyConfig.createKeyManager(env), generatedKeyConfig); - sslConfigurations.put(transportSSLConfiguration, createSslContext(keyManager, trustManager, transportSSLConfiguration)); - profileSettings.forEach((profileSetting) -> { - SSLConfiguration configuration = new SSLConfiguration(profileSetting, transportSSLConfiguration); - if (configuration.keyConfig() == KeyConfig.NONE) { - sslConfigurations.compute(configuration, (conf, holder) -> { - if (holder != null && holder.keyManager == keyManager && holder.trustManager == trustManager) { - return holder; - } else { - return createSslContext(keyManager, trustManager, configuration); - } - }); - } else { - sslConfigurations.computeIfAbsent(configuration, this::createSslContext); - } - }); - } - /** * This socket factory wraps an existing SSLSocketFactory and sets the protocols and ciphers on each SSLSocket after it is created. This * is needed even though the SSLContext is configured properly as the configuration does not flow down to the sockets created by the diff --git a/plugin/src/main/resources/org/elasticsearch/xpack/ssl/ca.pem b/plugin/src/main/resources/org/elasticsearch/xpack/ssl/ca.pem deleted file mode 100644 index eff9fc52273..00000000000 --- a/plugin/src/main/resources/org/elasticsearch/xpack/ssl/ca.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWDCCAkCgAwIBAgIJANRlkT/I8aROMA0GCSqGSIb3DQEBCwUAMCYxJDAiBgNV -BAMTG3hwYWNrIHB1YmxpYyBkZXZlbG9wbWVudCBjYTAeFw0xNzAxMDUxNDUyMDNa -Fw00NDA1MjMxNDUyMDNaMCYxJDAiBgNVBAMTG3hwYWNrIHB1YmxpYyBkZXZlbG9w -bWVudCBjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALBfQEQYZmPW -cAw939i8RRsa27+qxd32ysJu9aKgSEiIDFKU0JwFh6pog1l8frICM4jF0TqILGHv -+QbQYsD2e3jYp0cj8dy2+YN6jgTXMf1N8yh6GYXEzRrEKYhqVTHLpZgbhxEFxsws -gZiEMHiVxn6h5i4uWDmkp6zt4kHlKgvjtIEzZ1xiXWcS7jJvVPb8r0xUFPDu8Qij -BhjxkbkXprzjGEtt4bKqZ8/R+pr+eUuvmApMSMB38dZxDRXxyavbmbJcGDJX+ZKN -4OcECH55B/EtxhPxpfFXmX+y5Lh597vkhgitw8Qhayaa8gF16tt4rUgYude9kGSi -m3hs6Q9mWM8CAwEAAaOBiDCBhTAdBgNVHQ4EFgQUM6+ZLgmnj1FXHEPejFcpiRR+ -ANIwVgYDVR0jBE8wTYAUM6+ZLgmnj1FXHEPejFcpiRR+ANKhKqQoMCYxJDAiBgNV -BAMTG3hwYWNrIHB1YmxpYyBkZXZlbG9wbWVudCBjYYIJANRlkT/I8aROMAwGA1Ud -EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABqgr2p+Ivb3myF56BuiJYYz55Wa -ncm4Aqdw6p/A5qkl3pSXu2zbgSfyFvux7Q1+lowIvw4fAOTBcQQpQkYWJmObkCLg -HMiKbBreFVqPOqScjTBk6t1g/mOdJXfOognc6QRwfunEBqevNVDT2w3sGlNHooEM -3XUPBgyuznE1Olqt7U0tMGsENyBgZv51bUg7ZZCLrV2sdgqc3XYZUqBnttvbBDyU -tozgDMoCXLvVHcpWcKsA+ONd0szbSAu1uF0ZfqgaoSslM1ph9ydPbXEvnD5AFO6Y -VBTW3v4cnluhrxO6TwRqNo43L5ENqZhtX9gVtzQ54exQsuoKzZ8NO5X1uIA= ------END CERTIFICATE----- diff --git a/plugin/src/main/resources/org/elasticsearch/xpack/ssl/private.pem b/plugin/src/main/resources/org/elasticsearch/xpack/ssl/private.pem deleted file mode 100644 index 19306bffb51..00000000000 --- a/plugin/src/main/resources/org/elasticsearch/xpack/ssl/private.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAsF9ARBhmY9ZwDD3f2LxFGxrbv6rF3fbKwm71oqBISIgMUpTQ -nAWHqmiDWXx+sgIziMXROogsYe/5BtBiwPZ7eNinRyPx3Lb5g3qOBNcx/U3zKHoZ -hcTNGsQpiGpVMculmBuHEQXGzCyBmIQweJXGfqHmLi5YOaSnrO3iQeUqC+O0gTNn -XGJdZxLuMm9U9vyvTFQU8O7xCKMGGPGRuRemvOMYS23hsqpnz9H6mv55S6+YCkxI -wHfx1nENFfHJq9uZslwYMlf5ko3g5wQIfnkH8S3GE/Gl8VeZf7LkuHn3u+SGCK3D -xCFrJpryAXXq23itSBi5172QZKKbeGzpD2ZYzwIDAQABAoIBADRpKbzSj2Ktr4BD -xsguMk76rUCIq+Ho25npxT69aJ19KERGCrPChO0jv5yQ/UlClDPZrPI60w2LdTIM -LLxwwoJHx3XBfbb7/KuQeLGBjU5bop1tozX4JIcGsdzi1ExG2v+XdoydbdTwiNZc -udark1/AFpm0le0TO+yMiEbSpasAUetmwmBLl0ld1qOoEFNM4ueLtM0/JE4kQHJC -a6a0fS1D+TQsPCdziW80X2hpwCIbg4CF3LqR521SfwIzRscbaXzCzeBNCShJE8Nm -Qun91Szze80aaFBBIwMKbppEx5iYCCKeTyO3yswRuZ44+iBe/piB3F/qRKnjBwNS -LeL9NOECgYEA4xMUueF8HN23QeC/KZ/6LALwyNBtT7JP7YbW6dvo+3F0KSPxbDL1 -nMmeOTV8suAlGslsE+GuvPU6M9fUCxpbVnbYH5hEuh0v25WRekFv14H/yEpVF26o -OHeilUIzpRTUOndgkmN8cXNp2xkzs2Yp7F2RSlog2kXQOYgC91YmvjECgYEAxtbC -OzxUUjebeqnolo8wYur42BievUDqyD9pCnaix+2F59SdLDgirJIOEtv31jjpLaIh -nO8akxMCPNwhEgVzelI2k+jJ+Kermi3+tEAnlBBDf/tMEGNav2XE3MnYkDt2jdza -fganfhKQwAufyq2lUHC/Slh+xcLPepTef6zFxv8CgYB6ZEJ7ninDdU3dWEIxMWUq -a7tUweLpXfbu1Arqqfl97bzqn9D0vNLd215I/6di0qWtNnvmi3Ifrx3b660C/wXU -KOJ8xRnmJu0wsgFjn/mkcxFm54nNw3swVGtxf+lORVfO26FVxgHBNLANxBu1yo82 -M4ioRsQGYjLFj6XpoqnnQQKBgE8RpYlCs1FCdZxwpmIArMAZKj1chPtDLlnVBWM4 -zABuzpni7WFhLUCsj9YmDMbuOKOB3pX2av3jSDeFXc05x7LzsGpe3rn3iwCzm554 -CIUTdpQVDSlTKQoFYSRfS7QHQVymX2hQIxi6Lz9/H9rL9Hopa5gX2smvbywSuOvS -e49nAoGAM7TQ9iFBsygXxbxh2EL47nw/LBxbDm86TazpSKrHd9pV6Z/Xv870QEf7 -cZJ9T/KRGkxlK8L6B7uzeckpk4uMWuDRiymnbg2pqk94oELKkh0iLnlGSMf3IPO8 -qIRFQsQfA3PaU6SG/izaB1lquBRtIj5kAW2ZXI4O9l5V39Y5/n4= ------END RSA PRIVATE KEY----- diff --git a/plugin/src/main/resources/org/elasticsearch/xpack/ssl/public.pem b/plugin/src/main/resources/org/elasticsearch/xpack/ssl/public.pem deleted file mode 100644 index 2b46db3019e..00000000000 --- a/plugin/src/main/resources/org/elasticsearch/xpack/ssl/public.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsF9ARBhmY9ZwDD3f2LxF -Gxrbv6rF3fbKwm71oqBISIgMUpTQnAWHqmiDWXx+sgIziMXROogsYe/5BtBiwPZ7 -eNinRyPx3Lb5g3qOBNcx/U3zKHoZhcTNGsQpiGpVMculmBuHEQXGzCyBmIQweJXG -fqHmLi5YOaSnrO3iQeUqC+O0gTNnXGJdZxLuMm9U9vyvTFQU8O7xCKMGGPGRuRem -vOMYS23hsqpnz9H6mv55S6+YCkxIwHfx1nENFfHJq9uZslwYMlf5ko3g5wQIfnkH -8S3GE/Gl8VeZf7LkuHn3u+SGCK3DxCFrJpryAXXq23itSBi5172QZKKbeGzpD2ZY -zwIDAQAB ------END PUBLIC KEY----- diff --git a/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java b/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java index ede64fdfbec..bb65bd543a8 100644 --- a/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/integration/ldap/AbstractAdLdapRealmTestCase.java @@ -34,7 +34,6 @@ import org.junit.BeforeClass; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.Arrays; @@ -221,8 +220,8 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase } @Override - protected boolean useGeneratedSSLConfig() { - return useGlobalSSL == false; + protected boolean transportSSLEnabled() { + return useGlobalSSL; } protected final void configureFileRoleMappings(Settings.Builder builder, List mappings) { diff --git a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java index 20ab893812d..d13be9b95fe 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java @@ -43,14 +43,12 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.rules.ExternalResource; -import java.io.IOException; import java.net.InetSocketAddress; import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.CountDownLatch; import java.util.function.Function; import java.util.stream.Collectors; @@ -169,12 +167,12 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { case SUITE: if (customSecuritySettingsSource == null) { customSecuritySettingsSource = - new CustomSecuritySettingsSource(useGeneratedSSLConfig(), createTempDir(), currentClusterScope); + new CustomSecuritySettingsSource(transportSSLEnabled(), createTempDir(), currentClusterScope); } break; case TEST: customSecuritySettingsSource = - new CustomSecuritySettingsSource(useGeneratedSSLConfig(), createTempDir(), currentClusterScope); + new CustomSecuritySettingsSource(transportSSLEnabled(), createTempDir(), currentClusterScope); break; } } @@ -325,7 +323,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { /** * Allows to control whether ssl key information is auto generated or not on the transport layer */ - protected boolean useGeneratedSSLConfig() { + protected boolean transportSSLEnabled() { return randomBoolean(); } @@ -339,8 +337,8 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { private class CustomSecuritySettingsSource extends SecuritySettingsSource { - private CustomSecuritySettingsSource(boolean useGeneratedSSLConfig, Path configDir, Scope scope) { - super(maxNumberOfNodes(), useGeneratedSSLConfig, configDir, scope); + private CustomSecuritySettingsSource(boolean sslEnabled, Path configDir, Scope scope) { + super(maxNumberOfNodes(), sslEnabled, configDir, scope); } @Override diff --git a/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index 911fca36e98..6aeec9c236a 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -79,7 +79,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas private final Path parentFolder; private final String subfolderPrefix; - private final boolean useGeneratedSSLConfig; + private final boolean sslEnabled; private final boolean hostnameVerificationEnabled; private final boolean usePEM; @@ -87,15 +87,15 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas * Creates a new {@link org.elasticsearch.test.NodeConfigurationSource} for the security configuration. * * @param numOfNodes the number of nodes for proper unicast configuration (can be more than actually available) - * @param useGeneratedSSLConfig whether ssl key/cert should be auto-generated + * @param sslEnabled whether ssl is enabled * @param parentFolder the parent folder that will contain all of the configuration files that need to be created * @param scope the scope of the test that is requiring an instance of SecuritySettingsSource */ - public SecuritySettingsSource(int numOfNodes, boolean useGeneratedSSLConfig, Path parentFolder, Scope scope) { + public SecuritySettingsSource(int numOfNodes, boolean sslEnabled, Path parentFolder, Scope scope) { super(numOfNodes, DEFAULT_SETTINGS); this.parentFolder = parentFolder; this.subfolderPrefix = scope.name(); - this.useGeneratedSSLConfig = useGeneratedSSLConfig; + this.sslEnabled = sslEnabled; this.hostnameVerificationEnabled = randomBoolean(); this.usePEM = randomBoolean(); } @@ -203,20 +203,24 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas } private void addNodeSSLSettings(Settings.Builder builder) { - if (usePEM) { - addSSLSettingsForPEMFiles(builder, "", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", - Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.crt", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/active-directory-ca.crt", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/openldap.crt", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), - useGeneratedSSLConfig, hostnameVerificationEnabled, false); + if (sslEnabled) { + if (usePEM) { + addSSLSettingsForPEMFiles(builder, "", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-client-profile.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/active-directory-ca.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/openldap.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), + sslEnabled, hostnameVerificationEnabled, false); - } else { - addSSLSettingsForStore(builder, "", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", - "testnode", useGeneratedSSLConfig, hostnameVerificationEnabled, false); + } else { + addSSLSettingsForStore(builder, "", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks", + "testnode", sslEnabled, hostnameVerificationEnabled, false); + } + } else if (randomBoolean()) { + builder.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), false); } } @@ -227,10 +231,10 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), - useGeneratedSSLConfig, hostnameVerificationEnabled, true); + sslEnabled, hostnameVerificationEnabled, true); } else { addSSLSettingsForStore(builder, prefix, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", - "testclient", useGeneratedSSLConfig, hostnameVerificationEnabled, true); + "testclient", sslEnabled, hostnameVerificationEnabled, true); } } @@ -241,31 +245,30 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas * @param password the password */ public static void addSSLSettingsForStore(Settings.Builder builder, String resourcePathToStore, String password) { - addSSLSettingsForStore(builder, "", resourcePathToStore, password, false, true, true); + addSSLSettingsForStore(builder, "", resourcePathToStore, password, true, true, true); } private static void addSSLSettingsForStore(Settings.Builder builder, String prefix, String resourcePathToStore, String password, - boolean useGeneratedSSLConfig, boolean hostnameVerificationEnabled, + boolean sslEnabled, boolean hostnameVerificationEnabled, boolean transportClient) { Path store = resolveResourcePath(resourcePathToStore); if (transportClient == false) { builder.put(prefix + "xpack.security.http.ssl.enabled", false); } + builder.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslEnabled); builder.put(prefix + "xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); - if (useGeneratedSSLConfig == false) { - builder.put(prefix + "xpack.ssl.keystore.path", store); - if (transportClient) { - // continue using insecure settings for clients until we figure out what to do there... - builder.put(prefix + "xpack.ssl.keystore.password", password); - } else { - addSecureSettings(builder, secureSettings -> - secureSettings.setString(prefix + "xpack.ssl.keystore.secure_password", password)); - } + builder.put(prefix + "xpack.ssl.keystore.path", store); + if (transportClient) { + // continue using insecure settings for clients until we figure out what to do there... + builder.put(prefix + "xpack.ssl.keystore.password", password); + } else { + addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "xpack.ssl.keystore.secure_password", password)); } - if (useGeneratedSSLConfig == false && true /*randomBoolean()*/) { + if (randomBoolean()) { builder.put(prefix + "xpack.ssl.truststore.path", store); if (transportClient) { // continue using insecure settings for clients until we figure out what to do there... @@ -278,29 +281,28 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas } private static void addSSLSettingsForPEMFiles(Settings.Builder builder, String prefix, String keyPath, String password, - String certificatePath, List trustedCertificates, boolean useGeneratedSSLConfig, + String certificatePath, List trustedCertificates, boolean sslEnabled, boolean hostnameVerificationEnabled, boolean transportClient) { if (transportClient == false) { builder.put(prefix + "xpack.security.http.ssl.enabled", false); } + builder.put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), sslEnabled); builder.put(prefix + "xpack.ssl.verification_mode", hostnameVerificationEnabled ? "full" : "certificate"); - if (useGeneratedSSLConfig == false) { - builder.put(prefix + "xpack.ssl.key", resolveResourcePath(keyPath)) - .put(prefix + "xpack.ssl.certificate", resolveResourcePath(certificatePath)); - if (transportClient) { - // continue using insecure settings for clients until we figure out what to do there... - builder.put(prefix + "xpack.ssl.key_passphrase", password); - } else { - addSecureSettings(builder, secureSettings -> - secureSettings.setString(prefix + "xpack.ssl.secure_key_passphrase", password)); - } + builder.put(prefix + "xpack.ssl.key", resolveResourcePath(keyPath)) + .put(prefix + "xpack.ssl.certificate", resolveResourcePath(certificatePath)); + if (transportClient) { + // continue using insecure settings for clients until we figure out what to do there... + builder.put(prefix + "xpack.ssl.key_passphrase", password); + } else { + addSecureSettings(builder, secureSettings -> + secureSettings.setString(prefix + "xpack.ssl.secure_key_passphrase", password)); + } - if (trustedCertificates.isEmpty() == false) { - builder.put(prefix + "xpack.ssl.certificate_authorities", - Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates))); - } + if (trustedCertificates.isEmpty() == false) { + builder.put(prefix + "xpack.ssl.certificate_authorities", + Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates))); } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java index e5c433341c5..d5f4041d2d8 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/PkiRealmBootstrapCheckTests.java @@ -26,6 +26,12 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase { .put("path.home", createTempDir()) .build(); Environment env = new Environment(settings); + assertTrue(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure()); + + // enable transport tls + settings = Settings.builder().put(settings) + .put("xpack.security.transport.ssl.enabled", true) + .build(); assertFalse(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure()); // disable client auth default diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTribeIT.java b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTribeIT.java index 128d2141f27..36ca4f95b57 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTribeIT.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/SecurityTribeIT.java @@ -69,14 +69,14 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase { private static final String SECOND_CLUSTER_NODE_PREFIX = "node_cluster2_"; private static InternalTestCluster cluster2; - private static boolean useGeneratedSSL; + private static boolean useSSL; private Node tribeNode; private Client tribeClient; @BeforeClass public static void setupSSL() { - useGeneratedSSL = randomBoolean(); + useSSL = randomBoolean(); } @Override @@ -84,7 +84,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase { super.setUp(); if (cluster2 == null) { SecuritySettingsSource cluster2SettingsSource = - new SecuritySettingsSource(defaultMaxNumberOfNodes(), useGeneratedSSL, createTempDir(), Scope.SUITE) { + new SecuritySettingsSource(defaultMaxNumberOfNodes(), useSSL, createTempDir(), Scope.SUITE) { @Override public Settings nodeSettings(int nodeOrdinal) { Settings.Builder builder = Settings.builder() @@ -118,8 +118,8 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase { } @Override - public boolean useGeneratedSSLConfig() { - return useGeneratedSSL; + public boolean transportSSLEnabled() { + return useSSL; } @AfterClass @@ -216,7 +216,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase { private void setupTribeNode(Settings settings) throws Exception { SecuritySettingsSource cluster2SettingsSource = - new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST) { + new SecuritySettingsSource(1, useSSL, createTempDir(), Scope.TEST) { @Override public Settings nodeSettings(int nodeOrdinal) { return Settings.builder() diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java index 7b57b1825c6..91a49272ce9 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/AuditTrailTests.java @@ -35,7 +35,6 @@ import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import static org.elasticsearch.test.SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING; -import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -79,7 +78,7 @@ public class AuditTrailTests extends SecurityIntegTestCase { } @Override - public boolean useGeneratedSSLConfig() { + public boolean transportSSLEnabled() { return true; } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java index cbaf1f5aab6..c71d34abe8d 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrailTests.java @@ -84,6 +84,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { public static final String SECOND_CLUSTER_NODE_PREFIX = "remote_" + SUITE_CLUSTER_NODE_PREFIX; private static boolean remoteIndexing; + private static boolean useSSL; private static InternalTestCluster remoteCluster; private static Settings remoteSettings; @@ -99,6 +100,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { @BeforeClass public static void configureBeforeClass() { + useSSL = randomBoolean(); remoteIndexing = randomBoolean(); if (remoteIndexing == false) { remoteSettings = Settings.EMPTY; @@ -114,6 +116,11 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { remoteSettings = null; } + @Override + protected boolean transportSSLEnabled() { + return useSSL; + } + @Before public void initializeRemoteClusterIfNecessary() throws Exception { if (remoteIndexing == false) { @@ -131,11 +138,11 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { // Setup a second test cluster with randomization for number of nodes, security enabled, and SSL final int numNodes = randomIntBetween(1, 2); final boolean useSecurity = randomBoolean(); - final boolean useGeneratedSSL = useSecurity && randomBoolean(); - logger.info("--> remote indexing enabled. security enabled: [{}], SSL enabled: [{}], nodes: [{}]", useSecurity, useGeneratedSSL, + final boolean remoteUseSSL = useSecurity && useSSL; + logger.info("--> remote indexing enabled. security enabled: [{}], SSL enabled: [{}], nodes: [{}]", useSecurity, useSSL, numNodes); SecuritySettingsSource cluster2SettingsSource = - new SecuritySettingsSource(numNodes, useGeneratedSSL, createTempDir(), Scope.SUITE) { + new SecuritySettingsSource(numNodes, useSSL, createTempDir(), Scope.SUITE) { @Override public Settings nodeSettings(int nodeOrdinal) { Settings.Builder builder = Settings.builder() @@ -192,8 +199,9 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase { .put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.TEST_USER_NAME + ":" + SecuritySettingsSource.TEST_PASSWORD); - if (useGeneratedSSL == false) { + if (remoteUseSSL) { cluster2SettingsSource.addClientSSLSettings(builder, "xpack.security.audit.index.client."); + builder.put("xpack.security.audit.index.client.xpack.security.transport.ssl.enabled", true); } if (useSecurity == false && builder.get(NetworkModule.TRANSPORT_TYPE_KEY) == null) { builder.put("xpack.security.audit.index.client." + NetworkModule.TRANSPORT_TYPE_KEY, getTestTransportType()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java index c40187e9ee9..5a73ae6a460 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/audit/index/RemoteIndexAuditTrailStartingTests.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.StreamSupport; @@ -50,13 +49,13 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase { private InternalTestCluster remoteCluster; - private final boolean useGeneratedSSL = randomBoolean(); + private final boolean sslEnabled = randomBoolean(); private final boolean localAudit = randomBoolean(); private final String outputs = randomFrom("index", "logfile", "index,logfile"); @Override - public boolean useGeneratedSSLConfig() { - return useGeneratedSSL; + public boolean transportSSLEnabled() { + return sslEnabled; } @Override @@ -90,7 +89,7 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase { // Setup a second test cluster with a single node, security enabled, and SSL final int numNodes = 1; SecuritySettingsSource cluster2SettingsSource = - new SecuritySettingsSource(numNodes, useGeneratedSSL, createTempDir(), Scope.TEST) { + new SecuritySettingsSource(numNodes, sslEnabled, createTempDir(), Scope.TEST) { @Override public Settings nodeSettings(int nodeOrdinal) { Settings.Builder builder = Settings.builder() @@ -104,6 +103,7 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase { .put("xpack.security.audit.index.client.xpack.security.user", TEST_USER_NAME + ":" + TEST_PASSWORD); addClientSSLSettings(builder, "xpack.security.audit.index.client."); + builder.put("xpack.security.audit.index.client.xpack.security.transport.ssl.enabled", sslEnabled); return builder.build(); } }; diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java index c447d0a80c1..37d9b794571 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java @@ -83,8 +83,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase { } @Override - public boolean useGeneratedSSLConfig() { - return true; + protected boolean transportSSLEnabled() { + return false; } public void testUserImpersonation() throws Exception { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java index 57f8cc4be85..09728b4dcbf 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java @@ -17,7 +17,6 @@ import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.support.CharArrays; import org.elasticsearch.xpack.security.client.SecurityClient; -import org.junit.AfterClass; import org.junit.BeforeClass; import java.nio.charset.StandardCharsets; @@ -52,9 +51,9 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { + protected boolean transportSSLEnabled() { // don't use autogenerated when we expect a different cert - return useSSL == false; + return useSSL; } @Override diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java index 2ac9cc59477..2f9ca0b2532 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java @@ -15,7 +15,6 @@ import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.network.NetworkModule; -import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.http.HttpServerTransport; @@ -73,8 +72,8 @@ public class PkiAuthenticationTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } public void testTransportClientCanAuthenticateViaPki() { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java index 280c4c86623..f6f77587c79 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiOptionalClientAuthTests.java @@ -66,8 +66,8 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } public void testRestClientWithoutClientCertificate() throws Exception { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java index b2c08846530..cf885973adf 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java @@ -13,8 +13,6 @@ import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.discovery.MasterNotDiscoveredException; import org.elasticsearch.node.MockNode; import org.elasticsearch.node.Node; import org.elasticsearch.node.NodeValidationException; @@ -42,7 +40,6 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.concurrent.CountDownLatch; -import static java.util.Collections.singletonMap; import static org.elasticsearch.test.SecuritySettingsSource.addSSLSettingsForStore; import static org.elasticsearch.xpack.security.test.SecurityTestUtils.writeFile; import static org.hamcrest.CoreMatchers.equalTo; @@ -57,10 +54,9 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase randomClientPort = randomIntBetween(49000, 65500); // ephemeral port } - // don't use it here to simplify the settings we need @Override - public boolean useGeneratedSSLConfig() { - return false; + public boolean transportSSLEnabled() { + return true; } @Override diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java index 1bd038cd9cd..288d23d43fc 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/DNSOnlyHostnameVerificationTests.java @@ -87,8 +87,8 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase { } @Override - public boolean useGeneratedSSLConfig() { - return false; + public boolean transportSSLEnabled() { + return true; } @Override diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java index 175606a39f8..3b3139d121c 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/IPHostnameVerificationTests.java @@ -23,8 +23,8 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase { Path keystore; @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } @Override diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java index 7b7fe359084..68813ed8806 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4TransportTests.java @@ -42,6 +42,7 @@ public class SecurityNetty4TransportTests extends ESTestCase { MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); Settings settings = Settings.builder() + .put("xpack.security.transport.ssl.enabled", true) .put("xpack.ssl.keystore.path", testnodeStore) .setSecureSettings(secureSettings) .put("path.home", createTempDir()) @@ -51,12 +52,13 @@ public class SecurityNetty4TransportTests extends ESTestCase { } private SecurityNetty4Transport createTransport() { - return createTransport(Settings.EMPTY); + return createTransport(Settings.builder().put("xpack.security.transport.ssl.enabled", true).build()); } private SecurityNetty4Transport createTransport(Settings additionalSettings) { final Settings settings = Settings.builder() + .put("xpack.security.transport.ssl.enabled", true) .put(additionalSettings) .build(); return new SecurityNetty4Transport( @@ -185,6 +187,7 @@ public class SecurityNetty4TransportTests extends ESTestCase { secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode"); secureSettings.setString("xpack.ssl.truststore.secure_password", "truststore-testnode-only"); Settings.Builder builder = Settings.builder() + .put("xpack.security.transport.ssl.enabled", true) .put("xpack.security.transport.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")) .put("xpack.security.transport.ssl.client_authentication", "none") diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java index 24fbc30bd9f..98abdf787a5 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SslHostnameVerificationTests.java @@ -27,8 +27,8 @@ import static org.hamcrest.Matchers.containsString; public class SslHostnameVerificationTests extends SecurityIntegTestCase { @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } @Override diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java index 768d9e3a27c..231f160a8a7 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java @@ -66,8 +66,8 @@ public class EllipticCurveSSLTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } public void testConnection() throws Exception { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java index 3ed07bcbc37..e4d64966900 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslIntegrationTests.java @@ -51,8 +51,8 @@ public class SslIntegrationTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } // no SSL exception as this is the exception is returned when connecting diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java index 4ef9599b33b..29607faa41a 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java @@ -73,8 +73,8 @@ public class SslMultiPortTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } private TransportClient createTransportClient(Settings additionalSettings) { @@ -82,6 +82,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { .put(transportClientSettings().filter(s -> s.startsWith("xpack.ssl") == false)) .put("node.name", "programmatic_transport_client") .put("cluster.name", internalCluster().getClusterName()) + .put("xpack.security.transport.ssl.enabled", true) .put(additionalSettings) .build(); return new TestXPackTransportClient(settings); @@ -105,6 +106,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { public void testThatStandardTransportClientCanConnectToNoClientAuthProfile() throws Exception { try(TransportClient transportClient = new TestXPackTransportClient(Settings.builder() .put(transportClientSettings()) + .put("xpack.security.transport.ssl.enabled", true) .put("node.name", "programmatic_transport_client") .put("cluster.name", internalCluster().getClusterName()) .build())) { @@ -247,6 +249,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) + .put("xpack.security.transport.ssl.enabled", true) .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) .put("xpack.ssl.truststore.password", "truststore-testnode-only") @@ -254,7 +257,6 @@ public class SslMultiPortTests extends SecurityIntegTestCase { try (TransportClient transportClient = new TestXPackTransportClient(settings)) { transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("no_client_auth"))); - assertGreenClusterState(transportClient); } } @@ -268,6 +270,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) + .put("xpack.security.transport.ssl.enabled", true) .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) @@ -292,6 +295,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { Settings settings = Settings.builder() .put(Security.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) + .put("xpack.security.transport.ssl.enabled", true) .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) .put("xpack.ssl.truststore.path", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/truststore-testnode-only.jks")) @@ -316,6 +320,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { .put(Security.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("xpack.security.transport.ssl.enabled", true) .build(); try (TransportClient transportClient = new TestXPackTransportClient(settings)) { transportClient.addTransportAddress(randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses())); @@ -336,6 +341,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { .put(Security.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("xpack.security.transport.ssl.enabled", true) .build(); try (TransportClient transportClient = new TestXPackTransportClient(settings)) { transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), getProfilePort("client"))); @@ -356,6 +362,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase { .put(Security.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) .put("xpack.ssl.client_authentication", SSLClientAuth.REQUIRED) + .put("xpack.security.transport.ssl.enabled", true) .build(); try (TransportClient transportClient = new TestXPackTransportClient(settings)) { transportClient.addTransportAddress(new TransportAddress(InetAddress.getLoopbackAddress(), diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslNullCipherTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslNullCipherTests.java index 4ea92016ed3..fb5d567bb36 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslNullCipherTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslNullCipherTests.java @@ -17,7 +17,7 @@ import org.elasticsearch.test.SecurityIntegTestCase; public class SslNullCipherTests extends SecurityIntegTestCase { @Override - public boolean useGeneratedSSLConfig() { + public boolean transportSSLEnabled() { return true; } @@ -25,7 +25,7 @@ public class SslNullCipherTests extends SecurityIntegTestCase { public Settings nodeSettings(int nodeOrdinal) { Settings settings = super.nodeSettings(nodeOrdinal); Settings.Builder builder = Settings.builder() - .put(settings.filter((s) -> s.startsWith("xpack.ssl") == false)); + .put(settings); builder.put("xpack.security.transport.ssl.cipher_suites", "TLS_RSA_WITH_NULL_SHA256"); return builder.build(); } @@ -34,7 +34,7 @@ public class SslNullCipherTests extends SecurityIntegTestCase { public Settings transportClientSettings() { Settings settings = super.transportClientSettings(); Settings.Builder builder = Settings.builder() - .put(settings.filter((s) -> s.startsWith("xpack.ssl") == false)); + .put(settings); builder.put("xpack.security.transport.ssl.cipher_suites", "TLS_RSA_WITH_NULL_SHA256"); return builder.build(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfigTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfigTests.java deleted file mode 100644 index add53b1e034..00000000000 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/GeneratedKeyConfigTests.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.ssl; - -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.node.Node; -import org.elasticsearch.test.ESTestCase; - -import javax.net.ssl.X509ExtendedKeyManager; - -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; - -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; - -public class GeneratedKeyConfigTests extends ESTestCase { - - public void testGenerating() throws Exception { - Settings settings = Settings.builder().put(Node.NODE_NAME_SETTING.getKey(), randomAlphaOfLengthBetween(1, 8)).build(); - GeneratedKeyConfig keyConfig = new GeneratedKeyConfig(settings); - assertThat(keyConfig.filesToMonitor(null), is(empty())); - X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(null); - assertNotNull(keyManager); - assertNotNull(keyConfig.createTrustManager(null)); - - String[] aliases = keyManager.getServerAliases("RSA", null); - assertEquals(1, aliases.length); - PrivateKey privateKey = keyManager.getPrivateKey(aliases[0]); - assertNotNull(privateKey); - assertThat(privateKey, instanceOf(RSAPrivateKey.class)); - X509Certificate[] certificates = keyManager.getCertificateChain(aliases[0]); - assertEquals(2, certificates.length); - assertEquals(GeneratedKeyConfig.readCACert(), certificates[1]); - - X509Certificate generatedCertificate = certificates[0]; - assertEquals("CN=" + Node.NODE_NAME_SETTING.get(settings), generatedCertificate.getSubjectX500Principal().getName()); - assertEquals(certificates[1].getSubjectX500Principal(), generatedCertificate.getIssuerX500Principal()); - } -} diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java deleted file mode 100644 index 22e9e830ae0..00000000000 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLBootstrapCheckTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.ssl; - -import org.elasticsearch.bootstrap.BootstrapContext; -import org.elasticsearch.common.settings.MockSecureSettings; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.test.ESTestCase; - -public class SSLBootstrapCheckTests extends ESTestCase { - - public void testSSLBootstrapCheckWithNoKey() throws Exception { - SSLService sslService = new SSLService(Settings.EMPTY, null); - SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(sslService, null); - assertTrue(bootstrapCheck.check(new BootstrapContext(Settings.EMPTY, null)).isFailure()); - } - - public void testSSLBootstrapCheckWithKey() throws Exception { - final String keyPrefix = randomBoolean() ? "security.transport." : ""; - MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString("xpack." + keyPrefix + "ssl.secure_key_passphrase", "testclient"); - Settings settings = Settings.builder() - .put("path.home", createTempDir()) - .put("xpack." + keyPrefix + "ssl.key", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem")) - .put("xpack." + keyPrefix + "ssl.certificate", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt")) - .setSecureSettings(secureSettings) - .build(); - final Environment env = randomBoolean() ? new Environment(settings) : null; - SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), env); - assertFalse(bootstrapCheck.check(new BootstrapContext(settings, null)).isFailure()); - } - - public void testSSLBootstrapCheckWithDefaultCABeingTrusted() throws Exception { - final String keyPrefix = randomBoolean() ? "security.transport." : ""; - MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString("xpack." + keyPrefix + "ssl.secure_key_passphrase", "testclient"); - Settings settings = Settings.builder() - .put("path.home", createTempDir()) - .put("xpack." + keyPrefix + "ssl.key", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem")) - .put("xpack." + keyPrefix + "ssl.certificate", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt")) - .putArray("xpack." + keyPrefix + "ssl.certificate_authorities", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt").toString(), - getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString()) - .setSecureSettings(secureSettings) - .build(); - final Environment env = randomBoolean() ? new Environment(settings) : null; - SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), env); - assertTrue(bootstrapCheck.check(new BootstrapContext(settings, null)).isFailure()); - - settings = Settings.builder().put(settings.filter((s) -> s.contains(".certificate_authorities"))) - .put("xpack.security.http.ssl.certificate_authorities", - getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString()) - .build(); - bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), env); - assertTrue(bootstrapCheck.check(new BootstrapContext(settings, null)).isFailure()); - } - - public void testSSLBootstrapCheckWithDefaultKeyBeingUsed() throws Exception { - final String keyPrefix = randomBoolean() ? "security.transport." : ""; - MockSecureSettings secureSettings = new MockSecureSettings(); - secureSettings.setString("xpack." + keyPrefix + "ssl.secure_key_passphrase", "testclient"); - Settings settings = Settings.builder() - .put("path.home", createTempDir()) - .put("xpack." + keyPrefix + "ssl.key", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem")) - .put("xpack." + keyPrefix + "ssl.certificate", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt")) - .put("xpack.security.http.ssl.key", getDataPath("/org/elasticsearch/xpack/ssl/private.pem").toString()) - .put("xpack.security.http.ssl.certificate", getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString()) - .setSecureSettings(secureSettings) - .build(); - final Environment env = randomBoolean() ? new Environment(settings) : null; - SSLBootstrapCheck bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), env); - assertTrue(bootstrapCheck.check(new BootstrapContext(settings, null)).isFailure()); - - settings = Settings.builder().put(settings.filter((s) -> s.contains(".http.ssl."))) - .put("xpack.security.transport.profiles.foo.xpack.security.ssl.key", - getDataPath("/org/elasticsearch/xpack/ssl/private.pem").toString()) - .put("xpack.security.transport.profiles.foo.xpack.security.ssl.certificate", - getDataPath("/org/elasticsearch/xpack/ssl/ca.pem").toString()) - .build(); - bootstrapCheck = new SSLBootstrapCheck(new SSLService(settings, env), env); - assertTrue(bootstrapCheck.check(new BootstrapContext(settings, null)).isFailure()); - } -} diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java index dd3baab7b9e..f6e7e74115d 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java @@ -56,8 +56,8 @@ public class SSLClientAuthTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } public void testThatHttpFailsWithoutSslClientAuth() throws IOException { @@ -93,6 +93,7 @@ public class SSLClientAuthTests extends SecurityIntegTestCase { MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString("xpack.ssl.keystore.secure_password", "testclient-client-profile"); Settings settings = Settings.builder() + .put("xpack.security.transport.ssl.enabled", true) .put("xpack.ssl.client_authentication", SSLClientAuth.NONE) .put("xpack.ssl.keystore.path", store) .setSecureSettings(secureSettings) diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java index 5a4a552629a..795bb2d2dc8 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationReloaderTests.java @@ -219,15 +219,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase { .setSecureSettings(secureSettings) .build(); Environment env = randomBoolean() ? null : new Environment(settings); - final X500Principal expectedPrincipal = new X500Principal("CN=xpack public development ca"); final SetOnce trustedCount = new SetOnce<>(); final BiConsumer trustManagerPreChecks = (trustManager, config) -> { // trust manager checks Certificate[] certificates = trustManager.getAcceptedIssuers(); trustedCount.set(certificates.length); - assertTrue(Arrays.stream(trustManager.getAcceptedIssuers()) - .anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal()))); }; @@ -247,8 +244,6 @@ public class SSLConfigurationReloaderTests extends ESTestCase { final BiConsumer trustManagerPostChecks = (updatedTrustManager, config) -> { assertThat(trustedCount.get() - updatedTrustManager.getAcceptedIssuers().length, is(5)); - assertTrue(Arrays.stream(updatedTrustManager.getAcceptedIssuers()) - .anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal()))); }; validateTrustConfigurationIsReloaded(settings, env, trustManagerPreChecks, modifier, trustManagerPostChecks); @@ -267,15 +262,12 @@ public class SSLConfigurationReloaderTests extends ESTestCase { .put("path.home", createTempDir()) .build(); Environment env = randomBoolean() ? null : new Environment(settings); - final X500Principal expectedPrincipal = new X500Principal("CN=xpack public development ca"); final BiConsumer trustManagerPreChecks = (trustManager, config) -> { // trust manager checks Certificate[] certificates = trustManager.getAcceptedIssuers(); - assertThat(certificates.length, is(2)); + assertThat(certificates.length, is(1)); assertThat(((X509Certificate)certificates[0]).getSubjectX500Principal().getName(), containsString("Test Client")); - assertTrue(Arrays.stream(trustManager.getAcceptedIssuers()) - .anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal()))); }; final Runnable modifier = () -> { @@ -291,10 +283,8 @@ public class SSLConfigurationReloaderTests extends ESTestCase { final BiConsumer trustManagerPostChecks = (updatedTrustManager, config) -> { Certificate[] updatedCerts = updatedTrustManager.getAcceptedIssuers(); - assertThat(updatedCerts.length, is(2)); + assertThat(updatedCerts.length, is(1)); assertThat(((X509Certificate)updatedCerts[0]).getSubjectX500Principal().getName(), containsString("Test Node")); - assertTrue(Arrays.stream(updatedTrustManager.getAcceptedIssuers()) - .anyMatch((cert) -> expectedPrincipal.equals(cert.getSubjectX500Principal()))); }; validateTrustConfigurationIsReloaded(settings, env, trustManagerPreChecks, modifier, trustManagerPostChecks); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java index b7a4c506674..5cb9b7de45a 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java @@ -85,8 +85,8 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } public void testThatSSLConfigurationReloadsOnModification() throws Exception { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java index 1a4bb0f793b..97c376a1700 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java @@ -134,8 +134,8 @@ public class SSLTrustRestrictionsTests extends SecurityIntegTestCase { } @Override - protected boolean useGeneratedSSLConfig() { - return false; + protected boolean transportSSLEnabled() { + return true; } public void testCertificateWithTrustedNameIsAccepted() throws Exception { diff --git a/qa/rolling-upgrade/build.gradle b/qa/rolling-upgrade/build.gradle index a1f3d9d7b87..7e3a94f10e3 100644 --- a/qa/rolling-upgrade/build.gradle +++ b/qa/rolling-upgrade/build.gradle @@ -159,6 +159,7 @@ subprojects { unicastTransportUri = { seedNode, node, ant -> oldClusterTest.nodes.get(0).transportUri() } dataDir = { nodeNumber -> oldClusterTest.nodes[1].dataDir } waitCondition = waitWithAuth + setting 'xpack.security.transport.ssl.enabled', 'true' setting 'xpack.ssl.keystore.path', 'testnode.jks' keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' setting 'node.attr.upgraded', 'first' @@ -190,6 +191,7 @@ subprojects { unicastTransportUri = { seedNode, node, ant -> mixedClusterTest.nodes.get(0).transportUri() } dataDir = { nodeNumber -> oldClusterTest.nodes[0].dataDir } waitCondition = waitWithAuth + setting 'xpack.security.transport.ssl.enabled', 'true' setting 'xpack.ssl.keystore.path', 'testnode.jks' keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' setting 'xpack.security.authc.token.enabled', 'true' diff --git a/qa/smoke-test-plugins-ssl/build.gradle b/qa/smoke-test-plugins-ssl/build.gradle index a8a02f46655..478822277bc 100644 --- a/qa/smoke-test-plugins-ssl/build.gradle +++ b/qa/smoke-test-plugins-ssl/build.gradle @@ -154,6 +154,8 @@ processTestResources.dependsOn( importNodeCertificateInClientKeyStore, importClientCertificateInNodeKeyStore ) +integTestCluster.dependsOn(importClientCertificateInNodeKeyStore) + ext.pluginsCount = 1 // we install xpack explicitly project.rootProject.subprojects.findAll { it.path.startsWith(':plugins:') }.each { subproj -> // need to get a non-decorated project object, so must re-lookup the project by path From 89977928751ead5d7703f713150a77a7751375a6 Mon Sep 17 00:00:00 2001 From: jaymode Date: Thu, 14 Sep 2017 15:57:28 -0600 Subject: [PATCH 5/9] Test: use TLS for plugin integ tests Original commit: elastic/x-pack-elasticsearch@99971d72566b85a3a04314f908089a8ce3048a2d --- plugin/build.gradle | 39 +++++++++++++++++++ .../MlNativeAutodetectIntegTestCase.java | 13 +++++++ 2 files changed, 52 insertions(+) diff --git a/plugin/build.gradle b/plugin/build.gradle index a801c2d6689..fd2640835aa 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -1,3 +1,4 @@ +import org.elasticsearch.gradle.LoggedExec import org.elasticsearch.gradle.MavenFilteringHack import org.elasticsearch.gradle.test.NodeInfo @@ -198,7 +199,39 @@ integTestRunner { systemProperty 'tests.rest.blacklist', 'getting_started/10_monitor_cluster_health/*' } +// location of generated keystores and certificates +File keystoreDir = new File(project.buildDir, 'keystore') + +// Generate the node's keystore +File nodeKeystore = new File(keystoreDir, 'test-node.jks') +task createNodeKeyStore(type: LoggedExec) { + doFirst { + if (nodeKeystore.parentFile.exists() == false) { + nodeKeystore.parentFile.mkdirs() + } + if (nodeKeystore.exists()) { + delete nodeKeystore + } + } + executable = new File(project.javaHome, 'bin/keytool') + standardInput = new ByteArrayInputStream('FirstName LastName\nUnit\nOrganization\nCity\nState\nNL\nyes\n\n'.getBytes('UTF-8')) + args '-genkey', + '-alias', 'test-node', + '-keystore', nodeKeystore, + '-keyalg', 'RSA', + '-keysize', '2048', + '-validity', '712', + '-dname', 'CN=smoke-test-plugins-ssl', + '-keypass', 'keypass', + '-storepass', 'keypass' +} + +// Add keystores to test classpath: it expects it there +sourceSets.test.resources.srcDir(keystoreDir) +processTestResources.dependsOn(createNodeKeyStore) + integTestCluster { + dependsOn createNodeKeyStore setting 'xpack.ml.enabled', 'true' setting 'logger.org.elasticsearch.xpack.ml.datafeed', 'TRACE' // Integration tests are supposed to enable/disable exporters before/after each test @@ -206,11 +239,17 @@ integTestCluster { setting 'xpack.monitoring.exporters._local.enabled', 'false' setting 'xpack.monitoring.collection.interval', '-1' setting 'xpack.security.authc.token.enabled', 'true' + setting 'xpack.security.transport.ssl.enabled', 'true' + setting 'xpack.security.transport.ssl.keystore.path', nodeKeystore.name + setting 'xpack.security.transport.ssl.verification_mode', 'certificate' keystoreSetting 'bootstrap.password', 'x-pack-test-password' + keystoreSetting 'xpack.security.transport.ssl.keystore.secure_password', 'keypass' distribution = 'zip' // this is important since we use the reindex module in ML setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'x_pack_rest_user', '-p', 'x-pack-test-password', '-r', 'superuser' + extraConfigFile nodeKeystore.name, nodeKeystore + waitCondition = { NodeInfo node, AntBuilder ant -> File tmpFile = new File(node.cwd, 'wait.success') diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/MlNativeAutodetectIntegTestCase.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/MlNativeAutodetectIntegTestCase.java index f16936aadea..891d02ace1c 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/MlNativeAutodetectIntegTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/MlNativeAutodetectIntegTestCase.java @@ -11,6 +11,7 @@ import org.elasticsearch.cluster.ClusterModule; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; @@ -60,6 +61,8 @@ import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.authc.TokenMetaData; import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -80,10 +83,20 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase { @Override protected Settings externalClusterClientSettings() { + Path keyStore; + try { + keyStore = PathUtils.get(getClass().getResource("/test-node.jks").toURI()); + } catch (URISyntaxException e) { + throw new IllegalStateException("error trying to get keystore path", e); + } Settings.Builder builder = Settings.builder(); builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4); builder.put(Security.USER_SETTING.getKey(), "x_pack_rest_user:" + SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING); builder.put(XPackSettings.MACHINE_LEARNING_ENABLED.getKey(), true); + builder.put("xpack.security.transport.ssl.enabled", true); + builder.put("xpack.security.transport.ssl.keystore.path", keyStore.toAbsolutePath().toString()); + builder.put("xpack.security.transport.ssl.keystore.password", "keypass"); + builder.put("xpack.security.transport.ssl.verification_mode", "certificate"); return builder.build(); } From 4d20586b2462c393a6cce3e4cb2d1bd918e8ce9a Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Fri, 15 Sep 2017 14:46:44 +0200 Subject: [PATCH 6/9] [TEST] add integration test that ensures we reject license upgrades if TLS is not enabled Original commit: elastic/x-pack-elasticsearch@dfbadb5e5f7fbccac52ac6d613d6db8a01418dad --- .../LicenseServiceWithSecurityTests.java | 53 +++++++++++++++++++ .../test/SecurityIntegTestCase.java | 4 ++ .../test/SecuritySettingsSource.java | 4 ++ 3 files changed, 61 insertions(+) create mode 100644 plugin/src/test/java/org/elasticsearch/license/LicenseServiceWithSecurityTests.java diff --git a/plugin/src/test/java/org/elasticsearch/license/LicenseServiceWithSecurityTests.java b/plugin/src/test/java/org/elasticsearch/license/LicenseServiceWithSecurityTests.java new file mode 100644 index 00000000000..4b7895cda52 --- /dev/null +++ b/plugin/src/test/java/org/elasticsearch/license/LicenseServiceWithSecurityTests.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.license; + +import org.elasticsearch.analysis.common.CommonAnalysisPlugin; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.test.SecurityIntegTestCase; +import org.elasticsearch.transport.Netty4Plugin; +import org.elasticsearch.xpack.XPackPlugin; + +import java.util.Arrays; +import java.util.Collection; + +import static org.hamcrest.CoreMatchers.equalTo; + +/** + * Basic integration test that checks if license can be upgraded to a production license if TLS is enabled and vice versa. + */ +public class LicenseServiceWithSecurityTests extends SecurityIntegTestCase { + + @Override + protected Collection> nodePlugins() { + return Arrays.asList(XPackPlugin.class, CommonAnalysisPlugin.class, Netty4Plugin.class); + } + + @Override + protected Collection> transportClientPlugins() { + return nodePlugins(); + } + + public void testLicenseUpgradeFailsWithoutTLS() throws Exception { + assumeFalse("transport ssl is enabled", isTransportSSLEnabled()); + LicensingClient licensingClient = new LicensingClient(client()); + License license = licensingClient.prepareGetLicense().get().license(); + License prodLicense = TestUtils.generateSignedLicense("platinum", TimeValue.timeValueHours(24)); + IllegalStateException ise = expectThrows(IllegalStateException.class, () -> licensingClient.preparePutLicense(prodLicense).get()); + assertEquals("Can not upgrade to a production license unless TLS is configured or security is disabled", ise.getMessage()); + assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license)); + } + + public void testLicenseUpgradeSucceedsWithTLS() throws Exception { + assumeTrue("transport ssl is disabled", isTransportSSLEnabled()); + LicensingClient licensingClient = new LicensingClient(client()); + License prodLicense = TestUtils.generateSignedLicense("platinum", TimeValue.timeValueHours(24)); + PutLicenseResponse putLicenseResponse = licensingClient.preparePutLicense(prodLicense).get(); + assertEquals(putLicenseResponse.status(), LicensesStatus.VALID); + assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(prodLicense)); + } +} diff --git a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java index 7f9539d78e5..09632c649b1 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java @@ -518,4 +518,8 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase { } return null; } + + protected boolean isTransportSSLEnabled() { + return customSecuritySettingsSource.isSslEnabled(); + } } diff --git a/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index 6aeec9c236a..02bf772fa4c 100644 --- a/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/plugin/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -339,4 +339,8 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas throw new ElasticsearchException("exception while reading the store", e); } } + + public boolean isSslEnabled() { + return sslEnabled; + } } From 53d6d945f04e1d0ce85e7b8c698f47f77923d8e1 Mon Sep 17 00:00:00 2001 From: Jay Modi Date: Fri, 15 Sep 2017 08:44:03 -0600 Subject: [PATCH 7/9] Update documentation to reflect the latest TLS changes and licensing (elastic/x-pack-elasticsearch#2508) This commit updates to documentation and adds notes about TLS being required to install a license. Relates elastic/x-pack-elasticsearch#2463 Original commit: elastic/x-pack-elasticsearch@0d8bfb98eab055ce94d014f3fe07aaa3d49f4629 --- docs/en/security/getting-started.asciidoc | 3 ++- docs/en/security/securing-communications.asciidoc | 4 ++-- .../separating-node-client-traffic.asciidoc | 13 ------------- .../securing-communications/setting-up-ssl.asciidoc | 2 +- docs/en/settings/security-settings.asciidoc | 8 ++++---- 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/docs/en/security/getting-started.asciidoc b/docs/en/security/getting-started.asciidoc index 0a10e910f86..1375008b682 100644 --- a/docs/en/security/getting-started.asciidoc +++ b/docs/en/security/getting-started.asciidoc @@ -98,7 +98,8 @@ IMPORTANT: Once you get these basic security measures in place, we strongly recommend that you secure communications to and from nodes by configuring your cluster to use {xpack-ref}/ssl-tls.html[SSL/TLS encryption]. Nodes that do not have encryption enabled send passwords in plain - text! + text and will not be able to install a non-trial license that enables the use + of {security}. Depending on your security requirements, you might also want to: diff --git a/docs/en/security/securing-communications.asciidoc b/docs/en/security/securing-communications.asciidoc index f28221939d2..18c0f67eb08 100644 --- a/docs/en/security/securing-communications.asciidoc +++ b/docs/en/security/securing-communications.asciidoc @@ -4,8 +4,8 @@ Elasticsearch nodes store data that may be confidential. Attacks on the data may come from the network. These attacks could include sniffing of the data, manipulation of the data, and attempts to gain access to the server and thus the -files storing the data. Securing your nodes with the procedures below helps to -reduce risk from network-based attacks. +files storing the data. Securing your nodes is required in order to use a production +license that enables {security} and helps reduce the risk from network-based attacks. This section shows how to: diff --git a/docs/en/security/securing-communications/separating-node-client-traffic.asciidoc b/docs/en/security/securing-communications/separating-node-client-traffic.asciidoc index 8afb089ce9c..b5e126c1761 100644 --- a/docs/en/security/securing-communications/separating-node-client-traffic.asciidoc +++ b/docs/en/security/securing-communications/separating-node-client-traffic.asciidoc @@ -38,19 +38,6 @@ transport.profiles.client.bind_host: 1.1.1.1 <2> If separate networks are not available, then <> can be enabled to limit access to the profiles. -The TCP transport profiles also allow for enabling SSL on a per profile basis. -This is useful if you have a secured network for the node-to-node communication, -but the client is on an unsecured network. To enable SSL on a client profile when -SSL is disabled for node-to-node communication, add the following to -`elasticsearch.yml`: - -[source, yaml] --------------------------------------------------- -transport.profiles.client.xpack.security.ssl.enabled: true <1> --------------------------------------------------- -<1> This enables SSL on the client profile. The default value for this setting - is the value of `xpack.security.transport.ssl.enabled`. - When using SSL for transport, a different set of certificates can also be used for the client traffic by adding the following to `elasticsearch.yml`: diff --git a/docs/en/security/securing-communications/setting-up-ssl.asciidoc b/docs/en/security/securing-communications/setting-up-ssl.asciidoc index adde309bbaf..4c55ada41ca 100644 --- a/docs/en/security/securing-communications/setting-up-ssl.asciidoc +++ b/docs/en/security/securing-communications/setting-up-ssl.asciidoc @@ -6,7 +6,7 @@ cluster. Connections are secured using Transport Layer Security (TLS), which is commonly referred to as "SSL". WARNING: Clusters that do not have encryption enabled send all data in plain text -including passwords. +including passwords and will not be able to install a license that enables {security}. To enable encryption, you need to perform the following steps on each node in the cluster: diff --git a/docs/en/settings/security-settings.asciidoc b/docs/en/settings/security-settings.asciidoc index 8c0102d852d..52f6063bdaa 100644 --- a/docs/en/settings/security-settings.asciidoc +++ b/docs/en/settings/security-settings.asciidoc @@ -715,11 +715,11 @@ are also available for each transport profile. By default, the settings for a transport profile will be the same as the default transport unless they are specified. -As an example, lets look at the enabled setting. For the default transport -this is `xpack.security.transport.ssl.enabled`. In order to use this setting in a +As an example, lets look at the key setting. For the default transport +this is `xpack.security.transport.ssl.key`. In order to use this setting in a transport profile, use the prefix `transport.profiles.$PROFILE.xpack.security.` and -append the portion of the setting after `xpack.security.transport.`. For the enabled -setting, this would be `transport.profiles.$PROFILE.xpack.security.ssl.enabled`. +append the portion of the setting after `xpack.security.transport.`. For the key +setting, this would be `transport.profiles.$PROFILE.xpack.security.ssl.key`. [float] [[ip-filtering-settings]] From 344603e40f24324e784fcafabab42f27ef7cb9eb Mon Sep 17 00:00:00 2001 From: jaymode Date: Fri, 15 Sep 2017 08:56:34 -0600 Subject: [PATCH 8/9] update text in TLSLicenseBootstrapCheck Original commit: elastic/x-pack-elasticsearch@4ee6827566de2381ae338f54117f524b84f464b6 --- .../xpack/ssl/TLSLicenseBootstrapCheck.java | 20 ++----------------- .../ssl/TLSLicenseBootstrapCheckTests.java | 5 +++-- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java index 1b5109901db..c18da907f65 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheck.java @@ -5,29 +5,12 @@ */ package org.elasticsearch.xpack.ssl; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.bootstrap.BootstrapCheck; import org.elasticsearch.bootstrap.BootstrapContext; -import org.elasticsearch.common.inject.internal.Nullable; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; import org.elasticsearch.license.License; import org.elasticsearch.license.LicenseService; import org.elasticsearch.xpack.XPackSettings; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SignatureException; -import java.security.cert.CertificateException; -import java.util.Arrays; -import java.util.Objects; -import java.util.stream.Stream; - /** * Bootstrap check to ensure that if we are starting up with a production license in the local clusterstate TLS is enabled */ @@ -38,7 +21,8 @@ public final class TLSLicenseBootstrapCheck implements BootstrapCheck { License license = LicenseService.getLicense(context.metaData); if (license != null && license.isProductionLicense()) { return BootstrapCheckResult.failure("Transport SSL must be enabled for setups with production licenses. Please set " + - "[xpack.security.transport.ssl.enabled] or disables security via [xpack.security.enabled]"); + "[xpack.security.transport.ssl.enabled] to [true] or disable security by setting [xpack.security.enabled] " + + "to [false]"); } } return BootstrapCheckResult.success(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java index 7b4a3db51d1..048cfa9c01d 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/TLSLicenseBootstrapCheckTests.java @@ -34,8 +34,9 @@ public class TLSLicenseBootstrapCheckTests extends ESTestCase { } else { assertTrue(new TLSLicenseBootstrapCheck().check(new BootstrapContext( Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(), build)).isFailure()); - assertEquals("Transport SSL must be enabled for setups with production licenses." + - " Please set [xpack.security.transport.ssl.enabled] or disables security via [xpack.security.enabled]", + assertEquals("Transport SSL must be enabled for setups with production licenses. Please set " + + "[xpack.security.transport.ssl.enabled] to [true] or disable security by setting " + + "[xpack.security.enabled] to [false]", new TLSLicenseBootstrapCheck().check(new BootstrapContext( Settings.builder().put("xpack.security.transport.ssl.enabled", false).build(), build)).getMessage()); } From 84dd719ab9a7b42375e464d5000a8c2c791c414b Mon Sep 17 00:00:00 2001 From: jaymode Date: Fri, 15 Sep 2017 09:03:36 -0600 Subject: [PATCH 9/9] remove outdated comment Original commit: elastic/x-pack-elasticsearch@06a51abb6556f4f3810ebfef902f8dcb5c725dc1 --- .../xpack/security/authc/esnative/ESNativeMigrateToolTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java index 09728b4dcbf..3fb9920d409 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ESNativeMigrateToolTests.java @@ -52,7 +52,6 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase { @Override protected boolean transportSSLEnabled() { - // don't use autogenerated when we expect a different cert return useSSL; }