diff --git a/README.md b/README.md
index d87b445..33389f2 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,9 @@ The following additional parameters can be set in set in `elasticsearch.yml`:
|*_openshift.acl.expire_in_millis_*| The delay in milliseconds before generated ACLs are removed from|
|*_openshift.config.project_index_prefix_*| The string value that project/namespace indices use as their prefix (default: ``) for example, with the common data model, if the namespace is `test`, the index name will be `project.test.$uuid.YYYY.MM.DD`. In this case, use `"project"` as the prefix - do not include the trailing `.`.|
|*_openshift.kibana.index.mode_*| The setting that determines the kibana index is used by users. Valid values are one of the following:
**unique** (Default) - Each user gets a unique index for kibana visualizations (e.g. .kibana.USER_UUID) **ops_shared** - Users who are in an ops role will share an index (e.g. kibana) while non ops users will have a unique index (e.g. .kibana.USER_UUID) |
+|*openshift.master.url*| If Openshift users must be authenticated to a remote cluster, this parameter must contain its URL (default: `https://kubernetes.default.svc`).|
+|*openshift.trust.certificates*| Trust remote Openshift certificate (default: `true`)|
+|*openshift.ca.path*| Absolute file path to the certificate that has to be used to authenticate remote Openshift cluster (default: `empty`)|
*Note*: The `io.fabric8.elasticsearch.kibana.mapping.*` properties are required and must be defined for the plugin to function. A sample file
may be found in the `samples` folder.
diff --git a/src/main/java/io/fabric8/elasticsearch/plugin/ConfigurationSettings.java b/src/main/java/io/fabric8/elasticsearch/plugin/ConfigurationSettings.java
index a2b2f6c..d9de244 100644
--- a/src/main/java/io/fabric8/elasticsearch/plugin/ConfigurationSettings.java
+++ b/src/main/java/io/fabric8/elasticsearch/plugin/ConfigurationSettings.java
@@ -89,6 +89,10 @@ public interface ConfigurationSettings extends KibanaIndexMode{
static final String OPENSHIFT_ACL_ROLE_STRATEGY = "openshift.acl.role_strategy";
static final String DEFAULT_ACL_ROLE_STRATEGY = "user";
+ static final String OPENSHIFT_MASTER = "openshift.master.url";
+ static final String OPENSHIFT_CA_PATH = "openshift.ca.path";
+ static final String OPENSHIFT_TRUST_CERT = "openshift.trust.certificates";
+
/**
* List of index patterns to create for operations users
*/
diff --git a/src/main/java/io/fabric8/elasticsearch/plugin/OpenShiftElasticSearchPlugin.java b/src/main/java/io/fabric8/elasticsearch/plugin/OpenShiftElasticSearchPlugin.java
index cebcf3e..ed9987b 100644
--- a/src/main/java/io/fabric8/elasticsearch/plugin/OpenShiftElasticSearchPlugin.java
+++ b/src/main/java/io/fabric8/elasticsearch/plugin/OpenShiftElasticSearchPlugin.java
@@ -87,7 +87,7 @@ public Collection createComponents(Client client, ClusterService cluster
final PluginSettings pluginSettings = new PluginSettings(settings);
final IndexMappingLoader indexMappingLoader = new IndexMappingLoader(settings);
final PluginClient pluginClient = new PluginClient(client, threadPool.getThreadContext());
- final OpenshiftAPIService apiService = new OpenshiftAPIService();
+ final OpenshiftAPIService apiService = new OpenshiftAPIService(pluginSettings);
final RequestUtils requestUtils = new RequestUtils(pluginSettings, apiService);
final OpenshiftRequestContextFactory contextFactory = new OpenshiftRequestContextFactory(settings, requestUtils,
apiService);
@@ -212,6 +212,9 @@ public List> getSettings() {
settings.add(Setting.boolSetting("openshift.operations.allow_cluster_reader", false, Property.NodeScope));
settings.add(Setting.simpleString("openshift.kibana.index.mode", Property.NodeScope));
settings.add(Setting.simpleString(OPENSHIFT_ACL_ROLE_STRATEGY, Property.NodeScope));
+ settings.add(Setting.simpleString(OPENSHIFT_CA_PATH, Property.NodeScope));
+ settings.add(Setting.simpleString(OPENSHIFT_MASTER, Property.NodeScope));
+ settings.add(Setting.simpleString(OPENSHIFT_TRUST_CERT, Property.NodeScope));
return settings;
}
diff --git a/src/main/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIService.java b/src/main/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIService.java
index d84b224..2c19a31 100644
--- a/src/main/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIService.java
+++ b/src/main/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIService.java
@@ -51,18 +51,20 @@ public class OpenshiftAPIService {
private static final String APPLICATION_JSON = "application/json";
private static final Logger LOGGER = Loggers.getLogger(OpenshiftAPIService.class);
private final OpenShiftClientFactory factory;
-
- public OpenshiftAPIService() {
- this(new OpenShiftClientFactory(){});
+ private final PluginSettings settings;
+
+ public OpenshiftAPIService(PluginSettings settings) {
+ this(new OpenShiftClientFactory(){}, settings);
}
-
- public OpenshiftAPIService(OpenShiftClientFactory factory) {
+
+ public OpenshiftAPIService(OpenShiftClientFactory factory, PluginSettings settings) {
this.factory = factory;
+ this.settings = settings;
}
public String userName(final String token) {
Response response = null;
- try (DefaultOpenShiftClient client = factory.buildClient(token)) {
+ try (DefaultOpenShiftClient client = factory.buildClient(settings, token)) {
Request okRequest = new Request.Builder()
.url(client.getMasterUrl() + "apis/user.openshift.io/v1/users/~")
.header(ACCEPT, APPLICATION_JSON)
@@ -83,7 +85,7 @@ public String userName(final String token) {
}
public Set projectNames(final String token){
- try (DefaultOpenShiftClient client = factory.buildClient(token)) {
+ try (DefaultOpenShiftClient client = factory.buildClient(settings, token)) {
Request request = new Request.Builder()
.url(client.getMasterUrl() + "apis/project.openshift.io/v1/projects")
.header(ACCEPT, APPLICATION_JSON)
@@ -124,7 +126,7 @@ public Set projectNames(final String token){
*/
public boolean localSubjectAccessReview(final String token,
final String project, final String verb, final String resource, final String resourceAPIGroup, final String [] scopes) {
- try (DefaultOpenShiftClient client = factory.buildClient(token)) {
+ try (DefaultOpenShiftClient client = factory.buildClient(settings, token)) {
XContentBuilder payload = XContentFactory.jsonBuilder()
.startObject()
.field("kind","SubjectAccessReview")
@@ -189,8 +191,20 @@ private void log(Response response, String body) {
}
interface OpenShiftClientFactory {
- default DefaultOpenShiftClient buildClient(final String token) {
+ default DefaultOpenShiftClient buildClient(final PluginSettings settings, final String token) {
Config config = new ConfigBuilder().withOauthToken(token).build();
+
+ if (settings.getMasterUrl() != null) {
+ config.setMasterUrl(settings.getMasterUrl());
+ }
+ if (settings.isTrustCerts() != null) {
+ config.setTrustCerts(settings.isTrustCerts());
+ }
+ if (settings.getOpenshiftCaPath() != null) {
+ config.setCaCertFile(settings.getOpenshiftCaPath());
+ }
+ LOGGER.debug("Target cluster is {}, trust cert is {}, ca path is {}",
+ config.getMasterUrl(), config.isTrustCerts(), config.getCaCertFile());
return new DefaultOpenShiftClient(config);
}
diff --git a/src/main/java/io/fabric8/elasticsearch/plugin/PluginSettings.java b/src/main/java/io/fabric8/elasticsearch/plugin/PluginSettings.java
index f438323..b7cf44a 100644
--- a/src/main/java/io/fabric8/elasticsearch/plugin/PluginSettings.java
+++ b/src/main/java/io/fabric8/elasticsearch/plugin/PluginSettings.java
@@ -42,6 +42,9 @@ public class PluginSettings implements ConfigurationSettings {
private final Set opsIndexPatterns;
private final long expireInMillis;
private final Settings settings;
+ private final String masterUrl;
+ private final Boolean isTrustCerts;
+ private final String openshiftCaPath;
public PluginSettings(final Settings settings) {
this.settings = settings;
@@ -64,6 +67,15 @@ public PluginSettings(final Settings settings) {
this.opsIndexPatterns = new HashSet(Arrays.asList(settings.getAsArray(OPENSHIFT_KIBANA_OPS_INDEX_PATTERNS, DEFAULT_KIBANA_OPS_INDEX_PATTERNS)));
this.expireInMillis = settings.getAsLong(OPENSHIFT_ACL_EXPIRE_IN_MILLIS, new Long(1000 * 60));
+ this.masterUrl = settings.get(OPENSHIFT_MASTER);
+ this.openshiftCaPath = settings.get(OPENSHIFT_CA_PATH);
+ // Do not overwrite default K8S behavior
+ if (settings.get(OPENSHIFT_TRUST_CERT) != null) {
+ this.isTrustCerts = settings.getAsBoolean(OPENSHIFT_TRUST_CERT, true);
+ } else {
+ this.isTrustCerts = null;
+ }
+
LOGGER.info("Using kibanaIndexMode: '{}'", this.kibanaIndexMode);
LOGGER.debug("searchGuardIndex: {}", this.searchGuardIndex);
LOGGER.debug("roleStrategy: {}", this.roleStrategy);
@@ -113,4 +125,16 @@ public void setKibanaIndexMode(String kibanaIndexMode) {
public Set getKibanaOpsIndexPatterns() {
return opsIndexPatterns;
}
+
+ public String getMasterUrl() {
+ return masterUrl;
+ }
+
+ public String getOpenshiftCaPath() {
+ return openshiftCaPath;
+ }
+
+ public Boolean isTrustCerts() {
+ return isTrustCerts;
+ }
}
diff --git a/src/main/java/io/fabric8/elasticsearch/util/RequestUtils.java b/src/main/java/io/fabric8/elasticsearch/util/RequestUtils.java
index 05b16d3..8babe8a 100644
--- a/src/main/java/io/fabric8/elasticsearch/util/RequestUtils.java
+++ b/src/main/java/io/fabric8/elasticsearch/util/RequestUtils.java
@@ -107,7 +107,7 @@ public String getBearerToken(RestRequest request) {
}
return StringUtils.defaultIfEmpty(token, "");
}
-
+
public boolean isClientCertAuth(final ThreadContext threadContext) {
return threadContext != null && StringUtils.isNotEmpty(threadContext.getTransient("_sg_ssl_transport_principal"));
}
diff --git a/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIServiceTest.java b/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIServiceTest.java
index 9c5904e..6e5a70d 100644
--- a/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIServiceTest.java
+++ b/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftAPIServiceTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
@@ -29,6 +30,7 @@
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
+import org.elasticsearch.common.settings.Settings;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -55,7 +57,8 @@ public class OpenshiftAPIServiceTest {
@Rule
public OpenShiftServer apiServer = new OpenShiftServer();
- private OpenshiftAPIService service = new OpenshiftAPIService();
+ private final PluginSettings pluginSettings = new PluginSettings(Settings.EMPTY);
+ private OpenshiftAPIService service = new OpenshiftAPIService(pluginSettings);
@Before
public void setup() {
@@ -105,7 +108,7 @@ public void testLocalSubjectAccessReviewWhenNotNonResourceURL() throws IOExcepti
DefaultOpenShiftClient client = mock(DefaultOpenShiftClient.class);
OpenShiftClientFactory factory = mock(OpenShiftClientFactory.class);
Call call = mock(Call.class);
- when(factory.buildClient(anyString())).thenReturn(client);
+ when(factory.buildClient(eq(pluginSettings), anyString())).thenReturn(client);
when(client.getHttpClient()).thenReturn(okClient);
when(client.getMasterUrl()).thenReturn(new URL("https://localhost:8443/"));
@@ -121,7 +124,7 @@ public void testLocalSubjectAccessReviewWhenNotNonResourceURL() throws IOExcepti
when(okClient.newCall(any(Request.class))).thenAnswer(answer);
when(call.execute()).thenReturn(response);
- service = new OpenshiftAPIService(factory );
+ service = new OpenshiftAPIService(factory, pluginSettings);
assertTrue(service.localSubjectAccessReview("sometoken", "openshift-logging", "get", "pod/metrics", null, ArrayUtils.EMPTY_STRING_ARRAY));
Buffer buffer = new Buffer();
@@ -139,7 +142,7 @@ public void testLocalSubjectAccessReviewForNonResourceURL() throws IOException{
DefaultOpenShiftClient client = mock(DefaultOpenShiftClient.class);
OpenShiftClientFactory factory = mock(OpenShiftClientFactory.class);
Call call = mock(Call.class);
- when(factory.buildClient(anyString())).thenReturn(client);
+ when(factory.buildClient(eq(pluginSettings), anyString())).thenReturn(client);
when(client.getHttpClient()).thenReturn(okClient);
when(client.getMasterUrl()).thenReturn(new URL("https://localhost:8443/"));
@@ -155,7 +158,7 @@ public void testLocalSubjectAccessReviewForNonResourceURL() throws IOException{
when(okClient.newCall(any(Request.class))).thenAnswer(answer);
when(call.execute()).thenReturn(response);
- service = new OpenshiftAPIService(factory );
+ service = new OpenshiftAPIService(factory, pluginSettings);
assertTrue(service.localSubjectAccessReview("sometoken", "openshift-logging", "get", "/metrics", null, ArrayUtils.EMPTY_STRING_ARRAY));
Buffer buffer = new Buffer();
diff --git a/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftClientFactoryTest.java b/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftClientFactoryTest.java
new file mode 100644
index 0000000..4a1f692
--- /dev/null
+++ b/src/test/java/io/fabric8/elasticsearch/plugin/OpenshiftClientFactoryTest.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fabric8.elasticsearch.plugin;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import com.google.common.io.Files;
+
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.ConfigBuilder;
+import io.fabric8.openshift.client.NamespacedOpenShiftClient;
+
+public class OpenshiftClientFactoryTest {
+
+ private final String cert =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIC0DCCAbigAwIBAgIBATANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5sb2dn\n"
+ + "aW5nLXNpZ25lcjAeFw0xNzEwMTQxMTMwMDFaFw0yNzEwMTIxMTMwMDJaMBkxFzAV\n"
+ + "BgNVBAMTDmxvZ2dpbmctc2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
+ + "CgKCAQEAwjq3zygMEywx0PD/qGO2IwZxN18DwJbWB71JH+ldbLQHMJ3fvIy4wpJV\n"
+ + "FlJDPAejQ6hFnsoArVZInxcIcVfTiLgX15CXfCcrWUXXxfY2WWc6qDbQKje/+VZX\n"
+ + "/nr8c5DvbiDQxTDjXNO7WDGxqCaJIKg72VIqE4ac4AYNEwHeW3rd5cLEh/wfAu3n\n"
+ + "/iGFQ0v75ZG8ef2QQE364/d5GHMrXcWXUrXxuqRO/wdEjuXkP3SY/8sUZHCdugt8\n"
+ + "QygSXLp5mHaMc+Ie70/gl7u8wAxJGOvkjYVEgZPUTbemjEYhr9QwMuPvXxalWNc8\n"
+ + "kWIsOXnnyKG+RWDo7FE7kZtXpYfBcwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAqQw\n"
+ + "DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAf+1IaNvSYQ1BNQVa\n"
+ + "hODEru6x+Ytg5HUyykT4tmxvvlqLS03ez37zKi2tDQBI/Sl4l46mu9H7GS98viO7\n"
+ + "Cj9Vn7km70GH6vDvCjY3iMKYK+rXzp1D2az0wmdmYymfrP8WC4X0q+KMZKPSVb9g\n"
+ + "9/0kAKPtH7YRzTiaSMlWhxNFQxM+zrHvw/Vp16PXZwq+FCbtv6zemQKo4JBHN2LM\n"
+ + "dIfgLqEMBkpvo1TeD3HOB4LyJJ6nnG4bUWsOnYYSZw1L70rHX9Vu5xq7xap2eL9g\n"
+ + "Uk4XsS8F+8hOE3zaHbqKbxRSqxnNqBI+UM+nQc1i3Qh2CXy8jgdVTjxWstDN/IHN\n"
+ + "Y6RrKw== \n"
+ + "-----END CERTIFICATE-----";
+
+ // We need a temporary folder because K8S plugin check if CA file exists in constructor
+ @Rule
+ public TemporaryFolder certFolder = new TemporaryFolder();
+
+ @Test
+ public void testWhenRemoteCAIsNotNull() throws Exception {
+
+ File tempCaFile = certFolder.newFile("ca.crt");
+ Files.write(cert.getBytes(), tempCaFile);
+
+ final Config config = (new ConfigBuilder()).build();
+ final PluginSettings pluginSettings = mock(PluginSettings.class);
+ when(pluginSettings.getOpenshiftCaPath()).thenReturn(tempCaFile.getAbsolutePath());
+ when(pluginSettings.getMasterUrl()).thenReturn("https://foo.bar");
+ when(pluginSettings.isTrustCerts()).thenReturn(false);
+
+ OpenshiftAPIService.OpenShiftClientFactory factory = new OpenshiftAPIService.OpenShiftClientFactory(){};
+
+ final NamespacedOpenShiftClient openShiftClient = factory.buildClient(pluginSettings, "foo");
+ final Config k8sConfig = openShiftClient.getConfiguration();
+
+ assertEquals("Exp. the CA file path to be loaded by K8S plugin", tempCaFile.getAbsolutePath(), k8sConfig.getCaCertFile());
+ assertEquals("Exp. the master url to be correctly set in the K8S plugin", "https://foo.bar/", k8sConfig.getMasterUrl());
+ assertFalse("Exp. the trust cert boolean to be correctly set in the K8S plugin", k8sConfig.isTrustCerts());
+ }
+
+}
diff --git a/src/test/java/io/fabric8/elasticsearch/plugin/PluginSettingsTest.java b/src/test/java/io/fabric8/elasticsearch/plugin/PluginSettingsTest.java
index 07a332c..9a89cbf 100644
--- a/src/test/java/io/fabric8/elasticsearch/plugin/PluginSettingsTest.java
+++ b/src/test/java/io/fabric8/elasticsearch/plugin/PluginSettingsTest.java
@@ -17,6 +17,9 @@
package io.fabric8.elasticsearch.plugin;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import org.elasticsearch.common.settings.Settings;
import org.junit.Test;
@@ -37,4 +40,25 @@ public void testKibanaIndexModeDefault() {
assertEquals("Exp. the plugin default to make kibana index mode unique", "unique", plugin.getKibanaIndexMode());
}
+ @Test
+ public void testRemoteOpenshiftWithDefaultConfiguration() {
+ PluginSettings plugin = new PluginSettings(Settings.builder().build());
+ assertNull("Exp. remote Openshift URL is null by default to not override default K8S plugin behaviour", plugin.getMasterUrl());
+ assertNull("Exp. Openshift certificate authority is null by default to not override default K8S plugin behaviour", plugin.getOpenshiftCaPath());
+ assertNull("Exp. default trust cert is null to not override default K8S plugin behaviour", plugin.isTrustCerts());
+ }
+
+ @Test
+ public void testRemoteOpenshift() {
+ final String expectedRemoteOpenshiftUrl = "https://foo.bar:8443";
+ final String expectedOpenshiftCaPath = "/etc/elasticsearch/secret/openshift-ca";
+ final String source = "openshift.master.url: " + expectedRemoteOpenshiftUrl + "\n"
+ + "openshift.ca.path: " + expectedOpenshiftCaPath + "\n"
+ + "openshift.trust.certificates: false";
+ PluginSettings plugin = new PluginSettings(Settings.builder().loadFromSource(source).build());
+ assertEquals("Exp. the correct remote Openshift URL", expectedRemoteOpenshiftUrl, plugin.getMasterUrl());
+ assertEquals("Exp. the correct Openshift certificate authority", expectedOpenshiftCaPath, plugin.getOpenshiftCaPath());
+ assertFalse("Exp. the correct non default trust cert value from configuration", plugin.isTrustCerts());
+ }
+
}