mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-09 22:45:04 +00:00
SSL/TLS: Add option to disable reverse DNS resolution of hostname
This change adds the option to disable reverse DNS lookup of a hostname from an IP address. This is needed if only an IP address is found in a SSL certificate and hostname verification is enabled. Closes elastic/elasticsearch#575 Original commit: elastic/x-pack-elasticsearch@07356bc885
This commit is contained in:
parent
02682ff4ec
commit
166514651a
@ -29,6 +29,7 @@ import java.net.InetSocketAddress;
|
|||||||
public class NettySecuredTransport extends NettyTransport {
|
public class NettySecuredTransport extends NettyTransport {
|
||||||
|
|
||||||
public static final String HOSTNAME_VERIFICATION_SETTING = "shield.ssl.hostname_verification";
|
public static final String HOSTNAME_VERIFICATION_SETTING = "shield.ssl.hostname_verification";
|
||||||
|
public static final String HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING = "shield.ssl.hostname_verification.resolve_name";
|
||||||
|
|
||||||
private final SSLService sslService;
|
private final SSLService sslService;
|
||||||
private final @Nullable IPFilter authenticator;
|
private final @Nullable IPFilter authenticator;
|
||||||
@ -112,9 +113,7 @@ public class NettySecuredTransport extends NettyTransport {
|
|||||||
SSLEngine sslEngine;
|
SSLEngine sslEngine;
|
||||||
if (settings.getAsBoolean(HOSTNAME_VERIFICATION_SETTING, true)) {
|
if (settings.getAsBoolean(HOSTNAME_VERIFICATION_SETTING, true)) {
|
||||||
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue();
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getValue();
|
||||||
String hostname = inetSocketAddress.getHostName();
|
sslEngine = sslService.createSSLEngine(ImmutableSettings.EMPTY, getHostname(inetSocketAddress), inetSocketAddress.getPort());
|
||||||
int port = inetSocketAddress.getPort();
|
|
||||||
sslEngine = sslService.createSSLEngine(ImmutableSettings.EMPTY, hostname, port);
|
|
||||||
SSLParameters parameters = new SSLParameters();
|
SSLParameters parameters = new SSLParameters();
|
||||||
parameters.setEndpointIdentificationAlgorithm("HTTPS");
|
parameters.setEndpointIdentificationAlgorithm("HTTPS");
|
||||||
sslEngine.setSSLParameters(parameters);
|
sslEngine.setSSLParameters(parameters);
|
||||||
@ -128,6 +127,20 @@ public class NettySecuredTransport extends NettyTransport {
|
|||||||
|
|
||||||
ctx.sendDownstream(e);
|
ctx.sendDownstream(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getHostname(InetSocketAddress inetSocketAddress) {
|
||||||
|
String hostname;
|
||||||
|
if (settings.getAsBoolean(HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING, true)) {
|
||||||
|
hostname = inetSocketAddress.getHostName();
|
||||||
|
} else {
|
||||||
|
hostname = inetSocketAddress.getHostString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace("resolved hostname [{}] for address [{}] to be used in ssl hostname verification", hostname, inetSocketAddress);
|
||||||
|
}
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.shield.transport.netty;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
|
import org.elasticsearch.test.ShieldIntegrationTest;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
|
@ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE)
|
||||||
|
public class IPHostnameVerificationIntegrationTests extends ShieldIntegrationTest {
|
||||||
|
|
||||||
|
static Path keystore;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean sslTransportEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||||
|
// The default Unicast test behavior is to use 'localhost' with the port number. For this test we need to use IP
|
||||||
|
String[] unicastAddresses = settings.getAsArray("discovery.zen.ping.unicast.hosts");
|
||||||
|
for (int i = 0; i < unicastAddresses.length; i++) {
|
||||||
|
String address = unicastAddresses[i];
|
||||||
|
unicastAddresses[i] = address.replace("localhost", "127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmutableSettings.Builder settingsBuilder = settingsBuilder()
|
||||||
|
.put(settings)
|
||||||
|
.putArray("discovery.zen.ping.unicast.hosts", unicastAddresses);
|
||||||
|
|
||||||
|
try {
|
||||||
|
//This keystore uses a cert with a CN of "Elasticsearch Test Node" and IPv4+IPv6 ip addresses as SubjectAlternativeNames
|
||||||
|
keystore = Paths.get(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-ip-only.jks").toURI());
|
||||||
|
assertThat(Files.exists(keystore), is(true));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return settingsBuilder.put("shield.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||||
|
.put("shield.ssl.keystore.password", "testnode-ip-only")
|
||||||
|
.put("shield.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||||
|
.put("shield.ssl.truststore.password", "testnode-ip-only")
|
||||||
|
.put("transport.host", "127.0.0.1")
|
||||||
|
.put("network.host", "127.0.0.1")
|
||||||
|
.put("shield.ssl.client.auth", "false")
|
||||||
|
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_SETTING, true)
|
||||||
|
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING, false)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings transportClientSettings() {
|
||||||
|
return ImmutableSettings.builder().put(super.transportClientSettings())
|
||||||
|
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_SETTING, true)
|
||||||
|
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING, false)
|
||||||
|
.put("shield.ssl.keystore.path", keystore.toAbsolutePath())
|
||||||
|
.put("shield.ssl.keystore.password", "testnode-ip-only")
|
||||||
|
.put("shield.ssl.truststore.path", keystore.toAbsolutePath())
|
||||||
|
.put("shield.ssl.truststore.password", "testnode-ip-only")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransportClientConnectionWorksWithIPOnlyHostnameVerification() throws Exception {
|
||||||
|
Client client = internalCluster().transportClient();
|
||||||
|
assertGreenClusterState(client);
|
||||||
|
}
|
||||||
|
}
|
@ -67,6 +67,7 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||||||
private final byte[] systemKey;
|
private final byte[] systemKey;
|
||||||
private final boolean sslTransportEnabled;
|
private final boolean sslTransportEnabled;
|
||||||
private final boolean hostnameVerificationEnabled;
|
private final boolean hostnameVerificationEnabled;
|
||||||
|
private final boolean hostnameVerificationResolveNameEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link org.elasticsearch.test.SettingsSource} for the shield configuration.
|
* Creates a new {@link org.elasticsearch.test.SettingsSource} for the shield configuration.
|
||||||
@ -85,7 +86,8 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||||||
this.parentFolder = parentFolder;
|
this.parentFolder = parentFolder;
|
||||||
this.subfolderPrefix = scope.name();
|
this.subfolderPrefix = scope.name();
|
||||||
this.sslTransportEnabled = sslTransportEnabled;
|
this.sslTransportEnabled = sslTransportEnabled;
|
||||||
hostnameVerificationEnabled = randomBoolean();
|
this.hostnameVerificationEnabled = randomBoolean();
|
||||||
|
this.hostnameVerificationResolveNameEnabled = randomBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -190,11 +192,11 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Settings getNodeSSLSettings() {
|
private Settings getNodeSSLSettings() {
|
||||||
return getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode", sslTransportEnabled, hostnameVerificationEnabled);
|
return getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode", sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Settings getClientSSLSettings() {
|
private Settings getClientSSLSettings() {
|
||||||
return getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient", sslTransportEnabled, hostnameVerificationEnabled);
|
return getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient", sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,10 +207,10 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||||||
* @return the configuration settings
|
* @return the configuration settings
|
||||||
*/
|
*/
|
||||||
public static Settings getSSLSettingsForStore(String resourcePathToStore, String password) {
|
public static Settings getSSLSettingsForStore(String resourcePathToStore, String password) {
|
||||||
return getSSLSettingsForStore(resourcePathToStore, password, true, true);
|
return getSSLSettingsForStore(resourcePathToStore, password, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean sslTransportEnabled, boolean hostnameVerificationEnabled) {
|
private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean sslTransportEnabled, boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled) {
|
||||||
File store;
|
File store;
|
||||||
try {
|
try {
|
||||||
store = new File(ShieldSettingsSource.class.getResource(resourcePathToStore).toURI());
|
store = new File(ShieldSettingsSource.class.getResource(resourcePathToStore).toURI());
|
||||||
@ -227,7 +229,8 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||||||
if (sslTransportEnabled) {
|
if (sslTransportEnabled) {
|
||||||
builder.put("shield.ssl.keystore.path", store.getPath())
|
builder.put("shield.ssl.keystore.path", store.getPath())
|
||||||
.put("shield.ssl.keystore.password", password)
|
.put("shield.ssl.keystore.password", password)
|
||||||
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_SETTING, hostnameVerificationEnabled);
|
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_SETTING, hostnameVerificationEnabled)
|
||||||
|
.put(NettySecuredTransport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING, hostnameVerificationResolveNameEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sslTransportEnabled && randomBoolean()) {
|
if (sslTransportEnabled && randomBoolean()) {
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDYjCCAkqgAwIBAgIJAKP3WbDN1WxEMA0GCSqGSIb3DQEBCwUAMEgxDDAKBgNV
|
||||||
|
BAoTA29yZzEWMBQGA1UECxMNZWxhc3RpY3NlYXJjaDEgMB4GA1UEAxMXRWxhc3Rp
|
||||||
|
Y3NlYXJjaCBUZXN0IE5vZGUwHhcNMTUwMTE5MTQwNDE3WhcNMTkwMTE4MTQwNDE3
|
||||||
|
WjBIMQwwCgYDVQQKEwNvcmcxFjAUBgNVBAsTDWVsYXN0aWNzZWFyY2gxIDAeBgNV
|
||||||
|
BAMTF0VsYXN0aWNzZWFyY2ggVGVzdCBOb2RlMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||||
|
AQ8AMIIBCgKCAQEA3a5+yBl2rVEGwlOjw6Ji43+iqvaAbmVhnCk6laEa3GpzothX
|
||||||
|
7HhtGGDfjdhaLzWF5PWP8SvMM8g4f1PLN0hGSR7vrWjlnpvUDXIHsoIRqWfYdwDA
|
||||||
|
RNiUvOI4FBjN4pZ4sXyUYsTpw80l6W0r3zopyycE4+4HJv55U1Yy2/3qzv1IITqD
|
||||||
|
LwRt6VpbPGVyzDSBMQXEgfT7sfaJB9Ru+A/onIpEicrWhgCPHrBnSUkKCKNj9AX/
|
||||||
|
RV6/yQYnS/KhLx/eQTP7NVcbrC2J4fFOLX9oZAj6dir/tYQ6rDAMqBTnbhGygDqP
|
||||||
|
0RgCVf82n6mA23n7l5DaZ4RZl+ssN3fNqDyDpQIDAQABo08wTTAJBgNVHRMEAjAA
|
||||||
|
MB0GA1UdDgQWBBSDFYaN/Od9ad7Kztv6cGjd2X4w1TAhBgNVHREEGjAYhwR/AAAB
|
||||||
|
hxAAAAAAAAAAAAAAAAAAAAACMA0GCSqGSIb3DQEBCwUAA4IBAQCbxk4VHMcdD2yU
|
||||||
|
VpLSBxHBdWY/Gn3f7k0WWhQAmRPR+S6vSr89hVO8UIkqEFzc+D19s9h0XvAmo2QO
|
||||||
|
G80OLTcHIjxiVqAVWoGUPH4D7FdG7sSBbrJbweIBMW8Ba4kefWGcI0KlUWTssFyE
|
||||||
|
YLJQIUCIdKtVf/qmcItvrEXw8ucSYaExvizMClTvf2fZxRws8Omo3dxn+ifUH5nn
|
||||||
|
evQW8Tawlx2ql5P6wHTSUclGLv1CXtMAnuOlyaYY/UbslNhSXigxYOZCI3ole3qL
|
||||||
|
Z0dBah+eCspOit14mi7jHPoS1Yji/CSh33KZD6ZESuv/V1B7oy6zZWei/b4vllW5
|
||||||
|
RwZx1Y/r
|
||||||
|
-----END CERTIFICATE-----
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user