From 0151f085cfda305d5ead473bc8df546c029e7feb Mon Sep 17 00:00:00 2001 From: prakhar Date: Sun, 3 May 2026 12:47:36 +1000 Subject: [PATCH 1/2] [ocp4_workload_rhacs] Pre-create CNAME to fix ACME DNS ENT issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cert-manager runs a DNS-01 ACME challenge for the central route, it creates a _acme-challenge TXT record which produces a DNS Empty Non-Terminal (ENT). The ENT causes the wildcard *.apps.* to stop matching the central hostname, failing the ACME challenge for all issuers (Google, ZeroSSL) and falling back to selfsigned. Fix: add dns_cname_pre_cert.yml which pre-creates a specific CNAME for the central route before cert issuance. The CNAME and the _acme-challenge record coexist as siblings — no ENT problem. - Issuer-agnostic: finds any ClusterIssuer with a DDNS webhook via json_query, no hardcoded issuer names - Silently skips on non-DDNS clusters (AWS Route53, GCP, etc.) - Reads tsigAlgorithm from ClusterIssuer config, nothing hardcoded - Called from workload.yml before certificate.yml so the CNAME exists before any ACME challenge fires - dns_registration.yml unchanged — BareMetal A record logic unaffected --- .../tasks/dns_cname_pre_cert.yml | 54 +++++++++++++++++++ roles/ocp4_workload_rhacs/tasks/workload.yml | 4 ++ 2 files changed, 58 insertions(+) create mode 100644 roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml diff --git a/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml b/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml new file mode 100644 index 0000000..b109193 --- /dev/null +++ b/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml @@ -0,0 +1,54 @@ +--- +# Pre-create a CNAME record for the central route before ACME cert issuance. +# +# Problem: When cert-manager runs a DNS-01 ACME challenge for the central route, +# it creates a _acme-challenge TXT record which creates a DNS Empty Non-Terminal (ENT). +# The ENT causes the wildcard *.apps.* to stop matching the central hostname, +# resulting in NODATA and a failed ACME challenge regardless of which issuer is used. +# +# Fix: Pre-create a specific CNAME for the central hostname before cert issuance. +# The CNAME and the _acme-challenge record coexist as siblings — no ENT problem. +# +# This task is issuer-agnostic: it finds any ready ClusterIssuer configured with +# a DDNS webhook and uses its credentials. Silently skips on non-DDNS clusters. + +- name: Find ClusterIssuer with DDNS webhook solver + kubernetes.core.k8s_info: + api_version: cert-manager.io/v1 + kind: ClusterIssuer + register: r_pre_cert_cluster_issuers + +- name: Set DDNS issuer fact + ansible.builtin.set_fact: + _ocp4_workload_rhacs_pre_cert_ddns_issuer: >- + {{ + r_pre_cert_cluster_issuers.resources + | json_query("[?spec.acme.solvers[?dns01.webhook.config.ddnsServer]]") + | first | default({}) + }} + +- name: Pre-create CNAME record to prevent DNS ENT issue during ACME challenge + when: _ocp4_workload_rhacs_pre_cert_ddns_issuer | length > 0 + vars: + _solver: "{{ _ocp4_workload_rhacs_pre_cert_ddns_issuer.spec.acme.solvers[0].dns01.webhook.config }}" + block: + - name: Get TSIG secret from cert-manager namespace + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: "{{ _solver.tsigSecretRef.name }}" + namespace: cert-manager + register: r_pre_cert_tsig_secret + + - name: Create CNAME record for central route + community.general.nsupdate: + server: "{{ _solver.ddnsServer }}" + zone: "{{ _solver.ddnsZone }}" + record: "central-{{ ocp4_workload_rhacs_central_namespace }}.{{ openshift_cluster_ingress_domain | regex_replace('\\.' + _solver.ddnsZone + '$', '') }}" + type: CNAME + ttl: 30 + value: "console-openshift-console.{{ openshift_cluster_ingress_domain }}." + key_name: "{{ _solver.tsigKeyName }}" + key_secret: "{{ r_pre_cert_tsig_secret.resources[0].data[_solver.tsigSecretRef.key] | b64decode }}" + key_algorithm: "{{ _solver.tsigAlgorithm }}" + state: present diff --git a/roles/ocp4_workload_rhacs/tasks/workload.yml b/roles/ocp4_workload_rhacs/tasks/workload.yml index b5d626b..b4ca02a 100644 --- a/roles/ocp4_workload_rhacs/tasks/workload.yml +++ b/roles/ocp4_workload_rhacs/tasks/workload.yml @@ -65,6 +65,10 @@ retries: 30 delay: 5 +- name: Pre-create CNAME record before ACME cert issuance + when: ocp4_workload_rhacs_enable_route_certs | bool + ansible.builtin.include_tasks: dns_cname_pre_cert.yml + - name: Set up Certificate for Central when: ocp4_workload_rhacs_enable_route_certs | bool ansible.builtin.include_tasks: certificate.yml From 3345d2357b3fcfe3992daef5eaccc9bbda533176 Mon Sep 17 00:00:00 2001 From: prakhar Date: Sun, 3 May 2026 12:56:25 +1000 Subject: [PATCH 2/2] Fix: skip CNAME pre-creation on BareMetal/SNO clusters to avoid A record conflict --- .../tasks/dns_cname_pre_cert.yml | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml b/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml index b109193..4aac6e6 100644 --- a/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml +++ b/roles/ocp4_workload_rhacs/tasks/dns_cname_pre_cert.yml @@ -9,16 +9,32 @@ # Fix: Pre-create a specific CNAME for the central hostname before cert issuance. # The CNAME and the _acme-challenge record coexist as siblings — no ENT problem. # +# Only runs on non-BareMetal platforms. BareMetal clusters use an explicit A record +# created by dns_registration.yml after Central is deployed — a CNAME would conflict. +# # This task is issuer-agnostic: it finds any ready ClusterIssuer configured with # a DDNS webhook and uses its credentials. Silently skips on non-DDNS clusters. +- name: Get cluster infrastructure platform + kubernetes.core.k8s_info: + api_version: config.openshift.io/v1 + kind: Infrastructure + name: cluster + register: r_pre_cert_infrastructure + +- name: Set platform fact + ansible.builtin.set_fact: + _ocp4_workload_rhacs_pre_cert_platform: "{{ r_pre_cert_infrastructure.resources[0].status.platform | default('Unknown') }}" + - name: Find ClusterIssuer with DDNS webhook solver + when: _ocp4_workload_rhacs_pre_cert_platform not in ["BareMetal", "None"] kubernetes.core.k8s_info: api_version: cert-manager.io/v1 kind: ClusterIssuer register: r_pre_cert_cluster_issuers - name: Set DDNS issuer fact + when: _ocp4_workload_rhacs_pre_cert_platform not in ["BareMetal", "None"] ansible.builtin.set_fact: _ocp4_workload_rhacs_pre_cert_ddns_issuer: >- {{ @@ -28,7 +44,9 @@ }} - name: Pre-create CNAME record to prevent DNS ENT issue during ACME challenge - when: _ocp4_workload_rhacs_pre_cert_ddns_issuer | length > 0 + when: + - _ocp4_workload_rhacs_pre_cert_platform not in ["BareMetal", "None"] + - _ocp4_workload_rhacs_pre_cert_ddns_issuer | default({}) | length > 0 vars: _solver: "{{ _ocp4_workload_rhacs_pre_cert_ddns_issuer.spec.acme.solvers[0].dns01.webhook.config }}" block: