Replace OpenShift Self-Signed Ingress and API SSL/TLS Certificates with Lets Encrypt

|
Published:
|
|

In this tutorial, you will learn how to replace OpenShift self-signed Ingress and API SSL/TLS certificates with Lets Encrypt. When you install a new Red Hat OpenShift cluster, it comes with default self-signed certificates for both the API server and Ingress routes. While these are fine for internal testing, browsers and automation clients will warn that the connection is insecure. In production, you’ll want publicly trusted SSL/TLS certificates and the easiest way to automate that is by using Let’s Encrypt.

In this comprehensive guide, we’ll walk through replacing OpenShift’s default self-signed certificates with trusted Let’s Encrypt certificates using cert-manager Operator for automated certificate management. Since our domain is hosted on Cloudflare, we’ll leverage Cloudflare’s DNS API for certificate validation.

Replace OpenShift Self-Signed Ingress and API SSL/TLS Certificates with Lets Encrypt

OpenShift Container Platform provides a robust environment for deploying and managing applications. However, out-of-the-box installations often come configured with self-signed SSL certificates for critical components like the Ingress and API servers. While these certificates enable basic encrypted communication, they are not trusted by external clients and browsers, leading to security warnings and a less-than-ideal user experience.

Understanding OpenShift’s Default SSL/TLS Certificates

In a freshly installed OpenShift cluster, default SSL/TLS certificates are automatically provisioned to secure communication between various cluster components and external clients. These certificates are self-signed, generated by the cluster’s internal certificate authority (CA), and are suitable for development or testing environments. However, for production environments, replacing these with certificates from a trusted CA is recommended to ensure trust and compliance.

Key OpenShift Components Using Default SSL/TLS Certificates:

  • API Server
    • The API server uses two main endpoints to manage control plane communication.
    • External API Server endpoint (api.<cluster-domain>:6443):
      • This endpoint serves as the primary control plane access point for external clients, including administrators using the oc CLI, automation tools, and the web console backend.
      • It is fronted by a load balancer and, by default, uses a certificate signed by the internal OpenShift CA. Because this certificate is not trusted by browsers or public systems, it should be replaced with one issued by a trusted CA in production environments to eliminate SSL warnings and ensure secure external access.
    • Internal API Server endpoint (api-int.<cluster-domain>:6443)
      • This internal endpoint is used exclusively by cluster components such as kubelets, the controller manager, scheduler, and cluster operators.
      • It also uses a certificate signed by the internal CA, which is automatically managed and rotated by OpenShift. Since it is not exposed outside the cluster, it normally remains unchanged.
  • Ingress Controller (Router Certificates)
    • Endpoint Pattern: *.apps.<cluster-domain>
    • The Ingress Controller manages all external HTTPS traffic for applications exposed through Routes.
    • During installation, OpenShift automatically generates a self-signed wildcard certificate to secure all applications under the apps.<cluster-domain> subdomain.
  • Web Console
    • Endpoint: console-openshift-console.apps.<cluster-domain>
    • The web console provides a graphical interface for managing cluster resources.
    • Since it is served via the ingress router, it inherits the ingress controller’s certificate.
  • Internal Component Certificates
    • OpenShift also issues and manages certificates for internal communication between control-plane and worker components. Examples include:
      • etcd peer communication
      • kubelet to API server connections
      • Control plane component communication (e.g., controller-manager to scheduler)
    • Since these certificates are used exclusively for internal communication and are not exposed externally, they are typically signed by the internal cluster CA and do not require manual replacement under normal circumstances.

Prerequisites

Before getting started, you must have the following:

  • OpenShift Container Platform 4.X (self-managed, we are using OCP 4.19 in our environment)
  • Cluster admin access (oc CLI authenticated and working)
  • A registered domain (e.g., kifarunix.com)
  • The cluster must be publicly accessible on required ports (80/443) if using HTTP or TLS-ALPN challenges for Let’s Encrypt validation. Alternatively, if the cluster is running behind a firewall, NAT, or is not publicly reachable, you can use the DNS-01 challenge, which only requires control over your main domain’s DNS (no public exposure required).

Domain and DNS Considerations

Let’s Encrypt uses the ACME (Automatic Certificate Management Environment) protocol to verify that you control the domain for which you’re requesting a certificate. Validation is done through one of the three challenge types:

1. HTTP-01 Challenge

  • With HTTP-01 challenge, Let’s Encrypt requests a specific HTTP resource under http://<your-domain>/.well-known/acme-challenge/<token>. Your ACME client (like Certbot or cert-manager) responds by creating that file on your web server.
  • It is commonly used for web servers or in environments where the server is publicly accessible over HTTP (port 80).
  • HTTP-01 challenge does not support wildcard certificates.

2. DNS-01 Challenge

  • With DNS-01 challenge, Let’s Encrypt verifies domain control by checking for a specific TXT record in your domain’s DNS under _acme-challenge.<your-domain>.
  • Commonly used when your cluster or service is not directly exposed over HTTP[S], such as in private or hybrid environments.
  • DNS-01 challenge does support wildcard certificates generation.
  • Requires DNS API access or manual record updates.

3. TLS-ALPN-01 Challenge

  • Let’s Encrypt connects to your server over port 443 (HTTPS) and expects a special ACME ALPN (Application-Layer Protocol Negotiation) certificate.
  • Used when port 80 is blocked but HTTPS (443) is available.
  • Suitable for environments where you can control TLS handshakes directly.
  • Not supported by all ACME clients or load balancers; requires low-level TLS access.

We will use DNS-01 challenge in our case since our cluster is not directly accessible from the public Internet.

Step by Step: Replacing the Default Ingress/API TLS Certificates on OpenShift

Step 1: Create a Cloudflare API Token

As already mentioned, our domain is hosted on Cloudflare, so we will leverage a Cloudflare API token to allow automated DNS management. This is particularly useful when using cert-manager to issue certificates via the DNS-01 challenge.

If your domain is hosted on a different DNS provider (such as AWS Route 53, Google Domains, or GoDaddy), you will need to follow that provider’s instructions and configure the corresponding solver supported by cert-manager.

To Create the Cloudflare API Token:

  • Log in to your Cloudflare Dashboard.
  • If you manage multiple domains, select the relevant domain.
  • In the top-right corner, click on your avatar (profile icon) and click Profile.
  • Under “My Profile” page, click the API Tokens menu option.
  • On the User API Tokens, click Create Token.
  • Select the “Edit zone DNS” template.
  • Optional: Click the pencil icon next to Token name: Edit zone DNS to rename the token to something meaningful (e.g. cert-manager-dns-token).
  • Under Permissions, ensure the following is set:
    • Zone > DNS > Edit
  • Under Zone Resources, configure the following:
    • Include > Specific zone > select your domain (e.g., kifarunix.com)
  • Configure optional security settings:
    • Client IP Address Filtering: Add one or more IP addresses or IP ranges if you want to restrict the token to be used only from specific IPs.
      This is useful if cert-manager or your automation runs from a known, fixed IP.
      If you leave this empty, the token will be usable from any IP (default and acceptable for most setups).
    • Token TTL (Start/End Dates)
      You can set a start date, end date to control how long the token remains active.
      If you leave these unset, the token will remain valid indefinitely until manually revoked.
  • Click Continue to summary, then Create Token.
    Replace OpenShift Self-Signed Ingress and API SSL/TLS Certificates with Lets Encrypt
  • Copy and store the token securely. You will not be able to view it again after this step!

You can run the provided curl command to test your token as suggested.

Step 2: Install cert-manager Operator

In OpenShift, the quickest and easiest way to install the cert-manager operator is through the Operator Hub in the Web Console. Hence:

  • Log in to the OpenShift Web Console as a cluster admin.
  • Navigate to Operators > OperatorHub.
  • In the search box, type cert-manager.
  • From the search results, select cert-manager Operator for Red Hat OpenShift.
    Replace OpenShift Self-Signed Ingress and API SSL/TLS Certificates with Lets Encrypt
  • On the operator details page, choose the version you want to install from the Version dropdown.
  • Proceed with the installation steps:
    • Set the Update channel if needed (default: stable-v1).
    • Select AllNamespaces installation mode (recommended).
    • Choose the Installed Namespace (default: cert-manager-operator). This namespace will be created automatically if it doesn’t exist.
    • Choose the Update approval strategy: Automatic (recommended) or Manual.
  • Click Install.

Verify cert-manager Operator Installation

After installing the cert-manager Operator, wait a few minutes for it to become ready.

You can verify the installation either through the OpenShift Web Console or via CLI:

Via Web Console:

  • Go to Operators > Installed Operators.
  • Select the cert-manager-operator namespace/Project.
  • Confirm the cert-manager Operator shows a status of Succeeded.
    openshift cert manager operator install status

