This draft comes from a real cluster note where I needed a repeatable way to issue TLS certificates through cert-manager using Cloudflare DNS-01 validation. I cleaned up the environment-specific details and replaced all real domains, e-mail addresses, and API tokens with placeholders.
The end goal was simple: let Kubernetes manage certificates automatically while keeping DNS-based validation in place for public-facing services.
Why DNS-01 Was the Right Fit
For multi-service or ingress-heavy clusters, DNS-01 is often the cleaner option:
- it does not depend on HTTP challenge paths being reachable first
- it works well for wildcard and externally routed cases
- it keeps certificate issuance independent from the application container itself
In this setup, Cloudflare provided the DNS API that cert-manager used to complete the challenge.
1. Install cert-manager
If cert-manager is not installed yet:
| |
One of the first possible failure modes is simply forgetting that the cert-manager namespace does not exist yet. The --create-namespace flag prevents that.
2. Install or Validate NGINX Ingress
Before requesting a certificate for an ingress-backed service, I made sure the ingress controller was in place:
| |
In the original note, one reason for keeping externalTrafficPolicy=Local was avoiding SSL lookup confusion during ingress handling.
If the release already exists, upgrade instead:
| |
3. Handle a Chart Values Gotcha
One of the installation issues I recorded later was a Helm template failure around controller.extraArgs.update-status.
The fix was to move that setting into values.yml and make it explicitly string-based:
| |
That is a good reminder that not all values behave the same when passed inline through --set.
4. Verify the Cloudflare Token
Before wiring the issuer, I like to verify the API token separately:
| |
The real token should never live in the post itself. In a live environment, store it securely and only reference a placeholder in documentation.
5. Store the Token as a Kubernetes Secret
Create a secret in the cert-manager namespace:
| |
Apply it:
| |
6. Create a ClusterIssuer
Because the goal was to reuse the issuer across services, I used a ClusterIssuer instead of a namespace-scoped Issuer:
| |
7. Request a Certificate
With the issuer in place, create a certificate in the service namespace:
| |
8. Wire the Certificate into Ingress
A representative ingress looked like this:
| |
9. Enable Snippet Annotations If Needed
One of the errors in the original note came from ingress annotation restrictions:
| |
The fix was updating the ingress controller ConfigMap:
| |
10. Verify and Troubleshoot
Useful checks:
| |
If NGINX still does not pick up the certificate immediately, a reload can help confirm whether the secret is already valid:
| |
What This Note Shows
This was not just a certificate issuance note. It was an operational sequence:
- install the controller components
- validate token access
- store the secret safely
- define the issuer
- request the certificate
- make sure ingress actually consumes it
That sequencing is usually where real-world TLS automation either becomes smooth or turns into a string of confusing partial failures.
Closing Thought
I like this kind of note because it starts as infrastructure glue work but ends up becoming a reusable pattern. Once cleaned up and sanitized, it is exactly the sort of thing that helps other admins move faster with fewer surprises.