ConfigMaps and Secrets: Managing Application Configuration in Kubernetes

Inject configuration data and sensitive information into Kubernetes pods using ConfigMaps and Secrets. Learn about mounting strategies, environment variables, and security best practices.

published: reading time: 19 min read author: GeekWorkBench

ConfigMaps and Secrets: Managing Application Configuration in Kubernetes

Applications need configuration. Database URLs, feature flags, API keys, and connection strings change between environments. Hardcoding these values into container images defeats the purpose of containerization. Kubernetes provides two resources for injecting configuration into pods: ConfigMap and Secret.

This post explains how to create these resources, inject them into pods, and use them securely.

For Kubernetes basics, see the Kubernetes fundamentals post. For advanced patterns like external secret operators, read the Advanced Kubernetes post.

Introduction

ConfigMaps and Secrets feed configuration into your Kubernetes containers. ConfigMaps handle the boring stuff — feature flags, environment-specific settings, config files. Secrets handle the stuff you do not want in plaintext: database passwords, API keys, TLS certs. Both mount into pods as environment variables or files.

The line between them blurs in dev. It sharpens in production. Native Kubernetes Secrets are just base64-encoded in etcd — no encryption by default, and anyone with cluster access can decode them. ConfigMaps are stored in plaintext everywhere. If you are running regulated workloads (PCI, HIPAA, anything with serious compliance requirements), you need to harden both before they touch production.

This post covers the basics: creating and injecting ConfigMaps and Secrets, when to use volume mounts instead of environment variables, and where External Secret Operators fit in. After reading, you will have a config management approach that works across dev, staging, and prod without accidentally leaking anything sensitive.

When to Use / When Not to Use

Use ConfigMaps when

ConfigMaps work well for non-sensitive configuration that changes between environments: feature flags, environment variables, application settings, and configuration files like nginx.conf or config.yaml.

Share ConfigMaps across pods in the same namespace. The key benefit is keeping configuration out of container images so the same image works in dev, staging, and prod.

Use Secrets when

Secrets are for anything that should not appear in plaintext: database passwords, API keys, OAuth tokens, TLS certificates, SSH keys.

Kubernetes stores Secrets as base64-encoded strings in etcd. Without encryption at rest, these are readable by anyone with etcd access. For sensitive production workloads, use External Secret Operators that sync from Vault, AWS Secrets Manager, or similar.

Skip ConfigMaps for

Sensitive data. It is not encrypted by default. If your ConfigMap name ends in _secret or contains passwords, use a Secret instead.

Skip native Kubernetes Secrets for (without encryption at rest)

Highly regulated environments (PCI-DSS, HIPAA) and multi-tenant clusters where you need strict isolation. Enable encryption at rest before using Secrets for anything genuinely sensitive.

ConfigMap/Secret Injection Flow

flowchart TD
    CM[ConfigMap<br/>or Secret] -->|kubectl apply| K8s[Kubernetes API Server]
    K8s -->|Store| etcd[etcd datastore]
    K8s -->|Watch| Pod[Pod with Container]
    Pod -->|Mount as| Volume[/etc/config<br/>or /run/secrets]
    Pod -->|Inject as| EnvVar[Environment<br/>Variables]

Volume mounts update automatically when the ConfigMap or Secret changes. Environment variables do not update after pod start. For dynamic configuration updates, use volume mounts with application-side file watching or SIGHUP reload.

ConfigMap Creation and Usage Patterns

ConfigMaps store non-sensitive configuration as key-value pairs or files. You create them from literal values, files, or directories.

Creating from literals

kubectl create configmap app-config \
  --from-literal=ENVIRONMENT=production \
  --from-literal=LOG_LEVEL=info \
  --from-literal=MAX_CONNECTIONS=100

Creating from a file

kubectl create configmap nginx-config \
  --from-file=nginx.conf

The filename becomes the configmap key. The file contents become the value.

Creating from a directory

kubectl create configmap html-content \
  --from-file=html/

Defining in YAML

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  ENVIRONMENT: "production"
  LOG_LEVEL: "info"
  DATABASE_HOST: "postgres.database.svc.cluster.local"
  DATABASE_PORT: "5432"

Injecting ConfigMap into Pods

You can inject ConfigMap values as environment variables or volume mounts.

Environment variables

apiVersion: v1
kind: Pod
metadata:
  name: web-app
  namespace: production
