ConfigMap vs Secret
Key Differences in Kubernetes
ConfigMaps store non-sensitive configuration data like feature flags, config files, and environment variables in plain text. Secrets store sensitive data like passwords, tokens, and TLS certificates with base64 encoding and additional access controls. Both inject configuration into Pods, but Secrets provide extra safeguards for sensitive information.
Side-by-Side Comparison
| Dimension | ConfigMap | Secret |
|---|---|---|
| Data Sensitivity | Non-sensitive configuration data | Sensitive data — passwords, tokens, keys, certificates |
| Encoding | Stored in plain text | Stored as base64-encoded values (not encrypted by default) |
| Encryption at Rest | Not encrypted in etcd by default | Can be encrypted at rest in etcd via EncryptionConfiguration |
| Size Limit | 1 MiB per ConfigMap | 1 MiB per Secret |
| RBAC | Standard RBAC — often broadly accessible | Should have tighter RBAC — restrict who can read Secrets |
| Mounting | Mounted as files or injected as environment variables | Mounted as files or injected as environment variables; files get 0644 permissions by default |
| kubectl Output | Values shown in plain text with kubectl get -o yaml | Values shown as base64 in kubectl get -o yaml |
| Built-in Types | Single generic type (Opaque) | Multiple types: Opaque, kubernetes.io/tls, kubernetes.io/dockerconfigjson, etc. |
Detailed Breakdown
Creating ConfigMaps and Secrets
# ConfigMap — plain text configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
config.yaml: |
server:
port: 8080
timeout: 30s
features:
caching: true
# Secret — sensitive data (values are base64 encoded)
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM=
API_KEY: c2VjcmV0LWtleS12YWx1ZQ==
You can also create Secrets with stringData to avoid base64 encoding yourself — Kubernetes encodes it for you:
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
stringData:
DB_PASSWORD: "password123"
API_KEY: "secret-key-value"
Injecting Into Pods
Both ConfigMaps and Secrets can be consumed as environment variables or mounted as files.
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app:1.0.0
env:
# From ConfigMap
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
# From Secret
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: DB_PASSWORD
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
- name: secret-volume
secret:
secretName: app-secrets
When mounted as volumes, each key becomes a file. The ConfigMap file at /etc/config/config.yaml contains the YAML content. The Secret files at /etc/secrets/DB_PASSWORD contain the decoded value.
Base64 Is Not Encryption
A critical point for interviews: base64 encoding is not a security mechanism. Anyone with access to the Secret resource can decode the values trivially:
echo "cGFzc3dvcmQxMjM=" | base64 -d
# Output: password123
Base64 exists so that Secrets can hold binary data (like TLS certificates) in a JSON/YAML format. It does not protect the data.
Encryption at Rest
By default, Secrets are stored as plain base64 in etcd — anyone with etcd access can read them. To actually encrypt Secrets in etcd, you configure an EncryptionConfiguration on the API server:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-key>
- identity: {}
This encrypts Secret data before it is written to etcd. ConfigMaps do not typically get this treatment, which is another reason to use Secrets for sensitive data — the ecosystem is designed to add layers of protection around them.
RBAC Considerations
In production, you should restrict Secret access with RBAC:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
resourceNames: ["app-secrets"]
This grants read access to only the specific Secret named app-secrets. ConfigMaps are often less restricted because they do not contain sensitive data.
Secret Types
Kubernetes has built-in Secret types that add validation:
# TLS Secret
apiVersion: v1
kind: Secret
metadata:
name: tls-cert
type: kubernetes.io/tls
data:
tls.crt: <base64-cert>
tls.key: <base64-key>
# Docker registry credentials
apiVersion: v1
kind: Secret
metadata:
name: registry-creds
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-docker-config>
ConfigMaps have no type system — they are all generic key-value stores.
Automatic Updates
When a ConfigMap or Secret is mounted as a volume, Kubernetes periodically syncs the file content (the default kubelet sync period is about 60 seconds). This means you can update a ConfigMap and the mounted files will eventually reflect the change without restarting the Pod.
However, environment variables are set at Pod startup and never updated. If you inject a ConfigMap or Secret value as an env var, you must restart the Pod to pick up changes.
External Secret Management
For production environments, many teams avoid storing sensitive values in Kubernetes Secrets directly. Instead, they use external secret managers:
- Secrets Store CSI Driver — mounts secrets from HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault as files in Pods
- External Secrets Operator — syncs secrets from external providers into Kubernetes Secret objects
- Sealed Secrets — encrypts Secrets so they can be safely committed to Git
These tools treat Kubernetes Secrets as a delivery mechanism while keeping the source of truth in a dedicated secrets manager with audit logging, rotation, and fine-grained access control.
Use ConfigMap when...
- •Storing application configuration files (nginx.conf, application.yml)
- •Setting non-sensitive environment variables like LOG_LEVEL or FEATURE_FLAGS
- •Sharing configuration across multiple Pods in the same namespace
- •Providing command-line arguments or config files to containers
Use Secret when...
- •Storing database passwords and connection strings
- •Managing TLS certificates and private keys
- •Storing Docker registry credentials for image pulls
- •Managing API tokens and OAuth client secrets
- •Any data that should not appear in logs or version control
Model Interview Answer
“ConfigMaps and Secrets both inject configuration into Pods via environment variables or volume mounts. The key difference is intent and safeguards. ConfigMaps are for non-sensitive data like config files and feature flags, stored in plain text. Secrets are for sensitive data like passwords and TLS certificates. Secrets are base64-encoded in the API and can be encrypted at rest in etcd with EncryptionConfiguration. They also support tighter RBAC policies and are not printed in kubectl describe output. However, base64 is not encryption — you should enable encryption at rest and consider external secret managers like HashiCorp Vault or the Secrets Store CSI driver for production environments.”