BlogKubernetes · DevOps
KubernetesTLScert-managerDevOps

TLS Certificate Debugging in Kubernetes

Certificate errors in Kubernetes are harder to debug because the certificates are hidden inside Secrets, managed by cert-manager, and surfaced only at ingress level. This guide shows you exactly where to look and how to fix the most common TLS failures.

Navsatech Team·March 2026·8 min read

Common Kubernetes TLS errors

01
x509: certificate signed by unknown authority
Your pod is connecting to a service using a self-signed or private CA certificate that isn't in the pod's trust store. Common when services inside the cluster use internal certificates.
02
Ingress returns default fake certificate
The TLS secret referenced by your Ingress doesn't exist, has the wrong name, or is in the wrong namespace. The ingress controller falls back to a self-signed default certificate.
03
cert-manager certificate stuck in Pending
cert-manager is waiting for an ACME HTTP-01 or DNS-01 challenge to complete, or there's a misconfiguration in the ClusterIssuer.
04
Certificate expired inside the cluster
cert-manager auto-renews certificates, but only if the Certificate resource exists and the issuer is healthy. Manual certs stored as Secrets expire silently.

Inspect TLS secrets

List all TLS secrets in a namespace:

kubectl get secrets -n your-namespace --field-selector type=kubernetes.io/tls

Extract and inspect the certificate from a secret:

# Extract the certificate
kubectl get secret your-tls-secret -n your-namespace \
  -o jsonpath='{.data.tls\.crt}' | base64 -d > cert.pem

# Inspect it
openssl x509 -in cert.pem -text -noout | grep -E "Subject|Issuer|Not Before|Not After|DNS"

Check expiry directly:

kubectl get secret your-tls-secret -n your-namespace \
  -o jsonpath='{.data.tls\.crt}' | base64 -d \
  | openssl x509 -noout -dates

Debugging cert-manager

Check the status of a Certificate resource:

kubectl describe certificate your-cert -n your-namespace

Check the CertificateRequest that cert-manager created:

kubectl get certificaterequest -n your-namespace
kubectl describe certificaterequest your-cert-xxxxx -n your-namespace

Check the Order (for ACME issuers):

kubectl get orders -n your-namespace
kubectl describe order your-cert-xxxxx -n your-namespace

Check cert-manager controller logs for errors:

kubectl logs -n cert-manager deploy/cert-manager | grep -E "ERROR|error|failed" | tail -20

Verify your ClusterIssuer is ready:

kubectl get clusterissuer
kubectl describe clusterissuer letsencrypt-prod

Ingress TLS configuration

A correctly configured Ingress with TLS:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - example.com
    secretName: example-com-tls    # cert-manager creates this
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80

Verify the ingress is using the right certificate:

kubectl describe ingress my-ingress -n your-namespace | grep -A5 TLS

Test what certificate the ingress is actually serving:

openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

Trust issues between pods

When a pod gets x509: certificate signed by unknown authority connecting to another internal service, you need to inject the CA cert into the pod's trust store. The cleanest way is via a ConfigMap:

kubectl create configmap ca-bundle \
  --from-file=ca.crt=internal-ca.pem \
  -n your-namespace
# Mount it in your deployment
volumes:
- name: ca-bundle
  configMap:
    name: ca-bundle
volumeMounts:
- name: ca-bundle
  mountPath: /etc/ssl/certs/internal-ca.crt
  subPath: ca.crt

For Java pods, set the trust store via environment variables:

env:
- name: JAVA_TOOL_OPTIONS
  value: "-Djavax.net.ssl.trustStore=/etc/ssl/certs/truststore.jks
          -Djavax.net.ssl.trustStorePassword=changeit"

Quick reference

# List all TLS secrets
kubectl get secrets -A --field-selector type=kubernetes.io/tls

# Check cert expiry from secret
kubectl get secret my-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates

# Force cert-manager to renew a certificate
kubectl annotate certificate my-cert cert-manager.io/issueTemporary="true" --overwrite

# Delete and recreate a stuck certificate
kubectl delete certificate my-cert -n my-namespace
# cert-manager will recreate it

# Check what cert an endpoint is serving
openssl s_client -connect my-service.namespace.svc.cluster.local:443 -showcerts
Inspect the certificate outside Kubernetes
Extract the cert from your secret and upload it to CertLens for a full chain analysis — expiry, trust, crypto strength, and fix suggestions — without kubectl.
Analyse Your Certificate →
✓ PEM certificate supported
✓ Chain validation
✓ Live TLS scan
✓ Files never stored
Copilot
CertLens Copilot
AI-powered PKI assistant
Hi! I'm CertLens Copilot — ask me anything about certificates, TLS errors, JKS keystores, SWIFT PKI, or trust chain issues.