Correctly propagate proxy settings in the operator and Keycloak (CRW-709) (#200)

* Correctly propagate proxy settings in the operator and Keycloak .This fixes issue https://issues.redhat.com/browse/CRW-709

* Use the same Go release in PR checks as in the main Docker file to avoid a syntax arror in the PR check jobs

Signed-off-by: David Festal <dfestal@redhat.com>
pull/217/head
David Festal 2020-03-18 12:03:04 +01:00 committed by GitHub
parent 605a6fd1e4
commit 48e367d163
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 22 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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{