How to fix TLS secret not found in Kubernetes

KubernetesINTERMEDIATEHIGHUpdated Dec 7, 2025· 159 views

This error occurs when an Ingress resource references a TLS secret that doesn't exist or is misconfigured. Fix it by creating the TLS secret in the correct namespace with proper certificate format, or configure cert-manager for automatic certificate management.

Quick fix

Fixes TLS secret not found

# Check if secret exists
kubectl get secret <tls-secret-name> -n <namespace>

# Describe secret to verify type and keys
kubectl describe secret <tls-secret-name> -n <namespace>
  1. Verify secret exists in correct namespace
  2. Create TLS secret from certificate files
  3. Fix certificate chain order
  4. Update Ingress with correct TLS configuration
kubernetes — error
# Check if secret exists
kubectl get secret <tls-secret-name> -n <namespace>
# Describe secret to verify type and keys
kubectl describe secret <tls-secret-name> -n <namespace>
TLS secret not found

What this error means

The "TLS secret not found" error indicates that the Ingress controller cannot locate the TLS secret referenced in your Ingress resource's tls.secretName field. Without this secret, the Ingress cannot serve HTTPS traffic and may fall back to serving a self-signed certificate or fail entirely. TLS secrets in Kubernetes must be of type kubernetes.io/tls and contain two keys: tls.crt (the certificate chain) and tls.key (the private key). The secret must exist in the same namespace as the Ingress resource—Kubernetes doesn't allow cross-namespace secret references for Ingress TLS. This error commonly occurs after cluster migrations, when secrets are accidentally deleted, or when using cert-manager before certificates are issued.

Typical symptoms

  • Ingress controller serves fake/self-signed certificate instead of expected certificate
  • HTTPS connections fail or show certificate warnings
  • Ingress controller logs show "secret does not exist" errors
  • All HTTPS requests to the ingress host fail
  • HTTP 403 errors when client certificate authentication is configured

Common causes

  1. TLS secret doesn't exist in the Ingress namespace
  2. Secret type is not kubernetes.io/tls (e.g., Opaque)
  3. Secret missing required keys tls.crt or tls.key
  4. Certificate chain in wrong order (should be leaf → intermediate → root)
  5. cert-manager hasn't finished issuing the certificate yet

How to fix "TLS secret not found"

1Verify secret exists in correct namespace

Check if the TLS secret exists in the same namespace as the Ingress:

bash
# Check if secret exists
kubectl get secret <tls-secret-name> -n <namespace>

# Describe secret to verify type and keys
kubectl describe secret <tls-secret-name> -n <namespace>

Expected output should show:
- Type: kubernetes.io/tls
- Data keys: tls.crt, tls.key

2Create TLS secret from certificate files

Create the secret from your certificate and key files:

bash
# Create TLS secret
kubectl create secret tls my-tls-secret \
  --cert=server.crt \
  --key=server.key \
  --namespace <namespace>

# Verify secret was created correctly
kubectl get secret my-tls-secret -n <namespace> -o jsonpath='{.type}'
# Should output: kubernetes.io/tls

For self-signed certificates (development only):

bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout server.key -out server.crt \
  -subj "/CN=example.com/O=example.com" \
  -addext "subjectAltName = DNS:example.com"

kubectl create secret tls my-tls-secret \
  --cert=server.crt --key=server.key -n <namespace>
3Fix certificate chain order

If using intermediate certificates, ensure correct chain order:

bash
# Correct order: leaf certificate first, then intermediates, then root
cat server.crt intermediate.crt root.crt > fullchain.pem

# Recreate secret with full chain
kubectl delete secret my-tls-secret -n <namespace>
kubectl create secret tls my-tls-secret \
  --cert=fullchain.pem \
  --key=server.key \
  --namespace <namespace>

Verify certificate details:

bash
kubectl get secret my-tls-secret -n <namespace> \
  -o jsonpath='{.data.tls\.crt}' | base64 -d | \
  openssl x509 -text -noout
4Update Ingress with correct TLS configuration

Ensure Ingress TLS hosts match rules hosts:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: <namespace>
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com        # Must match rules host
    - www.example.com
    secretName: my-tls-secret
  rules:
  - host: example.com    # Must match tls hosts
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80

Apply and verify:

bash
kubectl apply -f ingress.yaml
kubectl describe ingress my-ingress -n <namespace>
5Use cert-manager for automatic certificates

Install cert-manager and configure Let's Encrypt:

bash
# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

Create ClusterIssuer:

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

Add annotation to Ingress:

yaml
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod

cert-manager will automatically create and renew the TLS secret.

6Debug and validate TLS configuration

Verify certificate is being served correctly:

bash
# Check ingress controller logs
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep -i tls

# Test TLS connection
curl -kv https://<ingress-ip> -H "Host: example.com"

# Verify certificate matches private key
kubectl get secret my-tls-secret -n <namespace> \
  -o jsonpath='{.data.tls\.crt}' | base64 -d | \
  openssl x509 -noout -modulus | openssl md5

kubectl get secret my-tls-secret -n <namespace> \
  -o jsonpath='{.data.tls\.key}' | base64 -d | \
  openssl rsa -noout -modulus | openssl md5
# Both MD5 hashes should match

Advanced notes

cert-manager Best Practices:
- Always test with Let's Encrypt staging first: https://acme-staging-v02.api.letsencrypt.org/directory
- Use a monitored email address for renewal notifications
- Let cert-manager manage secrets; avoid manual modifications
- Monitor Certificate status: kubectl describe certificate <name>

Common cert-manager Issues:
- Incorrect ACME URL (use acme-v02, not acme-v2)
- Challenge failures—ensure domain resolves to cluster IP
- Rate limiting—Let's Encrypt has strict limits; use staging for testing
- Secret name conflicts—use unique names for Ingress TLS vs issuer privateKeySecretRef

Namespace Isolation: TLS secrets must be in the same namespace as the Ingress. Cross-namespace references are not supported. For multi-namespace setups, either create secrets in each namespace or use cert-manager's Certificate resource per namespace.

Frequently asked questions

What does "TLS secret not found" mean?
secretName field. Without this secret, the Ingress cannot serve HTTPS traffic and may fall back to serving a self-signed certificate or fail entirely. key (the private key).
How do I fix "TLS secret not found"?
This error occurs when an Ingress resource references a TLS secret that doesn't exist or is misconfigured. Fix it by creating the TLS secret in the correct namespace with proper certificate format, or configure cert-manager for automatic certificate management.
What causes "TLS secret not found"?
TLS secret doesn't exist in the Ingress namespace Secret type is not kubernetes.io/tls (e.g., Opaque) Secret missing required keys tls.crt or tls.key
Is the "TLS secret not found" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading