A Secret holds a small amount of sensitive data (tokens, keys, passwords) so you do not embed it in Pod specs or container images. Secrets can be managed and audited separately from workload manifests.
ConfigMaps hold non-secret configuration; Secrets are intended for confidential data. Kubernetes defines several built-in Secret types. The kubernetes.io/tls type stores a TLS certificate and private key, typically for Ingress TLS termination or for mounting into an application that speaks TLS directly.
This guide shows how to:
- Generate a self-signed certificate for labs (production should use a public CA, internal PKI, or automation such as cert-manager).
- Create a TLS Secret with
kubectl, declarative YAML (stringDataordata), and Terraform. - Reference the Secret from an Ingress and avoid common base64 mistakes.
The Kubernetes API does not fully validate that tls.crt and tls.key match or form a valid chain; bad material usually shows up when the Ingress controller or your app loads the cert.
Prerequisites
- A running cluster and
kubectlconfigured (kubectl cluster-info). opensslfor the examples that generate local test keys.
Generate test certificate and key (OpenSSL)
For learning, you can create a self-signed certificate. In production, keep private keys off shared laptops, use short-lived certs where possible, and rotate on compromise.
Interactive (prompts for DN)
| |
Non-interactive with subject (Common Name)
| |
Modern clients and Ingress controllers often require Subject Alternative Names (SANs). A minimal self-signed cert with SAN:
| |
If your OpenSSL build does not support -addext, use a small config file with [ v3_req ] and subjectAltName instead.
You will pass example.crt (certificate) and example.key (private key) into the Secret. Never commit real keys to public Git repositories.
Create a TLS Secret with kubectl
The TLS pair must exist on disk first.
| |
Verify:
| |
Expected TYPE: kubernetes.io/tls, DATA: 2 (tls.crt and tls.key).
Inspect (values in data are base64-encoded on output):
| |
Remove:
| |
Create the same Secret from YAML
You can use kubectl apply -f or kubectl create -f.
Prefer stringData (PEM pasted as plain text)
Kubernetes encodes stringData to data for you. Include the full PEM, including the BEGIN / END lines—those lines are part of the standard PEM format.
| |
Apply:
| |
Git / security: If you version this file, use a private repo, SOPS, Sealed Secrets, External Secrets, or sync from a vault—never store production keys in cleartext in shared revision control.
Using data (base64-encoded PEM)
The data map must contain base64-encoded bytes of the entire PEM file (again including BEGIN/END lines). One-line encoding in the shell:
| |
That prints a valid manifest with data populated; you can save and edit it. To encode manually:
| |
Paste each output as a single line under tls.crt and tls.key in data:.
Correction vs. older tutorials: Kubernetes TLS Secrets store PEM material (as base64 in data). You do not strip the -----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- lines, and you are not switching to “raw DER only” unless your material is actually DER.
Use the Secret on an Ingress
A typical Ingress references the TLS secret by name:
| |
Replace your-service, hostnames, and paths to match your app. Controllers such as ingress-nginx or others use secretName to load the cert for HTTPS.
For production Let’s Encrypt-style automation on Kubernetes, cert-manager usually creates and renews these Secrets for you—see Kubernetes Nginx Ingress in AWS with Certbot / Let’s Encrypt for related patterns.
Create the TLS Secret with Terraform
The data attribute of kubernetes_secret expects base64-encoded strings (same as the API). Pass PEM file contents through base64encode(file(...)) or use filebase64:
| |
Notes:
- Use
type = "kubernetes.io/tls"(not a shortened alias) for clarity. - Do not put raw
file()PEM strings intodatawithout encoding; the API will reject or mis-handle them. - Point
provider "kubernetes"at the right kubeconfig or in-cluster credentials for your environment.
Operations and troubleshooting
| Topic | Guidance |
|---|---|
| Wrong namespace | TLS Secrets are namespaced. Create the Secret in the same namespace as the Ingress (or the workload that mounts it). |
| Certificate mismatch | tls.crt must match the private key in tls.key; hostname/SAN should match URLs clients use. |
kubectl create secret tls errors | Check file paths; ensure the key is RSA/EC PEM the controller accepts. |
| Rotation | Update cert/key and replace the Secret (same name) or create a new Secret and switch secretName, then roll Ingress/controller if needed. |
| Immutability | You can mark Secrets immutable for drift prevention (separate from TLS type); rotation then requires a name or version bump strategy. |
Decode what is stored (local shell only, handle with care):
| |
Related content
- Getting started with Kubernetes – Kubernetes components
- Kubernetes Nginx Ingress in AWS with Certbot / Let’s Encrypt
- Working with Kubernetes Jobs and CronJobs
- Ingress TLS documentation
Conclusion
kubernetes.io/tls Secrets bundle tls.crt and tls.key for Ingress and workloads. The fastest paths are kubectl create secret tls or YAML with stringData and full PEM blocks. In Terraform, filebase64 (or base64encode(file(...))) matches what the Kubernetes API expects. For production clusters, pair this knowledge with cert-manager or your PKI so issuance and renewal stay automated.