Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GEODE-7852: SNI extension support #4920

Merged
merged 5 commits into from Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -97,5 +97,6 @@ public void connectToSNIProxyDocker() {
region.destroy("hello");
region.put("hello", "world");
assertThat(region.get("hello")).isEqualTo("world");
assertThat(region.get("foo")).isEqualTo("bar");
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
}
}
Expand Up @@ -32,6 +32,7 @@
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Collections;
Expand All @@ -52,6 +53,7 @@
import org.apache.geode.cache.RegionService;
import org.apache.geode.cache.client.internal.ProxyCache;
import org.apache.geode.cache.client.internal.UserAttributes;
import org.apache.geode.cache.client.proxy.SniSocketFactory;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
Expand All @@ -62,6 +64,7 @@
import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator;
import org.apache.geode.internal.cache.xmlcache.ClientCacheCreation;
import org.apache.geode.internal.inet.LocalHostUtil;
import org.apache.geode.internal.serialization.Version;
import org.apache.geode.internal.serialization.VersionedDataInputStream;
import org.apache.geode.pdx.ReflectionBasedAutoSerializer;
Expand Down Expand Up @@ -127,7 +130,7 @@ public void test000Defaults() throws Exception {
}

@Test
public void test001FindDefaultFromXML() throws Exception {
public void test001FindDefaultPoolFromXML() throws Exception {
File cacheXmlFile = temporaryFolder.newFile("ClientCacheFactoryJUnitTest.xml");
URL url = ClientCacheFactoryJUnitTest.class
.getResource("ClientCacheFactoryJUnitTest_single_pool.xml");
Expand All @@ -149,6 +152,11 @@ public void test001FindDefaultFromXML() throws Exception {
.isEqualTo(PoolFactory.DEFAULT_SOCKET_CONNECT_TIMEOUT);
assertThat(defPool.getServers()).isEqualTo(
Collections.singletonList(new InetSocketAddress("localhost", CacheServer.DEFAULT_PORT)));

assertThat(defPool.getSocketFactory()).isInstanceOf(SniSocketFactory.class);
Socket socket = defPool.getSocketFactory().createSocket();
assertThat(socket.getPort()).isEqualTo(12345);
assertThat(socket.getInetAddress()).isEqualTo(LocalHostUtil.getLocalHost());
}

/**
Expand Down
Expand Up @@ -27,5 +27,14 @@
version="1.0">
<pool name="my_pool_name" multiuser-authentication="true">
<server host="localhost" port="40404"/>
<socket-factory>
<class-name>org.apache.geode.cache.client.proxy.SniSocketFactory</class-name>
<parameter name="hostname">
<string>localhost</string>
</parameter>
<parameter name="port">
<string>40404</string>
</parameter>
</socket-factory>
</pool>
</client-cache>
Expand Up @@ -18,24 +18,38 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Properties;

import org.apache.geode.cache.Cache;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.client.SocketFactory;
import org.apache.geode.internal.DistributionLocator;

/**
* A {@link SocketFactory} that connects a client to locators and servers
* through a SNI proxy.
*/
public class SniSocketFactory implements SocketFactory {
public class SniSocketFactory implements SocketFactory, Declarable {


private final String hostname;
private final int port;
private String hostname;
private int port;

public SniSocketFactory() {} // required by Declarable

public SniSocketFactory(String hostname, int port) {
this.hostname = hostname;
this.port = port;
}

@Override // Declarable
public void initialize(Cache cache, Properties properties) {
this.hostname = properties.getProperty("hostname");
String portString =
properties.getProperty("port", "" + DistributionLocator.DEFAULT_LOCATOR_PORT);
this.port = Integer.parseInt(portString);
}

@Override
public Socket createSocket() throws IOException {
return new SniProxySocket(new InetSocketAddress(hostname, port));
Expand Down
Expand Up @@ -31,6 +31,7 @@ For details, see [&lt;client-cache&gt; Element Reference.](client-cache.html)
<pool>
<locator>
<server>
<socket-factory>
<disk-store>
<disk-dirs>
<disk-dir>
Expand Down
26 changes: 26 additions & 0 deletions geode-docs/reference/topics/client-cache.html.md.erb
Expand Up @@ -338,6 +338,32 @@ Provide a server list or `locator` list, but not both.
port="123456"/>
</pool>
```
## <a id="cc-socket-factory" class="no-quick-link"></a>&lt;socket-factory&gt;

Defines a factory to create socket connections to locators and servers. A typical use of this element is to redirect connections to an ingress gateway such as Istio or HAProxy in a cluster where the TLS (SSL) Server Name Extension field is set to indicate the actual locator or server the client is trying to reach. This allows you to expose only the gateway hostname:port without the client needing to be able to resolve the names of the locator and server machines.
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved

**Note:**
This setting may be used with either a Server list or a Locator list. It will be used to form connections to either.

**Default:**

**API:** `org.apache.geode.cache.client.proxy.ProxySocketFactories`

**Example:**

``` pre
<pool ...>
<socket-factory>
<class-name>org.apache.geode.cache.client.proxy.SniSocketFactory</class-name>
<parameter name="hostname">
<string>my-haproxy-address</string>
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
</parameter>
<parameter name="port">
<string>12345</string>
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
</parameter>
</socket-factory>
</pool>
```

## <a id="cc-disk-store" class="no-quick-link"></a>&lt;disk-store&gt;

Expand Down
Expand Up @@ -53,15 +53,28 @@ Configure your server and client processes and data regions to run your client/s

<client-cache>
<pool name="publisher" subscription-enabled="true">
<locator host="lucy" port="41111"/>
<locator host="lucy" port="41111"/>
<locator host="lucy1" port="41111"/>
<locator host="lucy2" port="41111"/>
</pool>
...
<region name="clientRegion" ...
<region-attributes pool-name="publisher" ...

You do not need to provide the complete list of locators to the clients at startup, but you should provide as complete a list as possible. The locators maintain a dynamic list of locators and servers and provide the information to the clients as needed.

When TLS (SSL) is used clients can also be directed to go through a SNI gateway such as Istio or HAProxy to reach locators and servers. To do this add the following to your cache.xml pool configuration:
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
<pool... >
<socket-factory>
<class-name>org.apache.geode.cache.client.proxy.SniSocketFactory</class-name>
<parameter name="hostname">
<string>my-gateway-address</string>
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
</parameter>
<parameter name="port">
<string>my-gateway-port-number</string>
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
</parameter>
</socket-factory>
</pool>

3.

Configure the server data regions for client/server work, following these guidelines. These do not need to be performed in this order.
Expand Down
Expand Up @@ -258,8 +258,10 @@ private String[] buildJavaCommand(int vmNum, int namingPort, String version) {
// remove current-version product classes and resources from the classpath
dunitClasspath =
removeModulesFromPath(dunitClasspath, "geode-common", "geode-core", "geode-cq",
"geode-http-service", "geode-json", "geode-log4j", "geode-lucene",
"geode-serialization", "geode-wan", "geode-gfsh");
"geode-http-service", "geode-json", "geode-log4j", "geode-lucene", "geode-tcp-server",
"geode-membership", "geode-management", "geode-logging", "geode-web",
"geode-rebalancer",
"geode-serialization", "geode-wan", "geode-gfsh", "geode-lucene");
bschuchardt marked this conversation as resolved.
Show resolved Hide resolved
classPath = versionManager.getClasspath(version) + File.pathSeparator + dunitClasspath;
}

Expand Down