On CLI:

  • Watch cert-manager pods until they are running (may take 2-3 minutes)
    oc get pods -n cert-manager -w
  • You should see these pods with READY 1/1 state running:
    NAME                                       READY   STATUS    RESTARTS   AGE
    cert-manager-7cfb4fbb84-lbxll 1/1 Running 0 5m12s
    cert-manager-cainjector-854f669657-vkmvn 1/1 Running 0 5m17s
    cert-manager-webhook-68fd6d5f5c-57j8g 1/1 Running 0 5m16s
  • Check the ClusterServiceVersion (CSV) status of the operator
    oc get csv -n cert-manager
  • Sample output:
    NAME                            DISPLAY                                       VERSION   REPLACES                        PHASE
    cert-manager-operator.v1.17.0   cert-manager Operator for Red Hat OpenShift   1.17.0    cert-manager-operator.v1.16.1   Succeeded

Step 3: Configuring cert-manager for Split DNS Environments

If your OpenShift environment uses a split-horizon DNS setup (commonly called Split DNS), where internal DNS servers are authoritative for internal domains (e.g., *.apps.ocp.internal.domain), cert-manager may fail DNS-01 challenge validations. This is because internal resolvers typically won’t forward requests they can’t resolve, causing Let’s Encrypt’s validation checks to fail.

To solve this, cert-manager must use public recursive DNS servers (like Cloudflare or Google) for validating DNS challenges, instead of relying on the cluster’s default internal DNS.

If you’re not using Split DNS, you can skip this section and proceed to creating the ClusterIssuer.

Thus, to configure cert-manager to use external DNS, edit the cert-manager cluster resource:

oc edit certmanager cluster

Under the spec section, add the following controllerConfig overrides:

spec:
...
  controllerConfig:
    overrideArgs:
      - '--dns01-recursive-nameservers=8.8.8.8:53,1.1.1.1:53'
      - '--dns01-recursive-nameservers-only'

This forces cert-manager to use the specified external nameservers for all DNS-01 challenge validations.

Save and exit to make the changes.

After making any changes related to cert-manager, confirm that cert-manager is healthy and functioning:

Check pod status (most common)

oc get pods -n cert-manager
  • Ensure cert-manager pods STATUS is Running
  • The READY column should be 1/1 for the each pod.

Expected pods:

  • cert-manager-xxxxx
  • cert-manager-cainjector-xxxxx
  • cert-manager-webhook-xxxxx

For a detailed inspection of a pod, you can check the logs:

oc logs -n cert-manager <pod-name>

Or describe the pod for event-level issues:

oc describe pod -n cert-manager <pod-name>

Check Cluster Operator status (if needed)

If cert-manager was installed as a Red Hat Operator:

oc describe certmanager cluster

Step 4: Store Cloudflare API Token in OpenShift Secret

To allow cert-manager to authenticate with Cloudflare, you need to store your API token as a Kubernetes secret. This secret must be created in the cert-manager namespace (automatically created during operator installation):

oc create secret generic cloudflare-api-token-secret \
  --from-literal=api-token=<YOUR_CLOUDFLARE_API_TOKEN> \
  -n cert-manager

Replace <YOUR_CLOUDFLARE_API_TOKEN> with the actual token value you copied from Cloudflare.

Tip:
This secret will be referenced later by your ClusterIssuer or Issuer resource to allow cert-manager to perform DNS challenges via Cloudflare.

Step 5: Create Let’s Encrypt ClusterIssuers

To request TLS certificates from Let’s Encrypt or any other CA, cert-manager relies on custom resources called Issuer and ClusterIssuer. You can think of them as a configuration that tells cert-manager how to request certificates. It defines:

  • Which Certificate Authority (CA) to use (e.g., Let’s Encrypt)
  • What authentication or API credentials to use
  • What method (challenge type) to use to prove domain ownership

Issuer is a namespaced resource and can only be used to request certificates inside the same namespace it’s created in while ClusterIssuer is cluster-scoped; can be used to request certificates across all namespaces in the cluster.

In this guide, we will use ClusterIssuer for flexibility across the entire cluster.

The cert-manager Operator supports the different types of issuers including:

  • Self-signed: Generates self-signed certificates.
  • CA: Uses a local Certificate Authority to issue certs.
  • ACME: Integrates with ACME-based CAs like Let’s Encrypt.
  • Vault: Uses HashiCorp Vault to sign certificates.
  • Venafi: Integrates with Venafi Cloud or TPP.