spec:
  containers:
    - name: web-app
      image: nginx:1.25
      envFrom:
        - configMapRef:
            name: app-config

With envFrom, all keys from the ConfigMap become environment variables. For selective injection, use env:

env:
  - name: LOG_LEVEL
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: LOG_LEVEL
  - name: ENVIRONMENT
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: ENVIRONMENT

Volume mounts

Mount ConfigMap values as files:

apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
    - name: web-app
      image: nginx:1.25
      volumeMounts:
        - name: config
          mountPath: /etc/nginx/conf.d
          readOnly: true
  volumes:
    - name: config
      configMap:
        name: nginx-config
        items:
          - key: nginx.conf
            path: default.conf

With this setup, /etc/nginx/conf.d/default.conf contains the contents of the nginx.conf key from the ConfigMap.

Secrets Types and Limitations

Secrets work like ConfigMaps but store sensitive data. Kubernetes stores Secrets as base64-encoded strings, not encrypted. Anyone with API access or etcd access can read Secrets.

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: production
type: Opaque
data:
  username: cG9zdGdyZXM=
  password: c2VjcmV0cGFzc3dvcmQ=

Generate base64 values:

echo -n "postgres" | base64
echo -n "secretpassword" | base64

Kubernetes Secret types

TypeUse Case
OpaqueArbitrary key-value pairs
kubernetes.io/tlsTLS certificates
kubernetes.io/dockerconfigjsonDocker registry credentials
kubernetes.io/basic-authBasic auth credentials

TLS Secret

apiVersion: v1
kind: Secret
metadata:
  name: tls-cert
  namespace: production
type: kubernetes.io/tls
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...
  tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t...

Mounting vs Environment Variables

Both approaches work, but they have different properties:

AspectEnvironment VariablesVolume Mounts
Update propagationPod must restartFiles update automatically (with sync wave)
VisibilityVisible in kubectl exec outputLess exposed
FormatSingle valuesFiles
Size limitNot suitable for large configsGood for config files

Environment variables work well for simple string values. Volume mounts are better for configuration files, certificates, and other structured data.

For configuration files that change, volume mounts update automatically. Kubernetes syncs the ConfigMap to the volume within a short delay (configurable via ConfigMap data section). Your application needs to watch for file changes or reload on SIGHUP.

External Secret Operators

Kubernetes Secrets have limitations. They are not encrypted by default, they have strict size limits (1MB), and they do not integrate with external secret managers. External Secret Operators bridge this gap.

Tools like External Secrets Operator (ESO), HashiCorp Vault, and AWS Secrets Manager integrate with Kubernetes to sync secrets from external stores.

External Secrets Operator example

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: database-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: db-secrets
    creationPolicy: Owner
  data:
    - secretKey: password
      remoteRef:
        key: production/database
        property: password

This ExternalSecret syncs the password field from the Vault key production/database into a Secret named db-secrets. The Operator handles rotation and updates.

ESO supports AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vault, and other providers.

Security Hardening for Secrets

Since Kubernetes does not encrypt Secrets by default, you need additional measures for sensitive data:

Enable encryption at rest

Configure the kube-apiserver to encrypt Secrets before storing them in etcd:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aesgcm:
          keys:
            - name: key1
              secret: <base64-encoded-32-byte-key>
      - identity: {}

Enable this in the kube-apiserver configuration:

--encryption-provider-config=/path/to/encryption-config

Use RBAC to restrict Secret access

Limit who can read Secrets using Role-Based Access Control:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: secret-reader
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list"]

Enable RBAC authentication

Ensure your kube-apiserver has RBAC enabled:

kubectl get pod kube-apiserver -n kube-system -o jsonpath='{.spec.containers[0].command}' | grep -i rbac

Consider third-party solutions

For production workloads with strict security requirements, use a secrets manager with a Kubernetes operator. Vault, AWS Secrets Manager, and similar tools provide audit logs, secret rotation, and encryption that Kubernetes-native Secrets lack.

Trade-off Analysis

ConfigMap Mounting vs Environment Variables

AspectEnvironment VariablesVolume Mounts
Update propagationRequires pod restartAutomatic update within ~1 minute
Maximum size1MB total per pod env vars1MB per ConfigMap, good for config files
Application supportUniversal — all apps read env varsRequires file-watch or SIGHUP handling
Type safetyString values onlyCan map to JSON, YAML files
VisibilityVisible in kubectl exec outputLess exposed in process arguments

