A kubernetes.io/tls Secret must contain the keys tls.crt and tls.key, and the API server verifies those keys exist. It does not validate that the values are real, matching or unexpired. Create it with kubectl, then check the pair yourself, because a bad Secret only fails when something tries to use it.
What the type is for
The Kubernetes documentation says the TLS Secret type stores a certificate and its associated key, typically used for TLS. A common use is encryption in transit for an Ingress, but you can also use it with other resources or directly in a workload.
It is a convenience. You could use an Opaque Secret for TLS credentials, but the documentation says using the defined, public type helps keep the format consistent across your project.
What is and is not checked
| Check | Done by the API server |
|---|---|
| tls.crt key present | Yes |
| tls.key key present | Yes |
| Value is a valid PEM | No, per the documentation |
| Certificate matches the key | No |
| Certificate is unexpired | No |
| Chain is complete | No |
The documentation says the API server verifies that the required keys are set for this type, and states that it does not actually validate the values for each key. The rows beyond presence follow directly from that statement.
Creating one correctly
The documented command uses the tls subcommand of kubectl create secret, with the certificate file and the key file as arguments. The key pair must exist beforehand. The public key certificate must be PEM encoded and must match the given private key.
kubectl create secret tls my-tls-secret \
--cert=path/to/cert/file \
--key=path/to/key/file
If you write a manifest by hand, you can use the data field with base64 encoded values, or stringData with plain text. Treat the manifest as sensitive either way. See Kubernetes Secrets and base64.
Validate before you ship
Because Kubernetes will accept junk, add your own checks in CI or a deploy step.
- Confirm the certificate parses and has not expired. See checking expiry with openssl.
- Confirm the public key in the certificate matches the private key.
- Include the intermediate certificates in tls.crt after the leaf, so clients can build the chain. See incomplete chains that work in browsers but fail in curl.
- Check the SAN list covers every hostname that will use it. See hostname verification and SANs.
- Never commit the key. See what to do when a TLS private key leaks.
Let a manager write it
When cert-manager issues the certificate, it stores the result in the Secret you name, and its docs note that when the issuer provides a chain, tls.crt holds the requested certificate followed by the chain. That removes hand copying and the mismatches it causes. See duration and renewBefore.
Keep updates reaching pods
Updating a Secret does not help if a container mounted it with subPath. See why subPath mounts miss renewals.
Where Safeguard fits
Safeguard does not validate your certificates. It provides SBOM and dependency scanning plus policies and gates that review manifests before they merge. Free scan: gold.safeguard.sh/scan.
Quick check
Does Kubernetes check that the key matches the certificate?
No. The API server only checks that the required keys exist, and does not validate their values.
Can I use an Opaque Secret for TLS?
Yes, but the documentation recommends the defined TLS type for consistent format.
What format must the certificate be?
PEM encoded, and it must match the private key you supply.
Sources
Last reviewed: 19 October 2026.