Skip to content

Commit eb3c57b

Browse files
authored
Reject misconfigured/ambiguous SSL server config (#45892)
This commit makes it an error to start 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.
1 parent 625c00d commit eb3c57b

File tree

18 files changed

+301
-69
lines changed

18 files changed

+301
-69
lines changed

client/rest-high-level/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ testClusters.all {
126126
setting 'xpack.security.enabled', 'true'
127127
setting 'xpack.security.authc.token.enabled', 'true'
128128
setting 'xpack.security.authc.api_key.enabled', 'true'
129+
setting 'xpack.security.http.ssl.enabled', 'false'
130+
setting 'xpack.security.transport.ssl.enabled', 'false'
129131
// Truststore settings are not used since TLS is not enabled. Included for testing the get certificates API
130132
setting 'xpack.security.http.ssl.certificate_authorities', 'testnode.crt'
131133
setting 'xpack.security.transport.ssl.truststore.path', 'testnode.jks'

docs/reference/migration/migrate_8_0/security.asciidoc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,73 @@ realm directly.
4141
The `transport.profiles.*.xpack.security.type` setting has been removed since
4242
the Transport Client has been removed and therefore all client traffic now uses
4343
the HTTP transport. Transport profiles using this setting should be removed.
44+
45+
[float]
46+
[[ssl-validation-changes]]
47+
==== SSL/TLS configuration validation
48+
49+
[float]
50+
===== The `xpack.security.transport.ssl.enabled` setting may be required
51+
52+
It is now an error to configure any SSL settings for
53+
`xpack.security.transport.ssl` without also configuring
54+
`xpack.security.transport.ssl.enabled`.
55+
56+
For example, the following configuration is invalid:
57+
[source,yaml]
58+
--------------------------------------------------
59+
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
60+
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
61+
--------------------------------------------------
62+
63+
And must be configured as:
64+
[source,yaml]
65+
--------------------------------------------------
66+
xpack.security.transport.ssl.enabled: true <1>
67+
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
68+
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
69+
--------------------------------------------------
70+
<1> or `false`.
71+
72+
[float]
73+
===== The `xpack.security.http.ssl.enabled` setting may be required
74+
75+
It is now an error to configure any SSL settings for
76+
`xpack.security.http.ssl` without also configuring
77+
`xpack.security.http.ssl.enabled`.
78+
79+
For example, the following configuration is invalid:
80+
[source,yaml]
81+
--------------------------------------------------
82+
xpack.security.http.ssl.certificate: elasticsearch.crt
83+
xpack.security.http.ssl.key: elasticsearch.key
84+
xpack.security.http.ssl.certificate_authorities: [ "corporate-ca.crt" ]
85+
--------------------------------------------------
86+
87+
And must be configured as either:
88+
[source,yaml]
89+
--------------------------------------------------
90+
xpack.security.http.ssl.enabled: true <1>
91+
xpack.security.http.ssl.certificate: elasticsearch.crt
92+
xpack.security.http.ssl.key: elasticsearch.key
93+
xpack.security.http.ssl.certificate_authorities: [ "corporate-ca.crt" ]
94+
--------------------------------------------------
95+
<1> or `false`.
96+
97+
[float]
98+
===== The `xpack.security.transport.ssl` Certificate and Key may be required
99+
100+
It is now an error to enable SSL for the transport interface without also configuring
101+
a certificate and key through use of the `xpack.security.transport.ssl.keystore.path`
102+
setting or the `xpack.security.transport.ssl.certificate` and
103+
`xpack.security.transport.ssl.key` settings.
104+
105+
[float]
106+
===== The `xpack.security.http.ssl` Certificate and Key may be required
107+
108+
It is now an error to enable SSL for the HTTP (Rest) server without also configuring
109+
a certificate and key through use of the `xpack.security.http.ssl.keystore.path`
110+
setting or the `xpack.security.http.ssl.certificate` and
111+
`xpack.security.http.ssl.key` settings.
112+
113+

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import javax.net.ssl.TrustManagerFactory;
3434
import javax.net.ssl.X509ExtendedKeyManager;
3535
import javax.net.ssl.X509ExtendedTrustManager;
36-
3736
import java.io.IOException;
3837
import java.net.InetAddress;
3938
import java.net.Socket;
@@ -428,6 +427,10 @@ Map<SSLConfiguration, SSLContextHolder> loadSSLConfigurations() {
428427
Map<String, Settings> profileSettings = getTransportProfileSSLSettings(settings);
429428
profileSettings.forEach((key, profileSetting) -> loadConfiguration(key, profileSetting, sslContextHolders));
430429

430+
for (String context : List.of("xpack.security.transport.ssl", "xpack.security.http.ssl")) {
431+
validateServerConfiguration(context);
432+
}
433+
431434
return Collections.unmodifiableMap(sslContextHolders);
432435
}
433436

@@ -446,6 +449,33 @@ private SSLConfiguration loadConfiguration(String key, Settings settings, Map<SS
446449
}
447450
}
448451

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

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

Lines changed: 20 additions & 2 deletions
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

Lines changed: 26 additions & 6 deletions
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())
@@ -222,10 +224,10 @@ public void testReloadingTrustStore() throws Exception {
222224
updatedTruststorePath);
223225
MockSecureSettings secureSettings = new MockSecureSettings();
224226
secureSettings.setString("xpack.security.transport.ssl.truststore.secure_password", "testnode");
225-
Settings settings = Settings.builder()
227+
final Settings settings = baseKeystoreSettings(tempDir, secureSettings)
228+
.put("xpack.security.transport.ssl.enabled", true)
226229
.put("xpack.security.transport.ssl.truststore.path", trustStorePath)
227230
.put("path.home", createTempDir())
228-
.setSecureSettings(secureSettings)
229231
.build();
230232
Environment env = TestEnvironment.newEnvironment(settings);
231233
// Create the MockWebServer once for both pre and post checks
@@ -273,7 +275,8 @@ public void testReloadingPEMTrustConfig() throws Exception {
273275
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), serverCertPath);
274276
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"), serverKeyPath);
275277
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_updated.crt"), updatedCert);
276-
Settings settings = Settings.builder()
278+
Settings settings = baseKeystoreSettings(tempDir, null)
279+
.put("xpack.security.transport.ssl.enabled", true)
277280
.putList("xpack.security.transport.ssl.certificate_authorities", serverCertPath.toString())
278281
.put("path.home", createTempDir())
279282
.build();
@@ -322,6 +325,7 @@ public void testReloadingKeyStoreException() throws Exception {
322325
MockSecureSettings secureSettings = new MockSecureSettings();
323326
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
324327
Settings settings = Settings.builder()
328+
.put("xpack.security.transport.ssl.enabled", true)
325329
.put("xpack.security.transport.ssl.keystore.path", keystorePath)
326330
.setSecureSettings(secureSettings)
327331
.put("path.home", createTempDir())
@@ -372,6 +376,7 @@ public void testReloadingPEMKeyConfigException() throws Exception {
372376
MockSecureSettings secureSettings = new MockSecureSettings();
373377
secureSettings.setString("xpack.security.transport.ssl.secure_key_passphrase", "testnode");
374378
Settings settings = Settings.builder()
379+
.put("xpack.security.transport.ssl.enabled", true)
375380
.put("xpack.security.transport.ssl.key", keyPath)
376381
.put("xpack.security.transport.ssl.certificate", certPath)
377382
.putList("xpack.security.transport.ssl.certificate_authorities", certPath.toString(), clientCertPath.toString())
@@ -419,10 +424,10 @@ public void testTrustStoreReloadException() throws Exception {
419424
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"), trustStorePath);
420425
MockSecureSettings secureSettings = new MockSecureSettings();
421426
secureSettings.setString("xpack.security.transport.ssl.truststore.secure_password", "testnode");
422-
Settings settings = Settings.builder()
427+
Settings settings = baseKeystoreSettings(tempDir, secureSettings)
428+
.put("xpack.security.transport.ssl.enabled", true)
423429
.put("xpack.security.transport.ssl.truststore.path", trustStorePath)
424430
.put("path.home", createTempDir())
425-
.setSecureSettings(secureSettings)
426431
.build();
427432
Environment env = TestEnvironment.newEnvironment(settings);
428433
final SSLService sslService = new SSLService(settings, env);
@@ -463,7 +468,8 @@ public void testPEMTrustReloadException() throws Exception {
463468
Path tempDir = createTempDir();
464469
Path clientCertPath = tempDir.resolve("testclient.crt");
465470
Files.copy(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
466-
Settings settings = Settings.builder()
471+
Settings settings = baseKeystoreSettings(tempDir, null)
472+
.put("xpack.security.transport.ssl.enabled", true)
467473
.putList("xpack.security.transport.ssl.certificate_authorities", clientCertPath.toString())
468474
.put("path.home", createTempDir())
469475
.build();
@@ -501,6 +507,20 @@ void reloadSSLContext(SSLConfiguration configuration) {
501507
assertThat(sslService.sslContextHolder(config).sslContext(), sameInstance(context));
502508
}
503509

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

0 commit comments

Comments
 (0)