Native Secrets vs External Secret Operators

AspectNative Kubernetes SecretsExternal Secret Operators (ESO)
EncryptionBase64 only, not encrypted by defaultFull encryption with external provider
RotationManual rotation requiredAutomatic sync and rotation from external store
Audit logsNone built-inFull audit trail from the secret manager
Size limit1MB1MB but better distributed across providers
IntegrationNoneVault, AWS SM, Azure KV, GCP SM

ConfigMap Binary Data vs UTF-8 Data

AspectUTF-8 Data (data)Binary Data (binaryData)
EncodingUTF-8 strings directlyBase64-encoded binary content
Use caseConfig files, text valuesTLS certificates, private keys, images
ValidationKubernetes validates as stringNo content validation — you manage encoding
Size limit1MB1MB

YAML vs kubectl create configmap

AspectYAML (kubectl apply)kubectl create commands
Version controlYes — declarative, reviewableImperative — not self-documenting
Drift detectionYesNo
ReusabilityYes — with kustomize/helm overlaysLimited — hard to adapt for different envs
SpeedSlower to typeFaster for quick local dev

For production, use YAML with GitOps workflows. For local development, kubectl create commands are acceptable for temporary ConfigMaps.

Production Failure Scenarios

Secret Not Found at Pod Startup

If a Secret referenced in a pod does not exist when the pod starts, the pod fails to start with SecretNotFound error.

Symptoms: Pod stuck in Pending or ContainerCreating state, Secrets not found in events.

Diagnosis:

kubectl describe pod <pod-name> -n <namespace>
kubectl get secret <secret-name> -n <namespace>

Mitigation: Create Secrets before applying Pods that reference them. Use depends_on in Helm or kustomize to enforce ordering.

ConfigMap Update Not Propagating to Pods

When a ConfigMap is updated, volume-mounted files reflect the change, but environment variables do not update without pod restart.

Symptoms: Application uses stale configuration even after ConfigMap update.

Mitigation: Use volume mounts for configuration that changes at runtime. Implement SIGHUP handling in your application to reload on file change, or restart pods automatically using a tool like Reloader.

Base64 Encoding Errors in Secrets

Kubernetes Secrets store values as base64 strings. If the base64 encoding is wrong (missing padding, wrong characters), the decoded value is corrupted.

Symptoms: Application fails to connect to database with authentication failed, decoded values are garbled.

Mitigation: Always use echo -n "value" | base64 (note the -n to avoid trailing newline) and echo "b64value" | base64 -d for decoding.

Anti-Patterns

Storing Secrets in ConfigMaps

Never store actual secrets (passwords, API keys) in ConfigMaps. ConfigMaps are not encrypted by default and are visible in YAML exports and etcd dumps. Always use Secret resources for sensitive data.

Not Using binaryData for Non-UTF8 Content

ConfigMaps store data as UTF-8 strings. For binary files (certificates, keys), use the binaryData field instead of data and base64-encode the content.

Copying Entire ConfigMap into Every Environment

Different environments (dev, staging, prod) need different configurations. Copying the same ConfigMap across environments leads to hardcoded production URLs in dev or debug flags in production.

Use Kustomize overlays or Helm values to inject environment-specific configuration.

Interview Questions

1. What is the difference between a ConfigMap and a Secret in Kubernetes?

Expected answer points:

  • ConfigMaps store non-sensitive configuration as UTF-8 key-value pairs
  • Secrets store sensitive data (passwords, tokens, keys) but are base64-encoded, not encrypted by default
  • Both are namespaced resources accessible by pod volume mounts or environment variables
  • Secrets should be used for anything that must not appear in plaintext in YAML exports or etcd
2. How do you inject a ConfigMap value as an environment variable in a pod?

Expected answer points:

  • Use `envFrom` with `configMapRef` to inject all keys as environment variables
  • Use `env` with `configMapKeyRef` for selective injection of specific keys
  • Environment variables are set at pod startup — they do not update when the ConfigMap changes
  • For dynamic updates, use volume mounts instead of environment variables
3. What happens when a ConfigMap mounted as a volume is updated?

Expected answer points:

  • Kubernetes syncs the updated ConfigMap to the volume within a short delay (configurable)
  • The application must watch for file changes or reload on SIGHUP signal
  • Environment variables do NOT update without pod restart — volume mounts are required for dynamic updates
  • Tools like Reloader can automate pod restarts when ConfigMaps change
4. Why should you avoid storing Secrets in native Kubernetes Secrets without encryption at rest?

Expected answer points:

  • Kubernetes stores Secrets as base64-encoded strings in etcd — this is not encryption
  • Anyone with etcd access (cluster admin, etcd backup files) can read Secret values
  • Encryption at rest must be explicitly enabled via kube-apiserver encryption configuration
  • For regulated environments (PCI-DSS, HIPAA), native Secrets without encryption are insufficient
5. What is the External Secrets Operator and why would you use it?

Expected answer points:

  • ESO syncs secrets from external secret managers (Vault, AWS SM, Azure KV, GCP SM) into Kubernetes Secrets
  • It provides automatic rotation, audit logs, and encryption that native Secrets lack
  • You define an ExternalSecret resource that references the external store — ESO reconciles them
  • Best practice for production workloads in regulated or multi-tenant environments
6. What is the difference between `data` and `binaryData` fields in a ConfigMap?

Expected answer points:

  • `data` stores UTF-8 string values as-is
  • `binaryData` stores base64-encoded binary content for non-text files like certificates or images
  • If you need to store binary content in `data`, you must base64-encode it yourself
  • `binaryData` is an alternative that Kubernetes handles as raw binary without UTF-8 validation
7. How do you restrict which pods can read a specific Secret using RBAC?

Expected answer points:

  • Create a Role (namespace-scoped) with `get` and `list` verbs on `secrets`
  • Create a ServiceAccount for the pod
  • Create a RoleBinding to associate the ServiceAccount with the Role
  • The pod uses that ServiceAccount via `spec.serviceAccountName`
8. How do you enable encryption at rest for Secrets in etcd?

Expected answer points:

  • Create an EncryptionConfiguration YAML with AES-GCM or another provider
  • Pass the config to kube-apiserver via `--encryption-provider-config` flag
  • All Secrets written to etcd after enabling the provider are encrypted
  • Existing Secrets are not encrypted until they are rewritten (re-created)
9. What are the four built-in Secret types in Kubernetes?

Expected answer points:

  • Opaque — arbitrary key-value pairs (default type)
  • kubernetes.io/tls — TLS certificates and keys
  • kubernetes.io/dockerconfigjson — Docker registry credentials
  • kubernetes.io/basic-auth — basic authentication credentials
10. Why is it bad practice to copy the same ConfigMap across dev, staging, and production environments?

Expected answer points:

  • Dev, staging, and prod have different database URLs, API endpoints, and feature flags
  • Copying the same ConfigMap means production URLs end up in dev, or debug flags in production
  • Use Kustomize overlays or Helm values to inject environment-specific values
  • GitOps workflows should treat ConfigMaps as code with environment-specific variants
11. How do you debug a ConfigMap that is not being injected into a pod correctly?

Expected answer points:

  • Verify the ConfigMap exists in the same namespace as the pod: `kubectl get configmap -n `
  • Check the pod spec references the correct ConfigMap name and injection method (env vs volume)
  • Use `kubectl describe pod ` to see events — look for ConfigMap or Secret not found errors
  • Verify key names match exactly — Kubernetes is case-sensitive for ConfigMap keys
12. What is the maximum size for a ConfigMap and a Secret?

Expected answer points:

  • Both ConfigMaps and Secrets have a maximum size of 1MB
  • For very large configuration files, consider storing them in object storage and pulling them at runtime
  • Large ConfigMaps impact etcd performance and kubectl response times
13. How does a pod access a Secret mounted as a file?

Expected answer points:

  • Secrets mounted as volumes appear as files in the mount directory (default: `/run/secrets`)
  • Each Secret key becomes a file containing the decoded value
  • The mount is `tmpfs` — secrets are never written to disk
  • Files update automatically when the Secret changes (similar to ConfigMap volume mounts)
14. What is the recommended way to handle Secret rotation in Kubernetes?

Expected answer points:

  • Native Kubernetes Secrets do not support automatic rotation — you must manually update and restart pods
  • External Secret Operators can automate rotation by monitoring the external secret store
  • Application must support SIGHUP reload or be restarted when secrets change
  • Use versioned secrets or secret snapshots to avoid breaking running applications during rotation
