Adapting Containers to Run on Red Hat OpenShift

This short article will demonstrate how to use the cert-manager operator to shift a self-signed CA into the Red Hat OpenShift cluster, allowing the operator take care of the overhead of requesting and signing your certificates for you so you can use the same CA no matter how many times you reinstall your cluster.

If you have a workflow much like mine, you may find yourself reinstalling your OpenShift cluster often in order to test new configurations, swap between different versions, and sometimes just to test that a series of steps you are documenting truly work on a pristine cluster. When doing so, it is a good idea to replace the cluster's Ingress TLS certificates with one from a known CA, even if that known CA is your own self-signed certificate. It sure beats wasting time with your browser agreeing that yet another new TLS certificate from an "unknown certificate authority" is actually okay, a process that typically happens twice if you use the UI, one to reach the login screen, and one to authenticate via the oauth system.

You could follow the instructions in the documentation, Replacing the default ingress certificate, generate your CA, create a CSR for the appropriate wildcard domain, and sign it. You may even choose to automate the process after going through the manual version once to understand the workflow. But with a little more effort, you can future safe your certificate signing process to handle any TLS needs you might run into in the future.

Introducing cert-manager

The cert-manager operator for OpenShift handles the lifecycle management portion of your TLS certificates, whether for the cluster's ingress operator (as I will describe here) or for the various encryption needs of your containerized applications. Documentation for the cert-manager operator can be found alongside the certificates page previously mentioned. The cert-manager operator has capabilities far beyond simple self-signed TLS certificates, allowing integration with external certificate authorities like [Let's Encrypt](https://letsencrypt.org/) and others. So taking the time to learn it from this basic example could pay off in the future.

In my case, I will stick with the self-signed CA because I use a private domain, example.com, for illustration purposes in my blogs, and external CAs cannot sign requests for private domains.

Getting started

The first step is to generate a self-signed certificate for use as your CA. One of the easiest ways to create a CA is to use the CFSSL utility from Cloudflare. You can download binaries from the Git repository's Releases page, or build your own from source. Once you have the binary, create a JSON file like the following to configure some basic information for your CA:

{
  "CN": "Kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Westford",
      "O": "Example",
      "OU": "CA",
      "ST": "Massachusetts"
    }
  ]
}

Save that as "ca.json" and run it through cfssl with the following:

cfssl gencert -initca ca.json | cfssljson -bare ca

You should now have a ca.pem and ca-key.pem. This is your own certificate authority and its secret key. You will need to add this CA to several places to make things go smoothly.

If Firefox is your browser of choice like mine, these instructions work well. Other browser guides are easy to find with a web search.

Next, is your cluster's CA bundle. This is relatively easy if this is the only CA you are adding. Create a ConfigMap from the ca.pem file generated above:

oc create configmap custom-ca \
    --from-file=ca-bundle.crt=ca.pem \
    -n openshift-config

Patch the new ConfigMap in the cluster config:

oc patch proxy/cluster \
    --type=merge \
    --patch='{"spec":{"trustedCA":{"name":"custom-ca"}}}'

Third, we need to hand the CA and its secret key over to cert-manager, but I've gotten ahead of myself. Let's install cert-manager first.

Installing cert-manager

Following the instructions in the OpenShift Documentation, install the official cert-manager operator for Red Hat OpenShift from the OperatorHub. Once installed, it will create two namespaces, cert-manager-operator for the operator itself, and more importantly, cert-manager for its configuration. Now we can add our CA to cert-manager:

oc -n cert-manager \
    create secret tls ca-root-secret \
    --cert=ca.pem --key=ca-key.pem

Once that Secret is created, we can create a ClusterIssuer that tells cert-manager how to sign certificates with your CA:

oc create -f - <<END
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ca-issuer
spec:
  ca:
    secretName: ca-root-secret
status: {}
END

The final step is to create a Certificate, a custom resource added by cert-manager:

oc create -f - <<END
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ingress-cert
  namespace: openshift-ingress
spec:
  commonName: kubernetes
  dnsNames:
  - '*.apps.your-cluster.example.com'
  isCA: false
  issuerRef:
    group: cert-manager.io
    kind: ClusterIssuer
    name: ca-issuer
  privateKey:
    algorithm: ECDSA
    size: 256
  secretName: custom-certs-managed
status: {}
END

The previous certificate object will tell cert-manager to create a secret called custom-certs-managed under the openshift-ingress namespace. To apply the certificate to the cluster's ingress, thus any *.apps address in the cluster, patch the default IngressController:

oc --namespace openshift-ingress-operator \
  patch --type=merge ingresscontrollers/default \
  --patch '{"spec":{"defaultCertificate":{"name":"custom-certs-managed"}}}'

At this point, the routers will deploy the new certificate, and once that process is finished, your cluster will be using certificates signed by your own CA, which your browser should already trust.

Last updated: October 31, 2023