Kubernetes TLS Ingress route with cert-manager and SelfSigned ClusterIssuer not working
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When a TLS Ingress route with cert-manager and a SelfSigned ClusterIssuer is not working, the issue is typically one of three things: the ClusterIssuer is not in a Ready state, the Ingress annotations are wrong, or the Certificate/Secret is not being created in the correct namespace. Self-signed certificates add an extra layer of complexity because browsers and clients reject them by default. This guide walks through the correct configuration and the most common failure points.
Correct Setup
Step 1: Create the SelfSigned ClusterIssuer
The READY column must show True. If it shows False, cert-manager cannot issue certificates.
Step 2: Create the Ingress with TLS
Key annotations:
cert-manager.io/cluster-issuer: References the ClusterIssuer (notcert-manager.io/issuer, which references a namespaced Issuer)secretNameintls: Name of the Secret where cert-manager stores the certificate
Step 3: Verify the Certificate
Debugging: Certificate Not Ready
Common Issue 1: Wrong Annotation Name
Common Issue 2: Namespace Mismatch
A ClusterIssuer is cluster-scoped, but Issuer is namespace-scoped. If you created an Issuer instead of a ClusterIssuer, the Ingress in a different namespace cannot find it:
Common Issue 3: IngressClass Not Set
Without ingressClassName, no Ingress controller processes the Ingress resource, and TLS termination never happens.
Common Issue 4: Self-Signed CA for Multiple Certificates
A basic SelfSigned issuer creates a new self-signed certificate each time. For a proper CA setup, create a self-signed root CA, then use it to sign other certificates:
Then reference my-ca-issuer in your Ingress annotations instead of the self-signed issuer directly.
Testing the TLS Connection
Common Pitfalls
- Using
cert-manager.io/issuerinstead ofcert-manager.io/cluster-issuer: These are different annotations.issuerlooks for a namespacedIssuerresource;cluster-issuerlooks for aClusterIssuer. Using the wrong one causes cert-manager to silently fail to find the issuer. - cert-manager not installed or CRDs missing: If cert-manager is not installed, the annotations are ignored and no Certificate is created. Verify with
kubectl get pods -n cert-managerandkubectl get crd | grep cert-manager. - Secret not in the same namespace as the Ingress: The TLS secret must exist in the same namespace as the Ingress. cert-manager creates the secret in the Ingress namespace automatically, but if you created it manually in the wrong namespace, the Ingress controller cannot find it.
- Browsers rejecting self-signed certificates: Self-signed certificates are not trusted by browsers or HTTP clients by default. For development, use
curl -kor add the CA to your system trust store. For production, use Let's Encrypt with an ACME ClusterIssuer instead. - DNS not pointing to the Ingress controller: Even with a valid certificate, if
app.example.comdoes not resolve to the Ingress controller's external IP, TLS connections fail. Verify withnslookup app.example.comandkubectl get service -n ingress-nginx.
Summary
- Create a
ClusterIssuerwithselfSigned: {}and verify it showsREADY: True - Use the annotation
cert-manager.io/cluster-issuer(notcert-manager.io/issuer) on the Ingress - Set
ingressClassNamein the Ingress spec (required in Kubernetes 1.22+) - Check Certificate, CertificateRequest, and cert-manager logs when debugging
- For proper CA hierarchy, create a self-signed root CA and use a CA
ClusterIssuerto sign app certificates - Self-signed certificates are for development only — use Let's Encrypt ACME for production