This guide uses the ACME issuer type, which supports automated certificate management with Let’s Encrypt.

We’ll create two ClusterIssuer resources: one for Let’s Encrypt staging and one for production.

  • Staging ClusterIssuer: Uses Let’s Encrypt’s staging server to issue test certificates that don’t count against rate limits. This is essential for validating your certificate issuance without risking production limits.
  • Production ClusterIssuer: Uses Let’s Encrypt’s production server to issue real, trusted certificates for your OpenShift cluster. These are valid for public use and trusted by browsers and clients. Unlike the staging environment, the production server enforces strict rate limits such as 50 certificates per week per domain and a maximum of 5 duplicate certificates so it’s important to only use this after verifying your configuration works correctly with the staging issuer.

Create Staging ClusterIssuer manifest:

vim staging-clusterissuer.yaml

Paste the content below, making the necessary updates to fit your environment.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    # Let's Encrypt staging server (for testing)
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    
    # Your email for certificate expiration notifications
    email: [email protected]
    
    # Secret to store ACME account private key
    privateKeySecretRef:
      name: letsencrypt-staging-account-key
    
    # DNS-01 challenge using Cloudflare
    solvers:
    - dns01:
        cloudflare:
          apiTokenSecretRef:
            name: cloudflare-api-token-secret  # Name of the Kubernetes secret created above
            key: api-token  # This must match the key inside the secret (i.e., --from-literal=api-token)

For more information on the parameters used in the manifest above, refer to the oc explain clusterissuer or even further, oc explain clusterissuer.spec.

Then create the staging clusterissuer by applying the manifest:

oc apply -f staging-clusterissuer.yaml

Similarly, create the Let’s Encrypt production ClusterIssuer:

vim prod-clusterissuer.yaml

Paste the content below, making the necessary updates to fit your environment.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # Let's Encrypt production server
    server: https://acme-v02.api.letsencrypt.org/directory
    
    # Your email for certificate expiration notifications
    email: [email protected]
    
    # Secret to store ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    
    # DNS-01 challenge using Cloudflare
    solvers:
    - dns01:
        cloudflare:
          apiTokenSecretRef:
            name: cloudflare-api-token-secret  # Name of the Kubernetes secret created above
            key: api-token  # This must match the key inside the secret (i.e., --from-literal=api-token)

Then create the production clusterissuer by applying the manifest:

oc apply -f prod-clusterissuer.yaml

Verify ClusterIssuers. Their status conditions should be Ready: True.

oc get clusterissuer
NAME                  READY   AGE
letsencrypt-prod      True    26s
letsencrypt-staging   True    5m4s

Check detailed status:

oc describe clusterissuer <issuer-name>

Ensure the status condition is True/Ready:

...
Status:
...
  Conditions:
...
    Status: True      # MUST be True
    Type: Ready     # MUST be Ready

Step 6: Generate the Wildcard Ingress Certificate

Now that you have the ClusterIssuer resources configured, the next step is to create a cert-manager Certificate resource to issue a wildcard certificate for *.apps.<cluster-domain>. This certificate will be used by the OpenShift ingress controller in the openshift-ingress namespace to secure ingress routes.

Tip:
It’s recommended to start with the Let’s Encrypt staging ClusterIssuer to verify that your configuration and DNS-01 challenge setup are working correctly. Once certificate issuance succeeds in staging, you can safely switch to the production issuer.

Create a manifest file for your certificate:

vim ingress-cert-staging.yaml

Paste the content below, making the necessary updates to fit your environment.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ingress-ocp-kifarunix-com-cert-staging
  namespace: openshift-ingress
spec:
  # Secret where cert-manager will store the certificate
  secretName: ingress-ocp-kifarunix-com-tls-staging
  # Certificate subject
  subject:
    organizations:
    - Kifarunix Inc.
  # Common name for the certificate  
  commonName: '*.apps.ocp.kifarunix.com'
  # DNS subject alternative names covered by this certificate
  dnsNames:
  - '*.apps.ocp.kifarunix.com'
  - '*.ocp.kifarunix.com'
  - '*.kifarunix.com'
  # Use staging issuer for testing first
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer

Create the staging certificate:

oc apply -f ingress-cert-staging.yaml

So, what happens exactly after here?

The certificate generation process follows the following steps:

Certificate > CertificateRequest > Order > Challenge(s) > Secret

