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

Support git operation for repos with self-signed SSL certs #15218

Merged
merged 2 commits into from
Nov 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions deploy/kubernetes/helm/che/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,25 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace


# If git-self-signed-cert is used then configure Che Server with certificate content
# to propagate it to the specified location and provide particular configuration for Git service
{{- if .Values.global.useGitSelfSignedCerts }}
- name: CHE_GIT_SELF__SIGNED__CERT
valueFrom:
configMapKeyRef:
name: {{ .Values.global.cheGitSelfSignedCertConfigMapName }}
key: ca.crt
optional: false
- name: CHE_GIT_SELF__SIGNED__CERT__HOST
valueFrom:
configMapKeyRef:
name: {{ .Values.global.cheGitSelfSignedCertConfigMapName }}
key: githost
optional: false
{{- end }}

{{- if .Values.global.tls.enabled }}

# If self-signed-cert is used then configure Che Server with certificate content
Expand Down
7 changes: 7 additions & 0 deletions deploy/kubernetes/helm/che/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ global:
useSelfSignedCerts: false
selfSignedCertSecretName: self-signed-cert


## If using git self-signed certificate is enabled
## then certificate from `cheGitSelfSignedCertConfigMapName` will be propagated to Che components'
## and provide particular configuration for Git
useGitSelfSignedCerts: false
cheGitSelfSignedCertConfigMapName: che-git-self-signed-cert

gitHubClientID: ""
gitHubClientSecret: ""
pvcClaim: "1Gi"
Expand Down
12 changes: 12 additions & 0 deletions deploy/openshift/templates/che-server-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ objects:
key: ca.crt
name: self-signed-certificate
optional: true
- name: CHE_GIT_SELF__SIGNED__CERT
valueFrom:
configMapKeyRef:
name: che-git-self-signed-cert
key: ca.crt
optional: true
- name: CHE_GIT_SELF__SIGNED__CERT__HOST
valueFrom:
configMapKeyRef:
name: che-git-self-signed-cert
key: githost
optional: true
- name: CHE_WORKSPACE_PLUGIN__REGISTRY__URL
value: "${CHE_WORKSPACE_PLUGIN__REGISTRY__URL}"
- name: CHE_WORKSPACE_DEVFILE__REGISTRY__URL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.CertificateProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitUserProfileProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitConfigProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ImagePullSecretProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.IngressTlsProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.LogsVolumeMachineProvisioner;
Expand All @@ -31,6 +31,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ServiceAccountProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.UniqueNamesProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.VcsSshKeysProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.VcsSslCertificateProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.env.EnvVarsConverter;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.limits.ram.RamLimitRequestProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.restartpolicy.RestartPolicyRewriter;
Expand Down Expand Up @@ -73,8 +74,9 @@ class KubernetesEnvironmentProvisionerImpl
private final ServiceAccountProvisioner serviceAccountProvisioner;
private final CertificateProvisioner certificateProvisioner;
private final VcsSshKeysProvisioner vcsSshKeysProvisioner;
private final GitUserProfileProvisioner gitUserProfileProvisioner;
private final GitConfigProvisioner gitConfigProvisioner;
private final PreviewUrlExposer<KubernetesEnvironment> previewUrlExposer;
private final VcsSslCertificateProvisioner vcsSslCertificateProvisioner;

