What is the difference between ConfigMap and Secret, and when do you use each?
Quick Answer
ConfigMaps store non-sensitive configuration (URLs, feature flags, config files) as plain text. Secrets store sensitive data (passwords, tokens, TLS keys) with base64 encoding and optional encryption at rest. Both inject configuration into Pods without baking it into container images.
Detailed Answer
Think of ConfigMaps and Secrets like two types of documents in a company. ConfigMaps are like the employee handbook posted on the break room wall — useful information (office hours, WiFi password for guests, printer IP addresses) that anyone can read without concern. Secrets are like the HR folder locked in the filing cabinet — social security numbers, salary details, building alarm codes — information that must be restricted because exposure causes real damage. Both serve the same purpose (providing information to employees) but require very different handling.
ConfigMaps hold non-sensitive configuration that your application needs to function: database hostnames (not passwords), feature flags, logging levels, connection pool sizes, timeout values, or entire configuration files (nginx.conf, application.properties). They're stored in etcd as plain text, fully visible in kubectl get configmap -o yaml, and anyone with RBAC read access to the namespace can see their contents. You inject them into Pods either as environment variables (individual keys) or as volume mounts (entire ConfigMap as a directory of files). The volume mount approach is powerful because Kubernetes automatically propagates updates: when you change a ConfigMap value, mounted files update within 30-60 seconds (the kubelet sync period) without Pod restarts.
Secrets store sensitive data: database passwords, API tokens, TLS certificates and private keys, SSH keys, OAuth client secrets. Structurally, Secrets are nearly identical to ConfigMaps — they're key-value pairs stored in etcd. The differences are: (1) values are base64 encoded (this is NOT encryption — it's just encoding to handle binary data safely in YAML), (2) they're excluded from kubectl get secret output by default (you must add -o yaml to see values), (3) when mounted as volumes, they use tmpfs (in-memory filesystem) so they're never written to the node's physical disk, and (4) Kubernetes RBAC allows separate permissions for Secret access versus ConfigMap access, so you can grant wide ConfigMap read access while restricting Secret access to specific ServiceAccounts.
The types of Secrets matter in practice. Opaque (default — arbitrary key-value pairs), kubernetes.io/tls (TLS certificate and key — validated structure), kubernetes.io/dockerconfigjson (registry credentials for image pulling), kubernetes.io/service-account-token (auto-generated tokens for ServiceAccount authentication). Using the correct type enables Kubernetes to validate the Secret's structure and use it automatically in the right contexts.
The environment variable vs. volume mount decision has production implications. Environment variables are simpler but: they're visible in kubectl describe pod, they can leak into crash dumps and child processes, they're frozen at Pod startup (never updated without restart), and some frameworks log all env vars at startup. Volume mounts are slightly more complex but: they auto-update without restarts, they can have file permissions set (mode 0400 for secrets), and they don't leak through describe or process listings.
The most critical misconception: Secrets are NOT encrypted by default. Base64 is just encoding — anyone who runs echo 'cGFzc3dvcmQ=' | base64 -d gets your password instantly. For real security, you need: (1) etcd encryption at rest (EncryptionConfiguration), (2) RBAC restricting Secret read access, (3) audit logging to track who reads Secrets, and (4) ideally an external secrets manager (HashiCorp Vault, AWS Secrets Manager with External Secrets Operator) that stores actual values outside the cluster entirely.