The OpenShift Container Platform provides multiple options to provide access to external clients. The route is one of the methods to provide the access to external clients. We can enable TLS termination on route to encrpt the data sent over to the external clients. We need to update the valid certificate and private key in the route manifest to achieve this. Kindly refer to the last article to know how to enable TLS termination. In the DevOps practice, all the kubernetes/openshift manifests will be stored in the git repository. Storing the TLS certificate and key in the git is not a good practice.
Can the Openshift route have secrets in it? Is it possible to use the secrets in the route definition? No. OCP Routes cannot use secrets. It expects certs/keys in their route definition only. In order to enable a router to consume TLS credentials from OCP Secret, it requires access to all Secret which is considered a security risk as per the RedHat support article.
This article will provide the workaround to eliminate certificates and keys to be stored in the git repository using the operator – Cert-utils-operator
Installing Cert Util Operator
1. Install the cert util operator using the helm chart.
$ oc new-project cert-utils-operator $ helm repo add cert-utils-operator https://redhat-cop.github.io/cert-utils-operator $ helm repo update $ helm install cert-utils-operator cert-utils-operator/cert-utils-operato
2. Check the operator status
[lingesh@okd4 ~]$ oc get all NAME READY STATUS RESTARTS AGE pod/cert-utils-operator-controller-manager-59f9f8bc5f-5jp7h 2/2 Running 60 (15m ago) 23d NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/cert-utils-operator-controller-manager-metrics-service ClusterIP 10.217.4.84 <none> 8443/TCP 23d NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/cert-utils-operator-controller-manager 1/1 1 1 23d NAME DESIRED CURRENT READY AGE replicaset.apps/cert-utils-operator-controller-manager-59f9f8bc5f 1 1 1 23d [lingesh@okd4 ~]$
Create a secret for TLS cert & key:
1. Let’s store the TLS certificate and key on the OCP secret. If you are wondering how to create the self-signed certificate, kindly check the previous article.
[lingesh@okd4 certs]$ oc create secret tls nginx.crt --key=MyKey.key --cert=MyCertificate.crt secret/nginx.crt created [lingesh@okd4 certs]$
2. List the newly created secret.
[lingesh@okd4 certs]$ oc get secret nginx.crt NAME TYPE DATA AGE nginx.crt kubernetes.io/tls 2 115s [lingesh@okd4 certs]$
Expose the deployment using a route with TLS
1. If you are following my previous article, you can see that I have exposed the service using HTTP & HTTPS by directly updating the key and certificate in the route manifest.
2. We will create a similar manifest without updating the TLS cert & key in the route manifest. Instead, we will update the “cert util operator” annotate.
3. Here is my test nginx deployment and removed the route to use the operator.
[lingesh@okd4 certs]$ oc get all NAME READY STATUS RESTARTS AGE pod/ua-nginx-7bd5c655bb-z8nvk 1/1 Running 3 23d NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ua-nginx ClusterIP 10.217.5.76 <none> 80/TCP 23d NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ua-nginx 1/1 1 1 23d NAME DESIRED CURRENT READY AGE replicaset.apps/ua-nginx-7bd5c655bb 1 1 1 23d [lingesh@okd4 certs]$
4. Create the route manifest to expose the service outside with TLS enabled. Let’s assume that if you are storing this file on the git repository, there is no harm since we are not hardcoding any certificate or keys in the route manifest. That’s the whole purpose of the operator.
We have just added annotations by referring to the TLS secret name “nginx.crt“. Left the “tls.crt” & “tls.key” values empty.
apiVersion: route.openshift.io/v1 kind: Route metadata: annotations: cert-utils-operator.redhat-cop.io/certs-from-secret: nginx.crt labels: name: ua-nginx namespace: ua-nginx spec: host: ua-nginx-ua-nginx.apps-crc.testing port: targetPort: http tls: tls.crt: "" tls.key: "" termination: edge to: kind: Service name: ua-nginx weight: 100 wildcardPolicy: None
5. Create a route using the above manifest.
[lingesh@okd4 ~]$ oc create -f route.nginx.yaml route.route.openshift.io/ua-nginx created [lingesh@okd4 ~]$ oc get route NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD ua-nginx ua-nginx-ua-nginx.apps-crc.testing ua-nginx http edge None [lingesh@okd4 ~]$
6. Let’s verify the route resource.
[lingesh@okd4 ~]$ oc get route NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD ua-nginx ua-nginx-ua-nginx.apps-crc.testing ua-nginx http edge None [lingesh@okd4 ~]$
[lingesh@okd4 ~]$ oc get route ua-nginx -o yaml apiVersion: route.openshift.io/v1 kind: Route metadata: annotations: cert-utils-operator.redhat-cop.io/certs-from-secret: nginx.crt creationTimestamp: "2022-12-02T18:09:30Z" name: ua-nginx namespace: ua-nginx resourceVersion: "417278" uid: fa9da0f8-ee74-44db-bf44-c0d96a8b87a0 spec: host: ua-nginx-ua-nginx.apps-crc.testing port: targetPort: http tls: certificate: | -----BEGIN CERTIFICATE----- MIIFfzCCA2egAwIBAgIUdKIf+BEhAAZwHJ2hxKXOGCxExQowDQYJKoZIhvcNAQEL BQAwTzELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAktBMQswCQYDVQQHDAJFQzELMAkG A1UECgwCVUExGTAXBgNVBAMMEGFwcHMtY3JjLnRlc3RpbmcwHhcNMjIxMTAyMTY0 OTA4WhcNMjMxMTAyMTY0OTA4WjBPMQswCQYDVQQGEwJJTjELMAkGA1UECAwCS0Ex CzAJBgNVBAcMAkVDMQswCQYDVQQKDAJVQTEZMBcGA1UEAwwQYXBwcy1jcmMudGVz dGluZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/zww/58w6c/UGH
Here we can see that certificate has been automatically populated by the operator in the route manifest. You could verify the certificate in the browser by clicking the HTTPS section.
Conclusion:
In most cases, we might end up storing the certificate and key on git repositories. In some cases, we might have packaged it in helm and stored it in the artifactory. Cert-Util-Operator just populates the TLS certificate and key from secrets to remove the route limitation in OCP (Openshift container platform) and improves security by not storing in git repos and artifactory.
Joo says
I created the secret with tls.crt and tls.key, but Route’s Certificates and key are not imported from the secret.
They would just disappear when I submit/save them as blank string.
Perhaps I have to define them other than empty string (“”) ?
Christopher says
This manifest is not valid. How did you create Route object not fitting to the namespace?
Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: error validating “”: error validating data: [ValidationError(Route.spec.tls): unknown field “tls.crt” in com.github.openshift.api.route.v1.TLSConfig, ValidationError(Route.spec.tls): unknown field “tls.key” in com.github.openshift.api.route.v1.TLSConfig]
Cloud_Devops says
Have you created a secret already? Not sure why its failing in your case.