Kubernetes ConfigMaps and Secrets Managing App Settings

Every application needs configuration — database hostnames, feature flags, API endpoints, and credentials. Hardcoding these values inside your container image is a bad idea because you would need a different image for each environment. ConfigMaps and Secrets let you store configuration separately from your application code and inject it at runtime.

The Core Idea: Separate Config from Code

Think of a hotel room minibar menu. The menu (configuration) is separate from the food items (your application). The hotel changes prices on the menu without replacing the food. You change ConfigMaps without rebuilding the container image.

Container Image (code)  +  ConfigMap (settings)  =  Running Application
      Same image               Different per env        Different behavior

ConfigMaps: Non-Sensitive Configuration

A ConfigMap stores plain-text, non-sensitive configuration data as key-value pairs. Use it for settings like database hostnames, log levels, feature toggle flags, or API endpoint URLs.

Creating a ConfigMap from Literal Values

kubectl create configmap app-config \
  --from-literal=LOG_LEVEL=info \
  --from-literal=DB_HOST=mysql.default.svc.cluster.local \
  --from-literal=MAX_CONNECTIONS=50

Creating a ConfigMap from a YAML File

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  LOG_LEVEL: "info"
  DB_HOST: "mysql.default.svc.cluster.local"
  MAX_CONNECTIONS: "50"
  app.properties: |
    feature.dark-mode=true
    feature.beta-signup=false

ConfigMaps can hold individual key-value pairs or entire file contents (like properties files or configuration JSON).

Using ConfigMaps in Pods

You can inject ConfigMap data into a Pod in two ways: as environment variables or as files mounted into the container filesystem.

Method 1: Environment Variables

spec:
  containers:
  - name: app
    image: my-app:v1
    envFrom:
    - configMapRef:
        name: app-config

This injects every key from the ConfigMap as an environment variable. Your app reads LOG_LEVEL, DB_HOST, and MAX_CONNECTIONS as environment variables.

Method 2: Volume Mount (File-Based)

spec:
  volumes:
  - name: config-volume
    configMap:
      name: app-config
  containers:
  - name: app
    image: my-app:v1
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config

Each key in the ConfigMap becomes a file under /etc/config/. The file's content is the key's value. Your app reads configuration by reading files — useful for apps that expect config files rather than environment variables.

Secrets: Sensitive Data

Secrets work exactly like ConfigMaps but store sensitive data — passwords, API keys, TLS certificates, SSH keys. Kubernetes stores Secrets as base64-encoded strings (not encrypted by default, but the encoding prevents accidental exposure in logs).

Base64 encoding is not encryption. Anyone with access to the Secret object can decode the value. Combine Secrets with RBAC to control who can read them, and use external secret managers (like HashiCorp Vault or AWS Secrets Manager) for higher security requirements.

Creating a Secret

kubectl create secret generic db-credentials \
  --from-literal=DB_USER=admin \
  --from-literal=DB_PASSWORD=SuperSecretPass123

Secret YAML (values must be base64-encoded)

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  DB_USER: YWRtaW4=          # base64 of "admin"
  DB_PASSWORD: U3VwZXJTZWNyZXRQYXNzMTIz  # base64 of password

To generate base64 encoding in your terminal:

echo -n "admin" | base64
# Output: YWRtaW4=

Using Secrets as Environment Variables

spec:
  containers:
  - name: app
    image: my-app:v1
    env:
    - name: DATABASE_USER
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: DB_USER
    - name: DATABASE_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: DB_PASSWORD

Using Secrets as Mounted Files

spec:
  volumes:
  - name: secret-volume
    secret:
      secretName: db-credentials
  containers:
  - name: app
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true

The password file appears at /etc/secrets/DB_PASSWORD with restricted permissions. Applications that handle TLS certificates use this pattern frequently.

ConfigMap vs. Secret: Quick Comparison

FeatureConfigMapSecret
Data typePlain textbase64-encoded
Use forConfig, flags, URLsPasswords, tokens, certs
Stored in etcdPlain textbase64 (enable etcd encryption for production)
Injection methodsEnv vars, volume filesEnv vars, volume files

Updating ConfigMaps and Secrets

When you update a ConfigMap mounted as a volume, Kubernetes automatically refreshes the files inside the running container within about 60 seconds. Environment variables do not update until the Pod restarts. For apps that read config files at startup only, a Pod restart is still required after an update.

Best Practices

  • Never put passwords or API keys inside your container image or Dockerfile.
  • Always use Secrets for sensitive data, never ConfigMaps.
  • Enable etcd encryption at rest in production clusters.
  • Use RBAC to restrict which service accounts can read which Secrets.
  • Consider external secret management tools (Vault, AWS Secrets Manager) for advanced security requirements.

Leave a Comment