che #6258: Adding TLS support for OpenShift routes

Signed-off-by: Ilya Buziuk <ibuziuk@redhat.com>
6.19.x
Ilya Buziuk 2017-09-25 14:33:27 +02:00 committed by Ilya Buziuk
parent 772b1bbc71
commit dcbd5bf1e0
8 changed files with 168 additions and 7 deletions

View File

@ -398,6 +398,9 @@ che.infra.openshift.username=
che.infra.openshift.password=
che.infra.openshift.trust_certs=
# Create routes with Transport Layer Security (TLS) enabled
che.infra.openshift.tls_enabled=false
# Defines OpenShift namespace in which all workspaces will be created.
# If not set, every workspace will be created in a new project, where project name = workspace id
che.infra.openshift.project=

View File

@ -18,6 +18,7 @@ import org.eclipse.che.api.workspace.server.spi.InternalEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.provision.UniqueNamesProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.installer.InstallerConfigProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.route.TlsRouteProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.volume.PersistentVolumeClaimProvisioner;
/**
@ -32,15 +33,18 @@ public class OpenShiftInfrastructureProvisioner {
private final InstallerConfigProvisioner installerConfigProvisioner;
private final PersistentVolumeClaimProvisioner persistentVolumeClaimProvisioner;
private final UniqueNamesProvisioner uniqueNamesProvisioner;
private final TlsRouteProvisioner tlsRouteProvisioner;
@Inject
public OpenShiftInfrastructureProvisioner(
InstallerConfigProvisioner installerConfigProvisioner,
PersistentVolumeClaimProvisioner projectVolumeProvisioner,
UniqueNamesProvisioner uniqueNamesProvisioner) {
UniqueNamesProvisioner uniqueNamesProvisioner,
TlsRouteProvisioner tlsRouteProvisioner) {
this.installerConfigProvisioner = installerConfigProvisioner;
this.persistentVolumeClaimProvisioner = projectVolumeProvisioner;
this.uniqueNamesProvisioner = uniqueNamesProvisioner;
this.tlsRouteProvisioner = tlsRouteProvisioner;
}
public void provision(
@ -49,5 +53,6 @@ public class OpenShiftInfrastructureProvisioner {
installerConfigProvisioner.provision(environment, osEnv, identity);
persistentVolumeClaimProvisioner.provision(environment, osEnv, identity);
uniqueNamesProvisioner.provision(environment, osEnv, identity);
tlsRouteProvisioner.provision(environment, osEnv, identity);
}
}

View File

@ -90,8 +90,8 @@ public class RoutesAnnotations {
/**
* Retrieves server configuration from route annotations and returns (ref -> server config) map.
*/
public Map<String, ServerConfig> servers() {
Map<String, ServerConfig> servers = new HashMap<>();
public Map<String, ServerConfigImpl> servers() {
Map<String, ServerConfigImpl> servers = new HashMap<>();
for (Map.Entry<String, String> entry : annotations.entrySet()) {
Matcher refMatcher = SERVER_ANNOTATION_PATTERN.matcher(entry.getKey());
if (refMatcher.matches()) {

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.openshift.provision.route;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.api.model.RouteSpec;
import io.fabric8.openshift.api.model.TLSConfig;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.InternalEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.RoutesAnnotations;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.provision.ConfigurationProvisioner;
/**
* Enables Transport Layer Security (TLS) for workspace routes and changes protocol to secure (wss /
* https) in servers' configuration
*
* @author Ilya Buziuk
*/
@Singleton
public class TlsRouteProvisioner implements ConfigurationProvisioner {
private static final String TERMINATION_EDGE = "edge";
private static final String TERMINATION_POLICY_REDIRECT = "Redirect";
private final boolean isTlsEnabled;
@Inject
public TlsRouteProvisioner(@Named("che.infra.openshift.tls_enabled") boolean isTlsEnabled) {
this.isTlsEnabled = isTlsEnabled;
}
@Override
public void provision(
InternalEnvironment environment, OpenShiftEnvironment osEnv, RuntimeIdentity identity)
throws InfrastructureException {
if (isTlsEnabled) {
final Set<Route> routes = new HashSet<>(osEnv.getRoutes().values());
for (Route route : routes) {
useSecureProtocolForServers(route);
enableTls(route);
}
}
}
private void useSecureProtocolForServers(final Route route) {
Map<String, ServerConfigImpl> servers =
RoutesAnnotations.newDeserializer(route.getMetadata().getAnnotations()).servers();
servers.values().forEach(s -> s.setProtocol(getSecureProtocol(s.getProtocol())));
Map<String, String> annotations =
RoutesAnnotations.newSerializer().servers(servers).annotations();
route.getMetadata().getAnnotations().putAll(annotations);
}
private String getSecureProtocol(final String protocol) {
if ("ws".equals(protocol)) {
return "wss";
} else if ("http".equals(protocol)) {
return "https";
} else return protocol;
}
private void enableTls(final Route route) {
RouteSpec spec = route.getSpec();
spec.setTls(getTLSConfig());
}
private TLSConfig getTLSConfig() {
TLSConfig config = new TLSConfig();
config.setTermination(TERMINATION_EDGE);
config.setInsecureEdgeTerminationPolicy(TERMINATION_POLICY_REDIRECT);
return config;
}
}

View File

@ -18,6 +18,7 @@ import org.eclipse.che.api.workspace.server.spi.InternalEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.provision.UniqueNamesProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.installer.InstallerConfigProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.route.TlsRouteProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.volume.PersistentVolumeClaimProvisioner;
import org.mockito.InOrder;
import org.mockito.Mock;
@ -40,6 +41,7 @@ public class OpenShiftInfrastructureProvisionerTest {
@Mock private InternalEnvironment environment;
@Mock private OpenShiftEnvironment osEnv;
@Mock private RuntimeIdentity runtimeIdentity;
@Mock private TlsRouteProvisioner tlsRouteProvisioner;
private OpenShiftInfrastructureProvisioner osInfraProvisioner;
@ -49,8 +51,9 @@ public class OpenShiftInfrastructureProvisionerTest {
public void setUp() {
osInfraProvisioner =
new OpenShiftInfrastructureProvisioner(
installerProvisioner, pvcProvisioner, uniqueNamesProvisioner);
provisionOrder = inOrder(installerProvisioner, pvcProvisioner, uniqueNamesProvisioner);
installerProvisioner, pvcProvisioner, uniqueNamesProvisioner, tlsRouteProvisioner);
provisionOrder =
inOrder(installerProvisioner, pvcProvisioner, uniqueNamesProvisioner, tlsRouteProvisioner);
}
@Test
@ -66,6 +69,9 @@ public class OpenShiftInfrastructureProvisionerTest {
provisionOrder
.verify(uniqueNamesProvisioner)
.provision(eq(environment), eq(osEnv), eq(runtimeIdentity));
provisionOrder
.verify(tlsRouteProvisioner)
.provision(eq(environment), eq(osEnv), eq(runtimeIdentity));
provisionOrder.verifyNoMoreInteractions();
}
}

View File

@ -61,7 +61,7 @@ public class RoutesAnnotationsTest {
RoutesAnnotations.Deserializer deserializer = RoutesAnnotations.newDeserializer(annotations);
Map<String, ServerConfig> servers = deserializer.servers();
Map<String, ServerConfigImpl> servers = deserializer.servers();
ServerConfig server1 = servers.get("my-server1/http");
assertNotNull(server1, "first server");
assertEquals(server1.getPort(), "8000/tcp");

View File

@ -218,7 +218,7 @@ public class ServerExposerTest {
RoutesAnnotations.Deserializer routeDeserializer =
RoutesAnnotations.newDeserializer(route.getMetadata().getAnnotations());
Map<String, ServerConfig> servers = routeDeserializer.servers();
Map<String, ServerConfigImpl> servers = routeDeserializer.servers();
ServerConfig serverConfig = servers.get(serverName);
assertEquals(serverConfig, expected);
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.openshift.provision.route;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import io.fabric8.openshift.api.model.Route;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.spi.InternalEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link TlsRouteProvisioner}.
*
* @author Ilya Buziuk
*/
@Listeners(MockitoTestNGListener.class)
public class TlsRouteProvisionerTest {
@Mock private InternalEnvironment environment;
@Mock private OpenShiftEnvironment osEnv;
@Mock private RuntimeIdentity runtimeIdentity;
@Test
public void doNothingWhenTlsDisabled() throws Exception {
TlsRouteProvisioner tlsProvisioner = new TlsRouteProvisioner(false);
tlsProvisioner.provision(environment, osEnv, runtimeIdentity);
verify(osEnv, never()).getRoutes();
}
@Test
public void provisionTlsForRoutes() throws Exception {
TlsRouteProvisioner tlsProvisioner = new TlsRouteProvisioner(true);
final Map<String, Route> routes = new HashMap<>();
when(osEnv.getRoutes()).thenReturn(routes);
tlsProvisioner.provision(environment, osEnv, runtimeIdentity);
verify(osEnv, times(1)).getRoutes();
}
}