OpenShift Container Platform typically supports edge-terminated TLS applications in a simple way for application developers through the route resource. This is accomplished through a wildcard certificate which will usually take a form like *.apps.cluster.domain.example.com
. By default when exposing a service in OpenShift, a hostname is created by combining the service name (such as console
) with a project (like openshift-console
) to create a FQDN for a host, resulting in a host name like console-openshift-console.apps.cluster.domain.example.com
. This just "works" due to the cluster wildcard certificate.
However, it is possible to manage custom certificates for use with OpenShift routes or Kubernetes ingress resources. The Cert-Manager CNCF project provides a handy tool to request custom TLS certificates for OpenShift, or any other Kubernetes platform. This gist will walk through setting up cert-manager on OpenShift, setting it up with a confguration to request free TLS certificates from Let's Encrypt and requesting a certificate. You will need an OpenShift cluster (technically even CRC could work) and the ability to resolve the DNS names for your desired TLS certificates to your OpenShift router LoadBalancer service.
Begin by installing the Cert-Manager operator on your cluster. On OpenShift 4.x as a cluster-admin user, select the Administrator perspective and open the Operators->Operator Hub menu. Search with the string cert-manager, then click on the tile that is not tagged Marketplace
Click on the Install button to bring up the operator configuration form:
It's ok to keep all default values and keep the openshift-operators
namespace as shown. Click on Install to install the operator to your cluster.
After a few minutes, the operator will be confirmed as installed. Switch over to an OpenShift CLI session or use the Web UI to apply the resources as follows:
-
Create a project for the cert-manager:
oc new-project cert-manager
-
Create a cert-manager resource in this project. Apply this yaml to the
cert-manager
project:apiVersion: operator.cert-manager.io/v1alpha1 kind: CertManager metadata: name: cert-manager namespace: cert-manager spec: {}
-
Create a
ClusterIssuer
for Let's Encrypt using the acme protocol. This cluster issuer you will specify in the certificate requests. It's best to create both astaging
andproduction
issuer so that you can experiment as desired before making a request for a full production certificate. The issuer needs your email address, and this address will get automated notifications before the certificates expire.staging issuer (update with your email address before applying):
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging labels: name: letsencrypt-staging spec: acme: # update the following with your email address email: [email protected] privateKeySecretRef: name: letsencrypt-staging server: https://acme-staging-v02.api.letsencrypt.org/directory solvers: - http01: ingress: class: nginx
production issuer (update with your email address before applying):
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod labels: name: letsencrypt-prod spec: acme: # update the following with your email address email: [email protected] privateKeySecretRef: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - http01: ingress: class: nginx
-
At this point, you can change to another project, say
myproject
, where you have an application of interest where you want to have a secret created with the private key and associated TLS certificate. Within this project, create a Certificate Resource for your desired certificate. In this hypothetical example, we will request a nested subdomain certificate off the wildcard certificate of a Red Hat OpenShift on IBM Cloud cluster. Note that the Red Hat OpenShift on IBM Cloud cluster default wildcard certificate is very long so this example also includes an additionaldnsName
andcommonName
corresponding to the standard cluster CN (which you can get from the regular wildcard certificate).For this example, the CN is:
timrovpc-roks-demo-clus.us-east.containers.appdomain.cloud
, the Wildcard domain istimrovpc-roks-demo-clus-c0b572361ba41c9eef42d4d51297b04b-0000.us-east.containers.appdomain.cloud
and the nested subdomain host will be:mywebapp.myservice-myproject
. It's a good idea to test the process by setting the cluster issuer toletsencrypt-staging
and confirmed the certificate in the secret once:apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: mywebapp-crt spec: commonName: timrovpc-roks-demo-clus.us-east.containers.appdomain.cloud dnsNames: - >- mywebapp.myservice-myproject.timrovpc-roks-demo-clus-c0b572361ba41c9eef42d4d51297b04b-0000.us-east.containers.appdomain.cloud - timrovpc-roks-demo-clus.us-east.containers.appdomain.cloud issuerRef: group: cert-manager.io kind: ClusterIssuer name: letsencrypt-prod secretName: mywebapp-tls-secret
-
If there are no typos in the request, after a few minutes, this request will show a Ready status and the named secret will contain values for the private key and certificate. You can verify the certificate from the CLI with a command like:
oc get secret mywebapp-tls-secret -o jsonpath='{ .data.tls\.crt }' | base64 -d | openssl x509 -text
The secret is ready for use with a Kubernetes ingress resource, or you can extract the private key and certificate to use in other ways for example with the route command.