@Inject
public KubernetesEnvironmentProvisionerImpl(
Expand All @@ -94,8 +96,9 @@ public KubernetesEnvironmentProvisionerImpl(
ServiceAccountProvisioner serviceAccountProvisioner,
CertificateProvisioner certificateProvisioner,
VcsSshKeysProvisioner vcsSshKeysProvisioner,
GitUserProfileProvisioner gitUserProfileProvisioner,
PreviewUrlExposer<KubernetesEnvironment> previewUrlExposer) {
GitConfigProvisioner gitConfigProvisioner,
PreviewUrlExposer<KubernetesEnvironment> previewUrlExposer,
VcsSslCertificateProvisioner vcsSslCertificateProvisioner) {
this.pvcEnabled = pvcEnabled;
this.volumesStrategy = volumesStrategy;
this.uniqueNamesProvisioner = uniqueNamesProvisioner;
Expand All @@ -112,7 +115,8 @@ public KubernetesEnvironmentProvisionerImpl(
this.serviceAccountProvisioner = serviceAccountProvisioner;
this.certificateProvisioner = certificateProvisioner;
this.vcsSshKeysProvisioner = vcsSshKeysProvisioner;
this.gitUserProfileProvisioner = gitUserProfileProvisioner;
this.vcsSslCertificateProvisioner = vcsSslCertificateProvisioner;
this.gitConfigProvisioner = gitConfigProvisioner;
this.previewUrlExposer = previewUrlExposer;
}

Expand Down Expand Up @@ -152,7 +156,8 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity)
serviceAccountProvisioner.provision(k8sEnv, identity);
certificateProvisioner.provision(k8sEnv, identity);
vcsSshKeysProvisioner.provision(k8sEnv, identity);
gitUserProfileProvisioner.provision(k8sEnv, identity);
vcsSslCertificateProvisioner.provision(k8sEnv, identity);
gitConfigProvisioner.provision(k8sEnv, identity);
LOG.debug("Provisioning Kubernetes environment done for workspace '{}'", workspaceId);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;

@Singleton
public class GitUserProfileProvisioner implements ConfigurationProvisioner<KubernetesEnvironment> {
public class GitConfigProvisioner implements ConfigurationProvisioner<KubernetesEnvironment> {

private final String GIT_CONFIG_MAP_NAME_SUFFIX = "-gitconfig";

Expand All @@ -60,14 +60,20 @@ public class GitUserProfileProvisioner implements ConfigurationProvisioner<Kuber
private static final String GIT_USER_NAME_PROPERTY = "git.user.name";
private static final String GIT_USER_EMAIL_PROPERTY = "git.user.email";
private static final String CONFIG_MAP_VOLUME_NAME = "gitconfigvolume";
private static final String HTTPS = "https://";

private PreferenceManager preferenceManager;
private UserManager userManager;
private VcsSslCertificateProvisioner vcsSslCertificateProvisioner;

@Inject
public GitUserProfileProvisioner(PreferenceManager preferenceManager, UserManager userManager) {
public GitConfigProvisioner(
PreferenceManager preferenceManager,
UserManager userManager,
VcsSslCertificateProvisioner vcsSslCertificateProvisioner) {
this.preferenceManager = preferenceManager;
this.userManager = userManager;
this.vcsSslCertificateProvisioner = vcsSslCertificateProvisioner;
}

@Override
Expand Down Expand Up @@ -178,6 +184,33 @@ private Optional<String> prepareGitConfigurationContent(String userName, String
config.append('\t').append("email = ").append(userEmail).append('\n');
}

if (vcsSslCertificateProvisioner.isConfigured()) {
String host = vcsSslCertificateProvisioner.getGitServerHost();

// Will add leading scheme (https://) if it not provide in configuration.
// If host not configured wil return empty string, it will means that
// provided certificate will used for all https connections.

StringBuilder gitServerHosts = new StringBuilder();
if (!isNullOrEmpty(host)) {
gitServerHosts.append(" \"");
if (!host.startsWith(HTTPS)) {
gitServerHosts.append(HTTPS);
}
gitServerHosts.append(host);
gitServerHosts.append("\"");
}

config
.append("[http")
.append(gitServerHosts.toString())
.append("]")
.append('\n')
.append('\t')
.append("sslCAInfo = ")
.append(vcsSslCertificateProvisioner.getCertPath());
}

return of(config.toString());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.provision;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Collections.singletonMap;

import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import java.util.Optional;
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.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData;

/**
* Mount configured self-signed certificate for git provider as file in each workspace machines if
* configured.
*
* @author Vitalii Parfonov
*/
@Singleton
public class VcsSslCertificateProvisioner
implements ConfigurationProvisioner<KubernetesEnvironment> {
static final String CHE_GIT_SELF_SIGNED_CERT_CONFIG_MAP_SUFFIX = "-che-git-self-signed-cert";
static final String CHE_GIT_SELF_SIGNED_VOLUME = "che-git-self-signed-cert";
static final String CERT_MOUNT_PATH = "/etc/che/git/cert/";
static final String CA_CERT_FILE = "ca.crt";

@Inject(optional = true)
@Named("che.git.self_signed_cert")
private String certificate;

@Inject(optional = true)
@Named("che.git.self_signed_cert_host")
private String host;

public VcsSslCertificateProvisioner() {}

@VisibleForTesting
VcsSslCertificateProvisioner(String certificate, String host) {
this.certificate = certificate;
this.host = host;
}

/**
* @return true only if system configured for using self-signed certificate fot https git
* operation
*/
public boolean isConfigured() {
return !isNullOrEmpty(certificate);
}

/** @return path to the certificate file */
public String getCertPath() {
return CERT_MOUNT_PATH + CA_CERT_FILE;
}

/**
* Return given in configuration git server host (e.g. 110.23.0.1:3000).
*
* @return git server host for git config if it configured in che.git.self_signed_cert_host
*/
public String getGitServerHost() {
return host;
}

@Override
public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity)
throws InfrastructureException {
if (!isConfigured()) {
return;
}
String selfSignedCertConfigMapName =
identity.getWorkspaceId() + CHE_GIT_SELF_SIGNED_CERT_CONFIG_MAP_SUFFIX;
k8sEnv
.getConfigMaps()
.put(
selfSignedCertConfigMapName,
new ConfigMapBuilder()
.withNewMetadata()
.withName(selfSignedCertConfigMapName)
.endMetadata()
.withData(singletonMap(CA_CERT_FILE, certificate))
.build());

for (PodData pod : k8sEnv.getPodsData().values()) {
Optional<Volume> certVolume =
pod.getSpec()
.getVolumes()
.stream()
.filter(v -> v.getName().equals(CHE_GIT_SELF_SIGNED_VOLUME))
.findAny();

if (!certVolume.isPresent()) {
pod.getSpec().getVolumes().add(buildCertVolume(selfSignedCertConfigMapName));
}

for (Container container : pod.getSpec().getInitContainers()) {
provisionCertVolumeMountIfNeeded(container);
}
for (Container container : pod.getSpec().getContainers()) {
provisionCertVolumeMountIfNeeded(container);
}
}
}

private void provisionCertVolumeMountIfNeeded(Container container) {
Optional<VolumeMount> certVolumeMount =
container
.getVolumeMounts()
.stream()
.filter(vm -> vm.getName().equals(CHE_GIT_SELF_SIGNED_VOLUME))
.findAny();
if (!certVolumeMount.isPresent()) {
container.getVolumeMounts().add(buildCertVolumeMount());
}
}

private VolumeMount buildCertVolumeMount() {
return new VolumeMountBuilder()
.withName(CHE_GIT_SELF_SIGNED_VOLUME)
.withNewReadOnly(true)
.withMountPath(CERT_MOUNT_PATH)
.build();
}

private Volume buildCertVolume(String configMapName) {
return new VolumeBuilder()
.withName(CHE_GIT_SELF_SIGNED_VOLUME)
.withConfigMap(new ConfigMapVolumeSourceBuilder().withName(configMapName).build())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.CertificateProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitUserProfileProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.GitConfigProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ImagePullSecretProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.IngressTlsProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.LogsVolumeMachineProvisioner;
Expand All @@ -29,6 +29,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ServiceAccountProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.UniqueNamesProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.VcsSshKeysProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.VcsSslCertificateProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.env.EnvVarsConverter;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.limits.ram.RamLimitRequestProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.restartpolicy.RestartPolicyRewriter;
Expand Down Expand Up @@ -66,8 +67,9 @@ public class KubernetesEnvironmentProvisionerTest {
@Mock private ServiceAccountProvisioner serviceAccountProvisioner;
@Mock private CertificateProvisioner certificateProvisioner;
@Mock private VcsSshKeysProvisioner vcsSshKeysProvisioner;
@Mock private GitUserProfileProvisioner gitUserProfileProvisioner;
@Mock private GitConfigProvisioner gitConfigProvisioner;
@Mock private PreviewUrlExposer previewUrlExposer;
@Mock private VcsSslCertificateProvisioner vcsSslCertificateProvisioner;

private KubernetesEnvironmentProvisioner<KubernetesEnvironment> k8sInfraProvisioner;

Expand All @@ -93,8 +95,9 @@ public void setUp() {
serviceAccountProvisioner,
certificateProvisioner,
vcsSshKeysProvisioner,
gitUserProfileProvisioner,
previewUrlExposer);
gitConfigProvisioner,
previewUrlExposer,
vcsSslCertificateProvisioner);
provisionOrder =
inOrder(
logsVolumeMachineProvisioner,
Expand All @@ -111,7 +114,7 @@ public void setUp() {
proxySettingsProvisioner,
serviceAccountProvisioner,
certificateProvisioner,
gitUserProfileProvisioner,
gitConfigProvisioner,
previewUrlExposer);
}

Expand All @@ -137,7 +140,7 @@ public void performsOrderedProvisioning() throws Exception {
provisionOrder.verify(proxySettingsProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity));
provisionOrder.verify(serviceAccountProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity));
provisionOrder.verify(certificateProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity));
provisionOrder.verify(gitUserProfileProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity));
provisionOrder.verify(gitConfigProvisioner).provision(eq(k8sEnv), eq(runtimeIdentity));
provisionOrder.verifyNoMoreInteractions();
}
}
Loading