Skip to content

Commit fab2ec5

Browse files
committed
Deprecate misconfigured SSL server config
This commit adds a deprecation warning when starting a node where either of the server contexts (xpack.security.transport.ssl and xpack.security.http.ssl) meet either of these conditions: 1. The server lacks a certificate/key pair (i.e. neither ssl.keystore.path not ssl.certificate are configured) 2. The server has some ssl configuration, but ssl.enabled is not specified. This new validation does not care whether ssl.enabled is true or false (though other validation might), it simply makes it an error to configure server SSL without being explicit about whether to enable that configuration. Backport of: elastic#45892
1 parent abd4a70 commit fab2ec5

File tree

17 files changed

+237
-71
lines changed

17 files changed

+237
-71
lines changed

client/rest-high-level/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ testClusters.all {
123123
setting 'xpack.security.enabled', 'true'
124124
setting 'xpack.security.authc.token.enabled', 'true'
125125
setting 'xpack.security.authc.api_key.enabled', 'true'
126+
setting 'xpack.security.http.ssl.enabled', 'false'
127+
setting 'xpack.security.transport.ssl.enabled', 'false'
126128
// Truststore settings are not used since TLS is not enabled. Included for testing the get certificates API
127129
setting 'xpack.security.http.ssl.certificate_authorities', 'testnode.crt'
128130
setting 'xpack.security.transport.ssl.truststore.path', 'testnode.jks'

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

+35-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.elasticsearch.ElasticsearchSecurityException;
1515
import org.elasticsearch.common.CheckedSupplier;
1616
import org.elasticsearch.common.Strings;
17+
import org.elasticsearch.common.logging.DeprecationLogger;
1718
import org.elasticsearch.common.settings.Settings;
1819
import org.elasticsearch.env.Environment;
1920
import org.elasticsearch.xpack.core.XPackSettings;
@@ -33,14 +34,13 @@
3334
import javax.net.ssl.TrustManagerFactory;
3435
import javax.net.ssl.X509ExtendedKeyManager;
3536
import javax.net.ssl.X509ExtendedTrustManager;
36-
3737
import java.io.IOException;
3838
import java.net.InetAddress;
3939
import java.net.Socket;
4040
import java.security.GeneralSecurityException;
4141
import java.security.KeyManagementException;
42-
import java.security.NoSuchAlgorithmException;
4342
import java.security.KeyStore;
43+
import java.security.NoSuchAlgorithmException;
4444
import java.util.ArrayList;
4545
import java.util.Arrays;
4646
import java.util.Collection;
@@ -68,6 +68,8 @@
6868
public class SSLService {
6969

7070
private static final Logger logger = LogManager.getLogger(SSLService.class);
71+
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
72+
7173
/**
7274
* An ordered map of protocol algorithms to SSLContext algorithms. The map is ordered from most
7375
* secure to least secure. The names in this map are taken from the
@@ -432,6 +434,10 @@ Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
432434
Map<String, Settings> profileSettings = getTransportProfileSSLSettings(settings);
433435
profileSettings.forEach((key, profileSetting) -> loadConfiguration(key, profileSetting, sslContextHolders));
434436

437+
for (String context : Arrays.asList("xpack.security.transport.ssl", "xpack.security.http.ssl")) {
438+
validateServerConfiguration(context);
439+
}
440+
435441
return Collections.unmodifiableMap(sslContextHolders);
436442
}
437443

@@ -450,6 +456,33 @@ private SSLConfiguration loadConfiguration(String key, Settings settings, Map<SS
450456
}
451457
}
452458

459+
private void validateServerConfiguration(String prefix) {
460+
assert prefix.endsWith(".ssl");
461+
SSLConfiguration configuration = getSSLConfiguration(prefix);
462+
final String enabledSetting = prefix + ".enabled";
463+
if (settings.getAsBoolean(enabledSetting, false) == true) {
464+
// Client Authentication _should_ be required, but if someone turns it off, then this check is no longer relevant
465+
final SSLConfigurationSettings configurationSettings = SSLConfigurationSettings.withPrefix(prefix + ".");
466+
if (isConfigurationValidForServerUsage(configuration) == false) {
467+
deprecationLogger.deprecated("invalid SSL configuration for " + prefix +
468+
" - server ssl configuration requires a key and certificate, but these have not been configured; you must set either " +
469+
"[" + configurationSettings.x509KeyPair.keystorePath.getKey() + "], or both [" +
470+
configurationSettings.x509KeyPair.keyPath.getKey() + "] and [" +
471+
configurationSettings.x509KeyPair.certificatePath.getKey() + "]");
472+
}
473+
} else if (settings.hasValue(enabledSetting) == false) {
474+
final List<String> sslSettingNames = settings.keySet().stream()
475+
.filter(s -> s.startsWith(prefix))
476+
.sorted()
477+
.collect(Collectors.toList());
478+
if (sslSettingNames.isEmpty() == false) {
479+
deprecationLogger.deprecated("invalid configuration for " + prefix + " - [" + enabledSetting +
480+
"] is not set, but the following settings have been configured in elasticsearch.yml : [" +
481+
Strings.collectionToCommaDelimitedString(sslSettingNames) + "]");
482+
}
483+
}
484+
}
485+
453486
private void storeSslConfiguration(String key, SSLConfiguration configuration) {
454487
if (key.endsWith(".")) {
455488
key = key.substring(0, key.length() - 1);

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/transport/ProfileConfigurationsTests.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package org.elasticsearch.xpack.core.security.transport;
88

9+
import org.elasticsearch.common.settings.MockSecureSettings;
910
import org.elasticsearch.common.settings.Settings;
1011
import org.elasticsearch.env.Environment;
1112
import org.elasticsearch.env.TestEnvironment;
@@ -15,14 +16,16 @@
1516
import org.elasticsearch.xpack.core.ssl.VerificationMode;
1617
import org.hamcrest.Matchers;
1718

19+
import java.nio.file.Path;
1820
import java.util.Map;
1921

2022
public class ProfileConfigurationsTests extends ESTestCase {
2123

2224
public void testGetSecureTransportProfileConfigurations() {
23-
final Settings settings = Settings.builder()
25+
final Settings settings = getBaseSettings()
2426
.put("path.home", createTempDir())
2527
.put("xpack.security.transport.ssl.verification_mode", VerificationMode.CERTIFICATE.name())
28+
.put("xpack.security.transport.ssl.verification_mode", VerificationMode.CERTIFICATE.name())
2629
.put("transport.profiles.full.xpack.security.ssl.verification_mode", VerificationMode.FULL.name())
2730
.put("transport.profiles.cert.xpack.security.ssl.verification_mode", VerificationMode.CERTIFICATE.name())
2831
.build();
@@ -39,7 +42,7 @@ public void testGetSecureTransportProfileConfigurations() {
3942

4043
public void testGetInsecureTransportProfileConfigurations() {
4144
assumeFalse("Can't run in a FIPS JVM with verification mode None", inFipsJvm());
42-
final Settings settings = Settings.builder()
45+
final Settings settings = getBaseSettings()
4346
.put("path.home", createTempDir())
4447
.put("xpack.security.transport.ssl.verification_mode", VerificationMode.CERTIFICATE.name())
4548
.put("transport.profiles.none.xpack.security.ssl.verification_mode", VerificationMode.NONE.name())
@@ -53,4 +56,19 @@ public void testGetInsecureTransportProfileConfigurations() {
5356
assertThat(profileConfigurations.get("none").verificationMode(), Matchers.equalTo(VerificationMode.NONE));
5457
assertThat(profileConfigurations.get("default"), Matchers.sameInstance(defaultConfig));
5558
}
59+
60+
private Settings.Builder getBaseSettings() {
61+
final Path keystore = randomBoolean()
62+
? getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")
63+
: getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12");
64+
65+
MockSecureSettings secureSettings = new MockSecureSettings();
66+
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
67+
68+
return Settings.builder()
69+
.setSecureSettings(secureSettings)
70+
.put("xpack.security.transport.ssl.enabled", true)
71+
.put("xpack.security.transport.ssl.keystore.path", keystore.toString());
72+
}
73+
5674
}

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

+26-6
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public void testReloadingKeyStore() throws Exception {
110110
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
111111
final Settings settings = Settings.builder()
112112
.put("path.home", createTempDir())
113+
.put("xpack.security.transport.ssl.enabled", true)
113114
.put("xpack.security.transport.ssl.keystore.path", keystorePath)
114115
.setSecureSettings(secureSettings)
115116
.build();
@@ -166,6 +167,7 @@ public void testPEMKeyConfigReloading() throws Exception {
166167
secureSettings.setString("xpack.security.transport.ssl.secure_key_passphrase", "testnode");
167168
final Settings settings = Settings.builder()
168169
.put("path.home", createTempDir())
170+
.put("xpack.security.transport.ssl.enabled", true)
169171
.put("xpack.security.transport.ssl.key", keyPath)
170172
.put("xpack.security.transport.ssl.certificate", certPath)
171173
.putList("xpack.security.transport.ssl.certificate_authorities", certPath.toString())
@@ -223,10 +225,10 @@ public void testReloadingTrustStore() throws Exception {
223225
updatedTruststorePath);
224226
MockSecureSettings secureSettings = new MockSecureSettings();
225227
secureSettings.setString("xpack.security.transport.ssl.truststore.secure_password", "testnode");
226-
Settings settings = Settings.builder()
228+
final Settings settings = baseKeystoreSettings(tempDir, secureSettings)
229+
.put("xpack.security.transport.ssl.enabled", true)
227230
.put("xpack.security.transport.ssl.truststore.path", trustStorePath)
228231
.put("path.home", createTempDir())
229-
.setSecureSettings(secureSettings)
230232
.build();
231233
Environment env = randomBoolean() ? null : TestEnvironment.newEnvironment(settings);
232234
// Create the MockWebServer once for both pre and post checks
@@ -274,7 +276,8 @@ public void testReloadingPEMTrustConfig() throws Exception {
274276
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), serverCertPath);
275277
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"), serverKeyPath);
276278
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_updated.crt"), updatedCert);
277-
Settings settings = Settings.builder()
279+
Settings settings = baseKeystoreSettings(tempDir, null)
280+
.put("xpack.security.transport.ssl.enabled", true)
278281
.putList("xpack.security.transport.ssl.certificate_authorities", serverCertPath.toString())
279282
.put("path.home", createTempDir())
280283
.build();
@@ -323,6 +326,7 @@ public void testReloadingKeyStoreException() throws Exception {
323326
MockSecureSettings secureSettings = new MockSecureSettings();
324327
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
325328
Settings settings = Settings.builder()
329+
.put("xpack.security.transport.ssl.enabled", true)
326330
.put("xpack.security.transport.ssl.keystore.path", keystorePath)
327331
.setSecureSettings(secureSettings)
328332
.put("path.home", createTempDir())
@@ -373,6 +377,7 @@ public void testReloadingPEMKeyConfigException() throws Exception {
373377
MockSecureSettings secureSettings = new MockSecureSettings();
374378
secureSettings.setString("xpack.security.transport.ssl.secure_key_passphrase", "testnode");
375379
Settings settings = Settings.builder()
380+
.put("xpack.security.transport.ssl.enabled", true)
376381
.put("xpack.security.transport.ssl.key", keyPath)
377382
.put("xpack.security.transport.ssl.certificate", certPath)
378383
.putList("xpack.security.transport.ssl.certificate_authorities", certPath.toString(), clientCertPath.toString())
@@ -420,10 +425,10 @@ public void testTrustStoreReloadException() throws Exception {
420425
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath);
421426
MockSecureSettings secureSettings = new MockSecureSettings();
422427
secureSettings.setString("xpack.security.transport.ssl.truststore.secure_password", "testnode");
423-
Settings settings = Settings.builder()
428+
Settings settings = baseKeystoreSettings(tempDir, secureSettings)
429+
.put("xpack.security.transport.ssl.enabled", true)
424430
.put("xpack.security.transport.ssl.truststore.path", trustStorePath)
425431
.put("path.home", createTempDir())
426-
.setSecureSettings(secureSettings)
427432
.build();
428433
Environment env = randomBoolean() ? null : TestEnvironment.newEnvironment(settings);
429434
final SSLService sslService = new SSLService(settings, env);
@@ -464,7 +469,8 @@ public void testPEMTrustReloadException() throws Exception {
464469
Path tempDir = createTempDir();
465470
Path clientCertPath = tempDir.resolve("testclient.crt");
466471
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
467-
Settings settings = Settings.builder()
472+
Settings settings = baseKeystoreSettings(tempDir, null)
473+
.put("xpack.security.transport.ssl.enabled", true)
468474
.putList("xpack.security.transport.ssl.certificate_authorities", clientCertPath.toString())
469475
.put("path.home", createTempDir())
470476
.build();
@@ -502,6 +508,20 @@ void reloadSSLContext(SSLConfiguration configuration) {
502508
assertThat(sslService.sslContextHolder(config).sslContext(), sameInstance(context));
503509
}
504510

511+
private Settings.Builder baseKeystoreSettings(Path tempDir, MockSecureSettings secureSettings) throws IOException {
512+
final Path keystorePath = tempDir.resolve("testclient.jks");
513+
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), keystorePath);
514+
515+
if (secureSettings == null) {
516+
secureSettings = new MockSecureSettings();
517+
}
518+
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
519+
520+
return Settings.builder()
521+
.put("xpack.security.transport.ssl.keystore.path", keystorePath.toString())
522+
.setSecureSettings(secureSettings);
523+
}
524+
505525
private void validateSSLConfigurationIsReloaded(Settings settings, Environment env, Consumer<SSLContext> preChecks,
506526
Runnable modificationFunction, Consumer<SSLContext> postChecks) throws Exception {
507527
final CountDownLatch reloadLatch = new CountDownLatch(1);

0 commit comments

Comments
 (0)