diff --git a/.ci/cico_operator_prcheck.sh b/.ci/cico_operator_prcheck.sh index 190ae822a..17236a2ad 100644 --- a/.ci/cico_operator_prcheck.sh +++ b/.ci/cico_operator_prcheck.sh @@ -20,7 +20,7 @@ Catch_Finish() { } init() { - GO_TOOLSET_VERSION="1.11.5-3" + GO_TOOLSET_VERSION="1.12.12-4" SCRIPT=$(readlink -f "$0") # this script's absolute path SCRIPTPATH=$(dirname "$SCRIPT") # /path/to/e2e/ folder if [[ ${WORKSPACE} ]] && [[ -d ${WORKSPACE} ]]; then OPERATOR_REPO=${WORKSPACE}; else OPERATOR_REPO=$(dirname "$SCRIPTPATH"); fi diff --git a/pkg/controller/che/create.go b/pkg/controller/che/create.go index a4d686e19..be3b92d07 100644 --- a/pkg/controller/che/create.go +++ b/pkg/controller/che/create.go @@ -337,7 +337,7 @@ func (r *ReconcileChe) CreateTLSSecret(instance *orgv1.CheCluster, url string, n if err := r.client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: instance.Namespace}, secret); err != nil && errors.IsNotFound(err) { crt, err := r.GetEndpointTlsCrt(instance, url) if err != nil { - logrus.Errorf("Failed to extract crt. Failed to create a secret with a self signed crt: %s", err) + logrus.Errorf("Failed to extract crt for secret %s. Failed to create a secret with a self signed crt: %s", name, err) return err } else { secret := deploy.NewSecret(instance, name, crt) diff --git a/pkg/controller/che/k8s_helpers.go b/pkg/controller/che/k8s_helpers.go index 9265ed958..4c5ab2096 100644 --- a/pkg/controller/che/k8s_helpers.go +++ b/pkg/controller/che/k8s_helpers.go @@ -16,21 +16,25 @@ import ( "context" "crypto/tls" "encoding/pem" + "io" + "net/http" + "net/url" + "strings" + "time" + orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1" "github.com/eclipse/che-operator/pkg/deploy" "github.com/eclipse/che-operator/pkg/util" routev1 "github.com/openshift/api/route/v1" "github.com/sirupsen/logrus" - "io" + "golang.org/x/net/http/httpproxy" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" - "net/http" "sigs.k8s.io/controller-runtime/pkg/client/config" - "time" ) type k8s struct { @@ -221,10 +225,9 @@ func (cl *k8s) GetEvents(deploymentName string, ns string) (list *corev1.EventLi } // GetLogs prints stderr or stdout from a selected pod. Log size is capped at 60000 bytes -func (cl *k8s) GetPodLogs(podName string, ns string) () { +func (cl *k8s) GetPodLogs(podName string, ns string) { var limitBytes int64 = 60000 - req := cl.clientset.CoreV1().Pods(ns).GetLogs(podName, &corev1.PodLogOptions{LimitBytes: &limitBytes}, - ) + req := cl.clientset.CoreV1().Pods(ns).GetLogs(podName, &corev1.PodLogOptions{LimitBytes: &limitBytes}) readCloser, err := req.Stream() if err != nil { logrus.Errorf("Pod error log: %v", err) @@ -256,10 +259,10 @@ func (cl *k8s) GetDeploymentPod(name string, ns string) (podName string, err err // GetEndpointTlsCrt creates a test TLS route and gets it to extract certificate chain // There's an easier way which is to read tls secret in default (3.11) or openshift-ingress (4.0) namespace // which however requires extra privileges for operator service account -func (r *ReconcileChe) GetEndpointTlsCrt(instance *orgv1.CheCluster, url string) (certificate []byte, err error) { +func (r *ReconcileChe) GetEndpointTlsCrt(instance *orgv1.CheCluster, endpointUrl string) (certificate []byte, err error) { testRoute := &routev1.Route{} var requestURL string - if len(url) < 1 { + if len(endpointUrl) < 1 { testRoute = deploy.NewTlsRoute(instance, "test", "test", 8080) logrus.Infof("Creating a test route %s to extract router crt", testRoute.Name) if err := r.CreateNewRoute(instance, testRoute); err != nil { @@ -269,16 +272,61 @@ func (r *ReconcileChe) GetEndpointTlsCrt(instance *orgv1.CheCluster, url string) // sometimes timing conditions apply, and host isn't available right away if len(testRoute.Spec.Host) < 1 { time.Sleep(time.Duration(1) * time.Second) - testRoute := r.GetEffectiveRoute(instance, "test") - requestURL = "https://" + testRoute.Spec.Host + testRoute = r.GetEffectiveRoute(instance, "test") } requestURL = "https://" + testRoute.Spec.Host } else { - requestURL = url + requestURL = endpointUrl + } + + //adding the proxy settings to the Transport object + transport := &http.Transport{} + + if instance.Spec.Server.ProxyURL != "" { + logrus.Infof("Configuring proxy with %s to extract crt from the following URL: %s", instance.Spec.Server.ProxyURL, requestURL) + proxyParts := strings.Split(instance.Spec.Server.ProxyURL, "://") + proxyProtocol := "" + proxyHost := "" + if len(proxyParts) == 1 { + proxyProtocol = "" + proxyHost = proxyParts[0] + } else { + proxyProtocol = proxyParts[0] + proxyHost = proxyParts[1] + + } + + proxyURL := proxyHost + if instance.Spec.Server.ProxyPort != "" { + proxyURL = proxyURL + ":" + instance.Spec.Server.ProxyPort + } + if len(instance.Spec.Server.ProxyUser) > 1 && len(instance.Spec.Server.ProxyPassword) > 1 { + proxyURL = instance.Spec.Server.ProxyUser + ":" + instance.Spec.Server.ProxyPassword + "@" + proxyURL + } + + if proxyProtocol != "" { + proxyURL = proxyProtocol + "://" + proxyURL + } + config := httpproxy.Config{ + HTTPProxy: proxyURL, + HTTPSProxy: proxyURL, + NoProxy: strings.Replace(instance.Spec.Server.NonProxyHosts, "|", ",", -1), + } + proxyFunc := config.ProxyFunc() + transport.Proxy = func(r *http.Request) (*url.URL, error) { + theProxyUrl, err := proxyFunc(r.URL) + if err != nil { + logrus.Warnf("Error when trying to get the proxy to access TLS endpoint URL: %s - %s", r.URL, err) + } + logrus.Infof("Using proxy: %s to access TLS endpoint URL: %s", theProxyUrl, r.URL) + return theProxyUrl, err + } + } + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + client := &http.Client{ + Transport: transport, } - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - client := &http.Client{} req, err := http.NewRequest("GET", requestURL, nil) resp, err := client.Do(req) if err != nil { @@ -299,7 +347,7 @@ func (r *ReconcileChe) GetEndpointTlsCrt(instance *orgv1.CheCluster, url string) certificate = append(certificate, crt...) } - if len(url) < 1 { + if len(endpointUrl) < 1 { logrus.Infof("Deleting a test route %s to extract routes crt", testRoute.Name) if err := r.client.Delete(context.TODO(), testRoute); err != nil { logrus.Errorf("Failed to delete test route %s: %s", testRoute.Name, err) diff --git a/pkg/deploy/che_configmap.go b/pkg/deploy/che_configmap.go index 91e96061f..20f4a2080 100644 --- a/pkg/deploy/che_configmap.go +++ b/pkg/deploy/che_configmap.go @@ -123,7 +123,7 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) { cheWorkspaceHttpProxy := "" cheWorkspaceNoProxy := "" if len(cr.Spec.Server.ProxyURL) > 1 { - cheWorkspaceHttpProxy, cheWorkspaceNoProxy = util.GenerateProxyEnvs(cr.Spec.Server.ProxyURL, cr.Spec.Server.ProxyPort, cr.Spec.Server.NonProxyHosts, proxyUser, proxyPassword) + cheWorkspaceHttpProxy, cheWorkspaceNoProxy = util.GenerateProxyEnvs(cr.Spec.Server.ProxyURL, cr.Spec.Server.ProxyPort, nonProxyHosts, proxyUser, proxyPassword) } ingressDomain := cr.Spec.K8s.IngressDomain diff --git a/pkg/deploy/deployment_keycloak.go b/pkg/deploy/deployment_keycloak.go index a7b7a0486..3600bd906 100644 --- a/pkg/deploy/deployment_keycloak.go +++ b/pkg/deploy/deployment_keycloak.go @@ -12,6 +12,9 @@ package deploy import ( + "regexp" + "strings" + orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1" "github.com/eclipse/che-operator/pkg/util" appsv1 "k8s.io/api/apps/v1" @@ -59,7 +62,6 @@ func NewKeycloakDeployment(cr *orgv1.CheCluster, keycloakPostgresPassword string addCertToTrustStoreCommand := addRouterCrt + " && " + addOpenShiftAPICrt + " && " + addMountedCrt + " && " + addMountedServiceCrt + " && " + importJavaCacerts - startCommand := "sed -i 's/WILDCARD/ANY/g' /opt/eap/bin/launch/keycloak-spi.sh && /opt/eap/bin/openshift-launch.sh -b 0.0.0.0" // upstream Keycloak has a bit different mechanism of adding jks changeConfigCommand := "echo Installing certificates into Keycloak && " + "echo -e \"embed-server --server-config=standalone.xml --std-out=echo \n" + @@ -68,6 +70,50 @@ func NewKeycloakDeployment(cr *orgv1.CheCluster, keycloakPostgresPassword string "\"" + jbossDir + "/openshift.jks\", password => \"" + trustpass + "\", disabled => \"false\" },enabled=true) \n" + "stop-embedded-server\" > /scripts/add_openshift_certificate.cli && " + "/opt/jboss/keycloak/bin/jboss-cli.sh --file=/scripts/add_openshift_certificate.cli" + + addProxyCliCommand := "" + applyProxyCliCommand := "" + proxyEnvVars := []corev1.EnvVar{} + + if len(cr.Spec.Server.ProxyURL) > 1 { + cheWorkspaceHttpProxy, cheWorkspaceNoProxy := util.GenerateProxyEnvs(cr.Spec.Server.ProxyURL, cr.Spec.Server.ProxyPort, cr.Spec.Server.NonProxyHosts, cr.Spec.Server.ProxyUser, cr.Spec.Server.ProxyPassword) + + proxyEnvVars = []corev1.EnvVar{ + corev1.EnvVar{ + Name: "HTTP_PROXY", + Value: cheWorkspaceHttpProxy, + }, + corev1.EnvVar{ + Name: "HTTPS_PROXY", + Value: cheWorkspaceHttpProxy, + }, + corev1.EnvVar{ + Name: "NO_PROXY", + Value: cheWorkspaceNoProxy, + }, + } + + cheWorkspaceNoProxy = strings.ReplaceAll(regexp.QuoteMeta(cheWorkspaceNoProxy), "\\", "\\\\\\") + + jbossCli := "/opt/jboss/keycloak/bin/jboss-cli.sh" + serverConfig := "standalone.xml" + if cheFlavor == "codeready" { + jbossCli = "/opt/eap/bin/jboss-cli.sh" + serverConfig = "standalone-openshift.xml" + } + addProxyCliCommand = " && echo Configuring Proxy && " + + "echo -e 'embed-server --server-config=" + serverConfig + " --std-out=echo \n" + + "/subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=[\"" + cheWorkspaceNoProxy + ";NO_PROXY\",\".*;" + cheWorkspaceHttpProxy + "\"]) \n" + + "stop-embedded-server' > " + jbossDir + "/setup-http-proxy.cli" + + applyProxyCliCommand = " && " + jbossCli + " --file=" + jbossDir + "/setup-http-proxy.cli" + if cheFlavor == "codeready" { + applyProxyCliCommand = " && mkdir -p " + jbossDir + "/extensions && echo '#!/bin/bash\n" + + "" + jbossDir + "/bin/jboss-cli.sh --file=" + jbossDir + "/setup-http-proxy.cli' > " + jbossDir + "/extensions/postconfigure.sh && " + + "chmod a+x " + jbossDir + "/extensions/postconfigure.sh " + } + } + keycloakAdminUserName := util.GetValue(cr.Spec.Auth.IdentityProviderAdminUserName, DefaultKeycloakAdminUserName) keycloakEnv := []corev1.EnvVar{ { @@ -215,12 +261,18 @@ func NewKeycloakDeployment(cr *orgv1.CheCluster, keycloakPostgresPassword string }, } } - command := addCertToTrustStoreCommand + " && " + changeConfigCommand + " && /opt/jboss/docker-entrypoint.sh -b 0.0.0.0 -c standalone.xml" + + for _, envvar := range proxyEnvVars { + keycloakEnv = append(keycloakEnv, envvar) + } + + command := addCertToTrustStoreCommand + addProxyCliCommand + applyProxyCliCommand + " && " + changeConfigCommand + + " && /opt/jboss/docker-entrypoint.sh -b 0.0.0.0 -c standalone.xml" command += " -Dkeycloak.profile.feature.token_exchange=enabled -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled" if cheFlavor == "codeready" { - command = addCertToTrustStoreCommand + - " && echo \"feature.token_exchange=enabled\nfeature.admin_fine_grained_authz=enabled\" > /opt/eap/standalone/configuration/profile.properties && " + - startCommand + command = addCertToTrustStoreCommand + addProxyCliCommand + applyProxyCliCommand + + " && echo \"feature.token_exchange=enabled\nfeature.admin_fine_grained_authz=enabled\" > /opt/eap/standalone/configuration/profile.properties" + + " && sed -i 's/WILDCARD/ANY/g' /opt/eap/bin/launch/keycloak-spi.sh && /opt/eap/bin/openshift-launch.sh -b 0.0.0.0" } return &appsv1.Deployment{