TechLead
Lesson 8 of 25
5 min read
Cloud & Kubernetes

ConfigMaps and Secrets

Learn how to manage application configuration and sensitive data in Kubernetes using ConfigMaps, Secrets, and external secret managers

Configuration Management in Kubernetes

Kubernetes separates configuration from container images so that your applications remain portable across environments. ConfigMaps store non-confidential configuration data, while Secrets store sensitive information like passwords, tokens, and TLS certificates.

ConfigMaps vs Secrets

  • ConfigMaps: Non-sensitive key-value pairs, config files, or command-line arguments. Stored in plain text in etcd.
  • Secrets: Sensitive data (passwords, API keys, certificates). Base64-encoded in etcd, can be encrypted at rest with KMS.
  • Both: Can be consumed as environment variables, command-line arguments, or volume-mounted files.

ConfigMaps

Creating ConfigMaps

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  # Simple key-value pairs
  DATABASE_HOST: "postgres-service"
  DATABASE_PORT: "5432"
  REDIS_URL: "redis://redis-service:6379"
  LOG_LEVEL: "info"
  MAX_CONNECTIONS: "100"

  # Entire config file as a value
  nginx.conf: |
    server {
      listen 80;
      server_name localhost;
      location / {
        proxy_pass http://api-service:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
      location /health {
        return 200 'OK';
        add_header Content-Type text/plain;
      }
    }

  app-settings.json: |
    {
      "feature_flags": {
        "new_dashboard": true,
        "beta_api": false
      },
      "pagination": {
        "default_page_size": 25,
        "max_page_size": 100
      }
    }
# Create ConfigMap from literal values
kubectl create configmap app-config \
  --from-literal=DATABASE_HOST=postgres-service \
  --from-literal=DATABASE_PORT=5432 \
  --from-literal=LOG_LEVEL=info

# Create ConfigMap from a file
kubectl create configmap nginx-config --from-file=nginx.conf

# Create ConfigMap from a directory (each file becomes a key)
kubectl create configmap app-configs --from-file=./config/

# View ConfigMap
kubectl get configmap app-config -o yaml
kubectl describe configmap app-config

Using ConfigMaps in Pods

# pod-with-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: api-pod
spec:
  containers:
  - name: api
    image: myapp:1.0
    # Method 1: Individual environment variables
    env:
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_HOST
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_PORT

    # Method 2: All keys as environment variables
    envFrom:
    - configMapRef:
        name: app-config
      prefix: APP_    # Optional: adds prefix to all keys

    # Method 3: Mount as files in a volume
    volumeMounts:
    - name: config-volume
      mountPath: /etc/nginx/conf.d
      readOnly: true
    - name: app-settings
      mountPath: /app/config
      readOnly: true

  volumes:
  - name: config-volume
    configMap:
      name: app-config
      items:
      - key: nginx.conf
        path: default.conf   # Rename the file
  - name: app-settings
    configMap:
      name: app-config
      items:
      - key: app-settings.json
        path: settings.json

Secrets

Creating Secrets

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: production
type: Opaque
data:
  # Values must be base64-encoded
  username: YWRtaW4=           # echo -n 'admin' | base64
  password: c3VwZXJTZWNyZXQxMjM=  # echo -n 'superSecret123' | base64
  connection-string: cG9zdGdyZXM6Ly9hZG1pbjpzdXBlclNlY3JldDEyM0Bwb3N0Z3Jlcy1zZXJ2aWNlOjU0MzIvbXlkYg==
---
# TLS Secret for HTTPS
apiVersion: v1
kind: Secret
metadata:
  name: tls-secret
type: kubernetes.io/tls
data:
  tls.crt: LS0tLS1CRUdJTi...  # base64-encoded certificate
  tls.key: LS0tLS1CRUdJTi...  # base64-encoded private key
---
# Docker registry credentials
apiVersion: v1
kind: Secret
metadata:
  name: registry-credentials
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: eyJhdXRocyI6ey...  # base64-encoded Docker config
# Create a Secret from literal values
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=superSecret123

# Create a TLS Secret
kubectl create secret tls tls-secret \
  --cert=path/to/tls.crt \
  --key=path/to/tls.key

# Create Docker registry Secret
kubectl create secret docker-registry registry-credentials \
  --docker-server=ghcr.io \
  --docker-username=myuser \
  --docker-password=mytoken

# View Secret (values are base64-encoded)
kubectl get secret db-credentials -o yaml

# Decode a Secret value
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 --decode

Using Secrets in Pods

# pod-with-secrets.yaml
apiVersion: v1
kind: Pod
metadata:
  name: api-pod
spec:
  containers:
  - name: api
    image: myapp:1.0
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password
    volumeMounts:
    - name: tls-certs
      mountPath: /etc/tls
      readOnly: true
  volumes:
  - name: tls-certs
    secret:
      secretName: tls-secret
  imagePullSecrets:
  - name: registry-credentials

External Secret Management

For production environments, Kubernetes Secrets alone may not be sufficient since they are only base64-encoded (not encrypted by default). Use external secret managers like AWS Secrets Manager, HashiCorp Vault, or Google Secret Manager with the External Secrets Operator.

# external-secret.yaml (using External Secrets Operator)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
  - secretKey: username
    remoteRef:
      key: production/database
      property: username
  - secretKey: password
    remoteRef:
      key: production/database
      property: password

Key Takeaways

  • ConfigMaps store non-sensitive configuration; Secrets store sensitive data
  • Both can be consumed as environment variables or volume-mounted files
  • Secrets are base64-encoded, not encrypted — enable encryption at rest in production
  • Use External Secrets Operator with cloud secret managers for production-grade secret management
  • Never commit Secret manifests with real values to version control

Continue Learning