15. Can you share a ConfigMap across namespaces?

Expected answer points:

  • No — ConfigMaps are namespace-scoped resources
  • To share a ConfigMap across namespaces, you must create identical ConfigMaps in each namespace
  • Operators can replicate ConfigMaps across namespaces if needed
  • Consider an external config store if you need true cross-namespace shared configuration
16. How do you use subPath in a ConfigMap volume mount and what are its limitations?

Expected answer points:

  • subPath allows mounting a single key from a ConfigMap as a specific file without exposing all keys
  • It is useful for mounting config files that conflict with the directory structure of the container
  • The major limitation is that when using subPath, the application does not receive automatic updates when the ConfigMap changes — the pod must be restarted
  • subPath bypasses symlink updates that work with regular volume mounts, making it unsuitable for frequently-updated configuration
17. What are immutable ConfigMaps and when would you use them?

Expected answer points:

  • Set `immutable: true` in the ConfigMap spec to prevent any changes after creation
  • Immutable ConfigMaps have significant performance benefits — Kubernetes skips synchronization for ConfigMaps that cannot change
  • Use for configuration that must never change at runtime (security policies, feature flags, environment defaults)
  • If you need to change an immutable ConfigMap, you must delete and recreate it — there is no update operation
18. How does the size limit of 1MB for ConfigMaps and Secrets affect design decisions?

Expected answer points:

  • 1MB is the total size limit for both ConfigMaps and Secrets — large configurations must be split across multiple resources
  • For application configs exceeding 1MB, consider storing them in object storage (S3, GCS) and pulling at startup or via init container
  • For TLS certificates or binary assets, use `binaryData` field with base64 encoding, but be aware of base64 overhead (~33%)
  • Large ConfigMaps impact etcd performance and kube-apiserver response times — keep ConfigMaps small
19. What is the difference between merging configuration via multiple envFrom declarations versus mounting multiple ConfigMap volumes?

Expected answer points:

  • Multiple `envFrom` entries with different ConfigMaps merge all keys into environment variables — if keys conflict, one overwrites the other (order matters)
  • Multiple volume mounts from different ConfigMaps create separate files in different directories — no merge, no conflict
  • Volume mounts allow files to be updated dynamically; env vars do not update after pod start
  • For config that needs to be updated at runtime, use volumes; for static initialization values, use env vars
20. How do you combine ConfigMaps and Secrets in the same volume mount for a twelve-factor application?

Expected answer points:

  • You can mount both ConfigMaps and Secrets as volumes in the same container, giving the application a unified `/etc/config` or `/run/secrets` directory structure
  • Use projected volumes to combine multiple ConfigMaps and Secrets into a single mount point with specific file permissions
  • Projected volumes allow you to map specific keys from each resource to specific file names, controlling exactly what the application sees
  • This approach separates non-sensitive configuration (ConfigMap) from sensitive data (Secret) while presenting them in a unified file-based interface

Further Reading

Conclusion

Use this checklist when managing ConfigMaps and Secrets:

  • Used ConfigMaps for non-sensitive configuration, Secrets for credentials and keys
  • Mounted ConfigMaps as volumes for configuration files and dynamic updates
  • Injected ConfigMap values as environment variables only for static configuration
  • Enabled encryption at rest for etcd to protect Secret data
  • Used RBAC to restrict who can read Secrets
  • Used External Secret Operators for production workloads requiring audit trails
  • Tested application behavior when ConfigMap or Secret values change at runtime
  • Used binaryData field for non-UTF8 secret content
  • Never committed Secret values to version control
  • Used depends_on or ordering tools to ensure Secrets exist before Pods start

Category

Related Posts

Kustomize: Native Kubernetes Configuration Management

Use Kustomize for declarative Kubernetes configuration management without Helm's templating—overlays, patches, and environment-specific customization.

#kubernetes #kustomize #devops

Container Security: Image Scanning and Vulnerability Management

Implement comprehensive container security: from scanning images for vulnerabilities to runtime security monitoring and secrets protection.

#container-security #docker #kubernetes

Deployment Strategies: Rolling, Blue-Green, and Canary Releases

Compare and implement deployment strategies—rolling updates, blue-green deployments, and canary releases—to reduce risk and enable safe production releases.

#deployment #devops #kubernetes