How do ConfigMaps and Secrets differ, and when should you use each?
Quick Answer
ConfigMaps store non-sensitive configuration data as plaintext key-value pairs. Secrets store sensitive data (passwords, tokens, certificates) as base64-encoded values with restricted access via RBAC. Both inject configuration into pods as environment variables or mounted files, but Secrets get additional protections like memory-only storage on nodes.
Detailed Answer
Think of ConfigMaps and Secrets like the difference between a restaurant's public menu (ConfigMap) and the combination to the safe in the back office (Secret). Everyone can see the menu, it changes regularly, and it tells you what's available. The safe combination is shared only with authorized managers, stored separately from the menu, and handled with extra care. Both are 'configuration' for how the restaurant operates, but they require different levels of protection.
ConfigMaps store non-sensitive configuration data: application settings, feature flags, configuration file contents, environment-specific parameters like database hostnames (without credentials), log levels, and timeout values. They are stored in etcd as plaintext and are visible to anyone with read access to the namespace. You would use a ConfigMap for things like DATABASE_HOST=postgres.production.svc, LOG_LEVEL=info, or an entire nginx.conf file mounted as a volume.
Secrets store sensitive data: database passwords, API keys, TLS certificates, OAuth tokens, and SSH keys. They are base64-encoded (not encrypted by default!) in etcd, but have several additional protections: RBAC can restrict Secret access separately from other resources, Secrets are stored in tmpfs (memory-only) on nodes rather than written to disk, they can be configured for encryption-at-rest in etcd via EncryptionConfiguration, and kubectl get secrets does not display their values by default. It is critical to understand that base64 encoding is NOT encryption -- anyone who can read the Secret object can decode it trivially.
In production, the choice is straightforward: if leaking the value would be a security incident, it goes in a Secret. If it would merely be inconvenient or confusing, it goes in a ConfigMap. However, many teams go further and integrate external secret managers (HashiCorp Vault, AWS Secrets Manager) using the External Secrets Operator, which creates Kubernetes Secrets from external sources. This provides actual encryption, rotation, and audit logging that native Kubernetes Secrets lack.
A common gotcha: when you update a ConfigMap, pods mounting it as a volume see the change within 1-2 minutes (kubelet sync period), but pods using it as environment variables do NOT see the change until they are restarted. This catches many teams off guard. A pattern to force restarts is adding a ConfigMap hash annotation to the pod template so that changes trigger a rolling update. Secrets behave the same way regarding volume mounts vs environment variables.