Get crt of OpenShift baseURL for Keycloak (#14)

* Get crt of OpenShift baseURL for Keycloak

* Don't fails when rolling out router deployment
pull/16/head
Eugene Ivantsov 2019-04-19 14:40:49 +03:00 committed by GitHub
parent 560b21a838
commit 63787372bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 100 additions and 37 deletions

View File

@ -54,8 +54,8 @@ echo "[INFO] Update OpenShift router tls secret"
./oc project default
./oc secrets new router-certs tls.crt=ca.crt tls.key=key.pem -o json --type='kubernetes.io/tls' --confirm | ./oc replace -f -
echo "[INFO] Initiate a new router deployment"
sleep 10
./oc rollout latest dc/router -n=default
sleep 20
./oc rollout latest dc/router -n=default || true
echo "[INFO] Compile tests binary"
docker run -t \

View File

@ -215,25 +215,25 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
return reconcile.Result{}, err
}
}
// create a secret with router tls cert when on OpenShift infra and router is configured with a self signed certificate
selfSignedCert := instance.Spec.Server.SelfSignedCert
if isOpenShift && selfSignedCert {
secret := &corev1.Secret{}
if err := r.client.Get(context.TODO(), types.NamespacedName{Name: "self-signed-certificate", Namespace: instance.Namespace}, secret);
err != nil && errors.IsNotFound(err) {
crt, err := r.GetRouterTlsCrt(instance)
if err != nil {
logrus.Errorf("Default router tls secret not found. Self signed cert isn't added")
if err := r.CreateTLSSecret(instance, "", "self-signed-certificate"); err != nil {
return reconcile.Result{}, err
}
}
// create a secret with OpenShift API crt to be added to keystore that RH SSO will consume
if isOpenShift {
baseURL, err := util.GetClusterPublicHostname()
if err != nil {
logrus.Errorf("Failed to get OpenShift cluster public hostname. A secret with API crt will not be created and consumed by RH-SSO/Keycloak")
} else {
if err := r.CreateTLSSecret(instance, baseURL, "openshift-api-crt"); err != nil {
return reconcile.Result{}, err
} else {
secret := deploy.NewSecret(instance, "self-signed-certificate", crt)
if err := r.CreateNewSecret(instance, secret); err != nil {
return reconcile.Result{}, err
}
}
}
}
if !tests {
deployment := &appsv1.Deployment{}
name := "che"

View File

@ -318,6 +318,28 @@ func (r *ReconcileChe) CreateIdentityProviderItems(instance *orgv1.CheCluster, r
return nil
}
func (r *ReconcileChe) CreateTLSSecret(instance *orgv1.CheCluster, url string, name string) (err error) {
// create a secret with either router tls cert (or OpenShift API crt) when on OpenShift infra
// and router is configured with a self signed certificate
// this secret is used by CRW server to reach RH SSO TLS endpoint
secret := &corev1.Secret{}
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)
return err
} else {
secret := deploy.NewSecret(instance, name, crt)
if err := r.CreateNewSecret(instance, secret); err != nil {
return err
}
}
}
return nil
}
func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request reconcile.Request) (err error) {
chePostgresPassword := util.GetValue(instance.Spec.Database.ChePostgresPassword, util.GeneratePasswd(12))
@ -445,7 +467,6 @@ func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request
if len(instance.Spec.Auth.KeycloakClientId) < 1 {
instance.Spec.Auth.KeycloakClientId = keycloakClientId
if err := r.UpdateCheCRSpec(instance, "Keycloak client ID", keycloakClientId); err != nil {
return err
}

View File

@ -19,6 +19,7 @@ import (
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"
appsv1 "k8s.io/api/apps/v1"
@ -251,17 +252,21 @@ func (cl *k8s) GetDeploymentPod(name string, ns string) (podName string, err err
return podName, nil
}
// GetRouterTlsCrt creates a test TLS route and gets it to extract certificate chain
// 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) GetRouterTlsCrt(instance *orgv1.CheCluster) (certificate []byte, err error) {
testRoute := deploy.NewTlsRoute(instance, "test", "test")
logrus.Infof("Creating a test route %s to extract routes crt", testRoute.Name)
if err := r.CreateNewRoute(instance, testRoute); err != nil {
logrus.Errorf("Failed to create test route %s: %s", testRoute.Name, err)
return nil, err
func (r *ReconcileChe) GetEndpointTlsCrt(instance *orgv1.CheCluster, url string) (certificate []byte, err error) {
testRoute := &routev1.Route{}
if len(url) < 1 {
testRoute = deploy.NewTlsRoute(instance, "test", "test")
logrus.Infof("Creating a test route %s to extract routes crt", testRoute.Name)
if err := r.CreateNewRoute(instance, testRoute); err != nil {
logrus.Errorf("Failed to create test route %s: %s", testRoute.Name, err)
return nil, err
}
url = "https://" + testRoute.Spec.Host
}
url := "https://" + testRoute.Spec.Host
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
@ -283,10 +288,12 @@ func (r *ReconcileChe) GetRouterTlsCrt(instance *orgv1.CheCluster) (certificate
})
certificate = append(certificate, crt...)
}
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)
}
if len(url) < 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)
}
}
return certificate, nil
}

