This article describes how to use the cert-manager operator for Red Hat OpenShift to automatically provide and renew certificates to OpenShift applications. This approach uses the Automated Certificate Management Environment (ACME) feature provided by Identity Management (IdM) with DNS challenge.
This post follows a series of previous articles covering this feature:
- Managing Automatic Certificate Management Environment (ACME) in Identity Management (IdM) introduces the ACME feature and describes its setup.
- Automatically acquire and renew certificates using mod_md and Automated Certificate Management Environment (ACME) in Identity Management (IdM) covers how to use this feature with the
mod_md
client. - Automatic certificate issuing with IdM and cert-manager operator for OpenShift explains how to configure the
http-01
challenge using an Ingress Controller to expose the deployed web application.
This article provides an alternative to the previous article for those that use IdM as their DNS server. We will implement a DNS challenge to confirm domain authority for certificate requests.
The ACME advantage
As the previous articles demonstrate, the manual management of certificates that most companies currently perform has several limitations and introduces inefficiencies. This tedious process of monitoring and tracking certificate lifecycles requires significant time and effort, is prone to human error, and can lead to painful outages.
In that sense, the ACME protocol, which was created by the Internet Research Security Group (ISRG) and its Certificate Authority (CA) Let’s Encrypt, is designed to solve all these challenges by removing the need for human interaction.
Environment
Our environment will consist of a Red Hat Enterprise Linux (RHEL) 10 IdM server and an OpenShift 4.14 cluster (though any newer version will also work for this solution).
It is important to note that RHEL 10 is the first release that provides the ACME feature as Generally Available (GA), so it is considered fully supported. As we saw in the first article, a key prerequisite is the automatic removal of expired certificates. RHEL 9 and older releases require explicit enablement with several limitations, which is why they do not support this feature. In RHEL 10, this is enabled by default on new installations.
Additionally, RHEL 10 implements by default random serial numbers (RSNv3) in Dogtag CA. As a result, any new certificate issued by RHEL 10 IdM Dogtag CA has a random serial number and a default retention period of 30 days following the expiry date, after which the certificate will be automatically removed.
First, we will install the IdM server in our RHEL 10 server with hostname idm.melmac.univ
. For this, we will install the packages and then perform the installation:
root@idm:~# dnf install ipa-server ipa-server-dns bind-dyndb-ldap
For the installation, you do not need to specify the random serial numbers option (as in RHEL 9) because it’s selected by default:
root@idm:~# ipa-server-install --ds-password=<ds_pass> --admin-password=<admin_pass> --setup-dns --auto-reverse
Accept all the options provided by default. After the installation has finished, execute:
root@idm:~# firewall-cmd --add-service freeipa-ldap
root@idm:~# firewall-cmd --add-service freeipa-ldaps
root@idm:~# firewall-cmd --add-service dns
root@idm:~# firewall-cmd --runtime-to-permanent
Next, enable the ACME feature (it is disabled by default) with:
root@idm:~# ipa-acme-manage enable
The ipa-acme-manage command was successful
Check the result with:
root@idm:~# ipa-acme-manage status
ACME is enabled
The ipa-acme-manage command was successful
In the IdM web UI (Figure 1), you’ll see all is ready to start providing certificates with RSNv3.

Next, we will focus on the cert-manager operator in our OpenShift 4.14 cluster. For the installation, navigate to Operators → OperatorHub, shown in Figure 2.

As illustrated in Figure 2, there are two operators: one community upstream (ideal for pure vanilla Kubernetes clusters) and the cert-manager operator provided and curated by Red Hat. The latter is the one we will install.
Proceed with the installation using all default options (Figure 3).