Understanding this flow is key to knowing what to expect, how to monitor progress, and how to troubleshoot if anything goes wrong.

In details, here is what happens under the hood!

  1. After you apply a Certificate resource, cert-manager takes over to handle the certificate issuance process. This process involves several internal steps and Kubernetes custom resources working together, all managed by cert-manager’s controllers.
  2. The process begins when cert-manager detects the newly created Certificate. It continuously watches for new or updated Certificate resources across the cluster. Once it sees your Certificate, it begins processing it.
  3. The first thing cert-manager does is check the issuerRef field in the Certificate. This field tells cert-manager which Issuer or ClusterIssuer to use. cert-manager then verifies that the referenced Issuer exists and is in a ready state. If the Issuer is missing or not ready, cert-manager will mark the Certificate as failed and log an appropriate event.
  4. If the Issuer is valid, cert-manager creates a new resource called a CertificateRequest. This object is essentially a request to sign a certificate, and it contains information like the Common Name, Subject Alternative Names, and public key derived from the Certificate specification. This step is internal to cert-manager and is how it structures the signing workflow.
  5. Next, cert-manager uses the information in the CertificateRequest to initiate an ACME Order if the Issuer uses the ACME protocol, such as with Let’s Encrypt. The Order object represents a request to the ACME server to issue a certificate for one or more domains. The Order tracks the status of domain validation and whether the certificate can be issued.
  6. To complete the Order, cert-manager creates one or more Challenge resources. Each Challenge represents a domain that must be validated. The Challenge type depends on how your Issuer is configured. If you’re using a DNS-01 challenge, cert-manager will attempt to create a TXT record in your DNS provider using credentials (API Token) you previously configured in the Issuer. This step proves to the ACME server that you own the domain.
  7. Once cert-manager has created and submitted the required DNS records, it waits for the ACME server to query them. If the DNS records are correct and resolvable, the ACME server marks the challenges as valid. cert-manager then updates the Challenge and Order resources to reflect that validation has succeeded.
  8. With all domain validations complete, cert-manager finalizes the Order. The ACME server now issues the signed certificate and returns it to cert-manager.
  9. cert-manager receives the signed certificate and updates the CertificateRequest resource with the issued certificate data. It then creates or updates the Kubernetes Secret that was specified in the original Certificate resource’s secretName field. This Secret contains the TLS private key and the signed certificate, and optionally the CA bundle if the issuer provides it.
  10. Finally, cert-manager updates the Certificate resource with a status of Ready. At this point, the certificate is fully issued, stored in a Kubernetes Secret, and ready to be used by applications, Ingress, or Routes.

cert-manager continues to monitor the certificate for expiration and will automatically renew it before it expires by repeating the same process.

Thus, after applying the Certificate creation manifest, you can check status:

oc get certificate -n openshift-ingress

Ensure state is READY True. Otherwise:

  • Check more details of the Certificate
    oc describe certificate <cert-name> -n <namespace> 
  • Check the CertificateRequest status
    oc get certificaterequest -A
    Get more details:
    oc describe certificaterequest <certificate-request-name> -n <namespace>
  • Check Order Status (ACME Only)
    oc get order -A
    Get more order details:
    oc describe order <order-name> -n <namespace> 
  • Check Challenge Status. Challenges are short-lived and it seems they are automatically cleaned up after successful certificate issuance (just in case you don’t find it):
    oc get challenges -A 
    Get more order details:
    oc describe challenge <challenge-name> -n <namespace> 
  • Verify DNS Records. You need to check the actual TXT record in DNS. Hence:
    On your Master/Worker nodes, try to run TXT check to see if it resolves by the default DNS server configured.
    dig TXT _acme-challenge.<domain>
    If it doesn’t resolve, try the public DNS servers:
    dig TXT _acme-challenge.<domain> +short @1.1.1.1 
    If this resolves, then you might be experiencing the split-horizon DNS issue! Then refer above on how to fix on the cert-manager operator.
  • You can further check the cert-manager pods logs for more information.

All in all, assuming that the Certificate creation process completed successfully, you should be able to see the Certificate secret on the respective namespace. For example, we created a staging Ingress certificate on the openshift-ingress namespace above.

oc get secrets -n openshift-ingress

You should see your Certificate secret:

NAME                                    TYPE                DATA   AGE
ingress-ocp-kifarunix-com-tls-staging   kubernetes.io/tls   2      5m
router-certs-default                    kubernetes.io/tls   2      25h
router-metrics-certs-default            kubernetes.io/tls   2      6d4h
router-stats-default                    Opaque              2      6d4h

Now that the staging certificate has been issued successfully, update the manifest to use the production ClusterIssuer to request a valid, trusted certificate from Let’s Encrypt.

Simply edit your certificate manifest and change the issuerRef section (especially, you can also update other parameters as applicable):

vim ingress-cert-prod.yaml

Paste the content below, making the necessary updates to fit your environment.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ingress-ocp-kifarunix-com-cert-prod
  namespace: openshift-ingress
spec:
  # Secret where cert-manager will store the certificate
  secretName: ingress-ocp-kifarunix-com-tls-prod
  # Certificate subject
  subject:
    organizations:
    - Kifarunix Inc.
  # Common name for the certificate  
  commonName: '*.apps.ocp.kifarunix.com'
  # DNS subject alternative names covered by this certificate
  dnsNames:
  - '*.apps.ocp.kifarunix.com'
  - '*.ocp.kifarunix.com'
  - '*.kifarunix.com'
  # Use staging issuer for testing first
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Apply the manifest to create the certificate:

oc apply -f ingress-cert-prod.yaml

You can check the certificates again:

oc get certificates -n openshift-ingress

You can also list the secrets:

oc get secrets -n openshift-ingress

Step 7: Generate the API Certificates

Just like we generated the Ingress certificates above, we’ll now create a certificate for the API endpoint but using the staging ClusterIssuer first. This ensures everything is working before switching to production.

Create a YAML manifest for the API certificate.

vim api-staging-cert.yaml

Update the values to reflect your setup (e.g., domain name, secret name, issuer, etc.):

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-ocp-kifarunix-com-cert-staging
  namespace: openshift-config
spec:
  commonName: api.ocp.kifarunix.com
  secretName: api-ocp-kifarunix-com-tls
  dnsNames:
  - api.ocp.kifarunix.com
  issuerRef:
    name: letsencrypt-staging  
    kind: ClusterIssuer

Then apply the manifest:

oc apply -f api-staging-cert.yaml

Check the certificate:

oc get certificate -n openshift-config
NAME                                 READY   SECRET                      AGE
api-ocp-kifarunix-com-cert-staging   False   api-ocp-kifarunix-com-tls   19s

The certificate should be ready in a short while if all goes well.

In the meantime, check the CSR, challenges and Orders:

oc get certificaterequest,orders,challenges -n openshift-config
NAME                                                                      APPROVED   DENIED   READY   ISSUER                REQUESTER                                         AGE
certificaterequest.cert-manager.io/api-ocp-kifarunix-com-cert-staging-1   True                True    letsencrypt-staging   system:serviceaccount:cert-manager:cert-manager   92s

NAME                                                                         STATE   AGE
order.acme.cert-manager.io/api-ocp-kifarunix-com-cert-staging-1-1947057731   valid   92s

NAME                                                                                     STATE   DOMAIN                  AGE
challenge.acme.cert-manager.io/api-ocp-kifarunix-com-cert-staging-1-1947057731-7840971   valid   api.ocp.kifarunix.com   91s

The certificate should be ready now.

Check the secret:

oc get secret -n openshift-config

If all is well, proceed to create the production API certificate. Create a YAML manifest for the API certificate.

vim api-prod-cert.yaml

Update the values to reflect your setup (e.g., domain name, secret name, issuer, etc.):

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-ocp-kifarunix-com-cert-prod
  namespace: openshift-config
spec:
  commonName: api.ocp.kifarunix.com
  secretName: api-ocp-kifarunix-com-tls-prod
  dnsNames:
  - api.ocp.kifarunix.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Then apply the manifest:

oc apply -f api-prod-cert.yaml

Step 8: Configure Ingress Controller and API Server to Use Generated Certificates

Now that cert-manager has successfully issued your certificates, the next step is to configure OpenShift to actually use them.

First get the secret names for the production Ingress and API certificates:

oc get secret -n openshift-ingress
oc get secret -n openshift-config

Hence, backup the API server and Ingresscontroller configuration before patching them:

oc get ingresscontroller default -n openshift-ingress-operator -o yaml > ingresscontroller-backup.yaml
oc get apiserver cluster -o yaml > apiserver-backup.yaml

Patch the default ingress controller to use the TLS secret generated by cert-manager:

oc patch ingresscontroller default \
  -n openshift-ingress-operator \
  --type=merge \
  -p '{"spec":{"defaultCertificate":{"name":"ingress-ocp-kifarunix-com-tls-prod"}}}'

You can even use oc edit command to manually make the updates on the resource.

Check ingress controller configuration:

oc get ingresscontroller default -n openshift-ingress-operator -o yaml | grep -C5 defaultCertificate

Wait for router pods to restart (1-2 minutes)

oc get pods -n openshift-ingress -w

Similarly, patch the API server to use the TLS certificate for the API endpoint (e.g., api.ocp.kifarunix.com):

oc patch apiserver cluster --type=merge --patch='{
  "spec": {
    "servingCerts": {
      "namedCertificates": [
        {
          "names": ["api.ocp.kifarunix.com"],
          "servingCertificate": {
            "name": "api-ocp-kifarunix-com-tls-prod"
          }
        }
      ]
    }
  }
}'

Confirm the API server configuration:

oc get apiserver cluster -o yaml | grep -C10 servingCerts

Check API server rollout status:

oc get co kube-apiserver -w
NAME             VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE   MESSAGE
kube-apiserver   4.19.5    True        True          False      6d6h    NodeInstallerProgressing: 1 node is at revision 17; 2 nodes are at revision 18

Wait for API server pods to restart (3-5 minutes)

oc get pods -n openshift-kube-apiserver -w

Step 9: Verification and Testing

After applying your new certificates for the API and Ingress, it’s important to validate that everything is working correctly.

1. Verify Web Console (Ingress TLS)

  • Open your browser on ingognitor or normal tab and clear cache, and go to your OpenShift console URL: https://console-openshift-console.apps.<your-domain>
  • Ensure:
    • The browser shows a valid TLS certificate.
    • No warnings like “insecure” or “self-signed”.
    • The certificate is issued by Let’s Encrypt (or your chosen CA).
      Replace OpenShift Self-Signed Ingress and API Certificates with Lets Encrypt

2. Verify API Access (API TLS)

  • On a terminal, run:
    oc login https://api.<your-domain>:6443 -u <your-user> --insecure-skip-tls-verify=false
  • If the certificate is valid:
    • You should not get any TLS verification errors.
    • You may be prompted for username/password or token.
  • Alternatively, use curl:
    curl -I https://api.ocp.kifarunix.com:6443/healthz
  • Ensure no TLS errors.
  • Verify certificate:
    echo | openssl s_client -connect api.ocp.kifarunix.com:6443 2>/dev/null | openssl x509 -noout -subject -issuer

Check the certificate subject and issuer details to confirm it’s your Let’s Encrypt certificate.

Conclusion

Replacing OpenShift’s default self-signed certificates with trusted Let’s Encrypt certificates not only eliminates browser security warnings but also improves trust and security across your applications and APIs. By leveraging cert-manager and automating DNS validation via Cloudflare, you gain a powerful and scalable solution for certificate lifecycle management in OpenShift.

This approach is not only production-ready but also aligns with best practices for managing TLS in cloud-native environments. Whether you’re running a public-facing app or securing internal APIs, using trusted certificates should be a foundational part of your platform’s security strategy.

By following this guide, your OpenShift cluster now has:

  • Automated certificate issuance and renewal
  • Publicly trusted TLS for both API and Ingress
  • Reduced manual overhead for certificate management

Keep cert-manager updated, monitor certificate expiration logs, and enjoy a more secure and seamless OpenShift experience.

SUPPORT US VIA A VIRTUAL CUP OF COFFEE

We're passionate about sharing our knowledge and experiences with you through our blog. If you appreciate our efforts, consider buying us a virtual coffee. Your support keeps us motivated and enables us to continually improve, ensuring that we can provide you with the best content possible. Thank you for being a coffee-fueled champion of our work!

Photo of author
Kifarunix
DevOps Engineer and Linux Specialist with deep expertise in RHEL, Debian, SUSE, Ubuntu, FreeBSD... Passionate about open-source technologies, I specialize in Kubernetes, Docker, OpenShift, Ansible automation, and Red Hat Satellite. With extensive experience in Linux system administration, infrastructure optimization, information security, and automation, I design and deploy secure, scalable solutions for complex environments. Leveraging tools like Terraform and CI/CD pipelines, I ensure seamless integration and delivery while enhancing operational efficiency across Linux-based infrastructures.

Leave a Comment