View File

@ -32,17 +32,28 @@ func NewKeycloakDeployment(cr *orgv1.CheCluster, keycloakPostgresPassword string
// writable dir in the upstream Keycloak image
jbossDir = "/scripts"
}
// add crt to Java trust store so that Keycloak can connect to k8s API
addCertToTrustStoreCommand := "if [ ! -z \"${CHE_SELF__SIGNED__CERT}\" ]; then echo \"${CHE_SELF__SIGNED__CERT}\" > " + jbossDir + "/openshift.crt && " +
"keytool -importcert -alias HOSTDOMAIN0" +
" -keystore " + jbossDir +"/openshift.jks" +
" -file " + jbossDir + "/openshift.crt -storepass " + trustpass + " -noprompt; fi" +
" && keytool -importcert -alias HOSTDOMAIN" +
" -keystore " + jbossDir +"/openshift.jks" +
" -file /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -storepass " + trustpass + " -noprompt" +
" && keytool -importkeystore -srckeystore $JAVA_HOME/jre/lib/security/cacerts" +
// add various certificates to Java trust store so that Keycloak can connect to OpenShift API
// certificate that OpenShift router uses (for 4.0 only)
addRouterCrt := "if [ ! -z \"${CHE_SELF__SIGNED__CERT}\" ]; then echo \"${CHE_SELF__SIGNED__CERT}\" > " + jbossDir + "/openshift.crt && " +
"keytool -importcert -alias ROUTERCRT" +
" -keystore " + jbossDir + "/openshift.jks" +
" -file " + jbossDir + "/openshift.crt -storepass " + trustpass + " -noprompt; fi"
// certificate retrieved from http call to OpenShift API endpoint
addOpenShiftAPICrt := "if [ ! -z \"${OPENSHIFT_SELF__SIGNED__CERT}\" ]; then echo \"${OPENSHIFT_SELF__SIGNED__CERT}\" > " + jbossDir + "/openshift.crt && " +
"keytool -importcert -alias OPENSHIFTAPI" +
" -keystore " + jbossDir + "/openshift.jks" +
" -file " + jbossDir + "/openshift.crt -storepass " + trustpass + " -noprompt; fi"
// certificate mounted into container /var/run/secrets
addMountedCrt := " keytool -importcert -alias MOUNTEDCRT" +
" -keystore " + jbossDir + "/openshift.jks" +
" -file /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -storepass " + trustpass + " -noprompt"
importJavaCacerts := "keytool -importkeystore -srckeystore $JAVA_HOME/jre/lib/security/cacerts" +
" -destkeystore " + jbossDir + "/openshift.jks" +
" -srcstorepass changeit -deststorepass " + trustpass
addCertToTrustStoreCommand := addRouterCrt + " && " + addOpenShiftAPICrt + " && " + addMountedCrt + " && " + 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 -e \"embed-server --server-config=standalone.xml --std-out=echo \n" +
@ -101,6 +112,18 @@ func NewKeycloakDeployment(cr *orgv1.CheCluster, keycloakPostgresPassword string
},
},
},
{
Name: "OPENSHIFT_SELF__SIGNED__CERT",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "ca.crt",
LocalObjectReference: corev1.LocalObjectReference{
Name: "openshift-api-crt",
},
Optional: &optionalEnv,
},
},
},
}
if cheFlavor == "codeready" {
keycloakEnv = []corev1.EnvVar{
@ -168,6 +191,18 @@ func NewKeycloakDeployment(cr *orgv1.CheCluster, keycloakPostgresPassword string
},
},
},
{
Name: "OPENSHIFT_SELF__SIGNED__CERT",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "ca.crt",
LocalObjectReference: corev1.LocalObjectReference{
Name: "openshift-api-crt",
},
Optional: &optionalEnv,
},
},
},
}
}
command := addCertToTrustStoreCommand + " && " + changeConfigCommand + " && /opt/jboss/docker-entrypoint.sh -b 0.0.0.0"

View File

@ -110,7 +110,7 @@ func GetClusterPublicHostname() (hostname string, err error) {
client := &http.Client{}
kubeApi := os.Getenv("KUBERNETES_PORT_443_TCP_ADDR")
url := "https://" + kubeApi + "/.well-known/oauth-authorization-server"
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
resp, err := client.Do(req)
if err != nil {
logrus.Errorf("An error occurred when getting API public hostname: %s", err)