Wait for the installation to finish. Your base environment setup is now complete.
Provide and enable dynamic updates to DNS zones
To provide dynamic updates to the DNS zone in IdM, we need to authenticate as an approved nameserver or approved client. To accomplish that, IdM with Kerberos uses the standard TSIG (transaction signature) protocol, but given that programs do not typically use Kerberos for these tasks, we will choose another algorithm. Here, we select hmac-sha512
.
To create the key, execute the following:
root@idm:~# tsig-keygen -a hmac-sha512 update | tee -a /etc/named/ipa-ext.conf
This command appends a key with the name update to the named .conf
file, /etc/named/ipa-ext.conf
(this file is not modified during IdM upgrades).
Now we have to update the IdM named server and verify the update
key loads effectively. Execute the following command:
root@idm:~# rndc reconfig
root@idm:~# rndc tsig-list |grep bind |grep update
The last command should return the following:
view "_bind"; type "static"; key "update";
The last step is to modify the update policy of our DNS domain. First, we need to obtain a Kerberos ticket. Execute the following to enable updates in our DNS domain zone:
root@idm:~# echo <admin_pass> | kinit admin
root@idm:~# ipa dnszone-mod melmac.univ --update-policy='grant <MYDOMAIN.COM> krb5-self * A; grant <MYDOMAIN.COM> krb5-self * AAAA; grant <MYDOMAIN.COM> krb5-self * SSHFP; grant update subdomain <mydomain.com> TXT;'
Substitute <MYDOMAIN.COM>
with your domain in uppercase (in my case, MELMAC.UNIV
) and <mydomain.com>
with the same corresponding domain, but in lowercase. This grants the updates to our domain.
You can check it and observe how the policy is updated. For our environment:
root@idm:~# ipa dnszone-show melmac.univ
Zone name: melmac.univ.
Active zone: True
Authoritative nameserver: idm.melmac.univ.
Administrator e-mail address: hostmaster.melmac.univ.
SOA serial: 1751873655
SOA refresh: 3600
SOA retry: 900
SOA expire: 1209600
SOA minimum: 3600
BIND update policy: grant MELMAC.UNIV krb5-self * A; grant MELMAC.UNIV krb5-self * AAAA; grant MELMAC.UNIV krb5-self * SSHFP; grant update subdomain melmac.univ TXT;
Dynamic update: True
Allow query: any;
Allow transfer: none;
Now we can test the ACME server to get certificates.
Trusting IdM CA
To enable security in the communication between our ClusterIssuer resource in OpenShift Container Platform and IdM, we need to add the ca.crt
from the IdM to the trusted CA list that cert-manager uses.
To do this, we will create a new ConfigMap in OpenShift Container Platform that contains the certificate located in the path /etc/ipa/ca.crt
in IdM. Execute the following:
[azure@bastion-76dv5 ~]$ oc create configmap custom-ca --from-file=ca-bundle.crt=./ca.crt -n openshift-config
[azure@bastion-76dv5 ~]$ oc patch proxy/cluster --type=merge --patch='{"spec":{"trustedCA":{"name":"custom-ca"}}}'
[azure@bastion-76dv5 ~]$ oc create configmap trusted-ca -n cert-manager
[azure@bastion-76dv5 ~]$ oc label cm trusted-ca config.openshift.io/inject-trusted-cabundle=true -n cert-manager
[azure@bastion-76dv5 ~]$ oc -n cert-manager-operator patch subscription openshift-cert-manager-operator --type='merge' -p '{"spec":{"config":{"env":[{"name":"TRUSTED_CA_CONFIGMAP_NAME","value":"trusted-ca"}]}}}'
After that, roll out the cert-manager operator and all the cert-manager Deployments:
[azure@bastion-76dv5 ~]$ oc rollout status deployment/cert-manager-operator-controller-manager -n cert-manager-operator
[azure@bastion-76dv5 ~]$ oc rollout status deployment/cert-manager -n cert-manager
[azure@bastion-76dv5 ~]$ oc rollout status deployment/cert-manager-webhook -n cert-manager
[azure@bastion-76dv5 ~]$ oc rollout status deployment/cert-manager-cainjector -n cert-manager
The most effective way to verify this is to inspect the certificates in the bundle imported into your cert-manager pods. Your IdM CA certificate must be in the first position:
[azure@bastion-9psbk ~]$ oc get pods -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-647f56c54b-4ns5m 1/1 Running 0 15m
cert-manager-cainjector-7b95fc9574-ngxm2 1/1 Running 0 15m
cert-manager-webhook-5c68bc69bb-sptkl 1/1 Running 0 15m
[azure@bastion-9psbk ~]$ oc exec -it cert-manager-647f56c54b-4ns5m -n cert-manager -- cat /etc/pki/tls/certs/cert-manager-tls-ca-bundle.crt
Now that you trust the IdM CA, you can securely create your ClusterIssuer
resource.
Using cert-manager operator to acquire certificates
The cert-manager is a very popular operator in Kubernetes world to provide certificates to workloads and Ingress controllers.
To enable ACME with DNS01 challenge, we need to configure an Issuer
(in our case, a ClusterIssuer
, due to the required cluster scope and its ability to be referenced by certificates in every namespace). For that, we need to add the previously created TSIG
key to a Secret (which we will reference in our ClusterIssuer
) in the cert-manager project, as illustrated in Figure 4.

The ClusterIssuer
resource in the OpenShift cluster is under the rfc2136
element and should look like this:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: acme-issuer
namespace: cert-manager
spec:
acme:
email: admin@melmac.univ
server: https://idm.melmac.univ/acme/directory
privateKeySecretRef:
name: acme-issuer-key
solvers:
- dns01:
rfc2136:
nameserver: idm.melmac.univ:53
tsigKeyName: update
tsigAlgorithm: HMACSHA512
tsigSecretSecretRef:
name: tsig-secret
key: tsig-secret-key
After performing an oc apply
of the previous YAML file, you will see the following upon successful completion:
[azure@bastion-76dv5 ~]$ oc get clusterissuer -n cert-manager
NAME READY AGE
acme-issuer True 10s
If you query the ClusterIssuer
object by executing oc describe
, you will obtain the following Status section:
Status:
Acme:
Last Private Key Hash: nL9MRT1L0e4dfEWXdt9sccC8UcoYoDQ5HKSPTHlnRcY=
Last Registered Email: admin@melmac.univ
Uri: https://idm.melmac.univ/acme/v1/acct/DB21KAMgHWeWaC__4TyK56Uii7ZhSFrf9hfB-KA2JLo
Conditions:
Last Transition Time: 2025-07-03T10:36:30Z
Message: The ACME account was registered with the ACME server
Observed Generation: 1
Reason: ACMEAccountRegistered
Status: True
Type: Ready
Events: <none>
Next, acquire a new certificate against your recently created ClusterIssuer
object for the application myapplication5.melmac.univ
. To do this, create a Certificate
object with the following:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: www5
namespace: cert-manager
spec:
secretName: www5
duration: 2160h # 90d
renewBefore: 360h # 15d
subject:
organizations:
- MyOrg
commonName: myapplication5.melmac.univ
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
rotationPolicy: Always
usages:
- server auth
- client auth
dnsNames:
- myapplication5.melmac.univ
issuerRef:
name: acme-issuer
kind: ClusterIssuer
Regarding the previous YAML code, note that the duration: 2160h
field sets the certificate validity to 3 months, aligning with Let's Encrypt and the default Dogtag CA configuration. But the ACME profile in Dogtag CA ultimately dictates this duration.
To change the ACME profile lifetime of certificates, refer to the Certificates Lifecycle section in the blog Automatic certificate issuing with IdM and cert-manager operator for OpenShift. This configuration applies to both RHEL 9 and RHEL 10.
After applying that YAML file, a Secret
resource will be created containing the tls.key
and tls.crt
fields with the corresponding base64-encoded key and certificate values issued by Dogtag CA. First, tls.key
will create almost immediately, and after a few seconds, tls.crt
will issue and insert into the Secret:
[azure@bastion-9psbk ~]$ oc get secret -n cert-manager
[...]
www5-65k5f Opaque 1 3s
[azure@bastion-9psbk ~]$ oc get secret -n cert-manager
[...]
www5 kubernetes.io/tls 2 3s
[azure@bastion-9psbk ~]$ oc describe secret www5 -n cert-manager
Name: www5
Namespace: cert-manager
Labels: controller.cert-manager.io/fao=true
Annotations: cert-manager.io/alt-names: myapplication5.melmac.univ
cert-manager.io/certificate-name: www5
cert-manager.io/common-name: myapplication5.melmac.univ
cert-manager.io/ip-sans:
cert-manager.io/issuer-group:
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: acme-issuer
cert-manager.io/uri-sans:
Type: kubernetes.io/tls
Data
====
tls.crt: 3270 bytes
tls.key: 1679 bytes
To troubleshoot any incorrect behavior, you can check the logs of the cert-manager
pod in the cert-manager project. A successful certificate acquisition or renewal will show the following:
[azure@bastion-9psbk ~]$ oc logs -n cert-manager cert-manager-647f56c54b-4ns5m
[...]
I0704 08:48:43.631810 1 dns.go:90] "presenting DNS01 challenge for domain" logger="cert-manager.controller.Present" resource_name="www5-1-1869734104-2702398043" resource_namespace="cert-manager" resource_kind="Challenge" resource_version="v1" dnsName="myapplication5.melmac.univ" type="DNS-01" resource_name="www5-1-1869734104-2702398043" resource_namespace="cert-manager" resource_kind="Challenge" resource_version="v1" domain="myapplication5.melmac.univ"
I0704 08:49:45.199661 1 acme.go:236] "certificate issued" logger="cert-manager.controller.sign" resource_name="www5-1" resource_namespace="cert-manager" resource_kind="CertificateRequest" resource_version="v1" related_resource_name="www5-1-1869734104" related_resource_namespace="cert-manager" related_resource_kind="Order" related_resource_version="v1"
I0704 08:49:45.199810 1 conditions.go:252] Found status change for CertificateRequest "www5-1" condition "Ready": "False" -> "True"; setting lastTransitionTime to 2025-07-04 08:49:45.199781171 +0000 UTC m=+1601.571130576
I0704 08:49:45.238131 1 conditions.go:192] Found status change for Certificate "www5" condition "Ready": "False" -> "True"; setting lastTransitionTime to 2025-07-04 08:49:45.238119612 +0000 UTC m=+1601.609469017
Finally, note the renewBefore
parameter of the previous YAML code. This refers to the time relative to the not After
field of the issued certificate when the client will attempt renewal. It is a customizable and optional parameter that defaults to two-thirds of the current certificate’s validity period.
Before tls.crt
expires, your IdM Dogtag CA will automatically re-issue a new certificate with the same characteristics as the old one. It will insert the new tls.key
and tls.crt
values into the same Secret, thus providing a completely renewed certificate automatically.
Conclusion
This article demonstrated how to use the IdM ACME feature with the cert-manager operator using the DNS challenge. This is an effective and scalable way to provide certificates automatically to your applications deployed on an OpenShift Container Platform cluster.
Because IdM is included in your Red Hat Enterprise Linux subscription, you can try to replicate this content in your lab environment without any additional subscriptions to set up your own ACME environment. An additional OpenShift subscription is needed to set up the OpenShift Container Platform cluster.
If you are not already a RHEL subscriber, get a no-cost trial from Red Hat.