Kubernetes ConfigMaps and Secrets

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Kubernetes ConfigMaps and Secrets

ConfigMaps store configuration data while Secrets handle sensitive information. Learn best practices for both.

Introduction

Applications need configuration and secrets. Kubernetes provides ConfigMaps for non-sensitive configuration and Secrets for sensitive data.

ConfigMaps

Store configuration data as key-value pairs.

Creating ConfigMaps

# From literal values
kubectl create configmap app-config \
  --from-literal=DATABASE_HOST=postgres.example.com \
  --from-literal=DATABASE_PORT=5432 \
  --from-literal=LOG_LEVEL=info

# From file
kubectl create configmap app-config --from-file=config/app.conf

# From directory
kubectl create configmap app-config --from-file=config/

ConfigMap in YAML

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: postgres.example.com
  DATABASE_PORT: "5432"
  LOG_LEVEL: info
  app.conf: |
    server {
      listen 80;
      server_name localhost;
    }

Using ConfigMaps in Pods

Environment Variables

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: DATABASE_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_HOST
    - name: DATABASE_PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_PORT

All ConfigMap as Environment

envFrom:
- configMapRef:
    name: app-config

Volume Mount

apiVersion: v1
kind: Pod
metadata:
  name: app-with-config
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: config
      mountPath: /etc/config
      readOnly: true

  volumes:
  - name: config
    configMap:
      name: app-config

Files available in /etc/config:

/etc/config/DATABASE_HOST
/etc/config/DATABASE_PORT
/etc/config/LOG_LEVEL
/etc/config/app.conf

Secrets

Store sensitive data securely.

Secret Types

Opaque (default): Base64-encoded arbitrary data

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  username: cG9zdGdyZXM=  # base64-encoded 'postgres'
  password: c2VjcmV0MTIz  # base64-encoded 'secret123'

Docker Registry: Credentials for pulling images

apiVersion: v1
kind: Secret
metadata:
  name: regcred
type: kubernetes.io/dockercfg
data:
  .dockercfg: <base64-encoded-docker-config>

BasicAuth: Username and password

apiVersion: v1
kind: Secret
metadata:
  name: basic-auth
type: kubernetes.io/basic-auth
data:
  username: YWRtaW4=
  password: YWRtaW4xMjM=

Creating Secrets

# From literal values
kubectl create secret generic db-credentials \
  --from-literal=username=postgres \
  --from-literal=password=secretpassword

# From files
kubectl create secret generic api-keys \
  --from-file=api-key.txt

# Docker registry secret
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass \
  --docker-email=user@example.com

Using Secrets in Pods

Environment Variables

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    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

Volume Mount

apiVersion: v1
kind: Pod
metadata:
  name: app-with-secrets
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: secrets
      mountPath: /etc/secrets
      readOnly: true

  volumes:
  - name: secrets
    secret:
      secretName: db-credentials

Files available:

/etc/secrets/username
/etc/secrets/password

Pull Private Images

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  imagePullSecrets:
  - name: regcred

  containers:
  - name: app
    image: registry.example.com/myapp:1.0

Best Practices

Encryption at Rest

Enable encryption for secrets:

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

Start API server with flag:

--encryption-provider-config=/etc/kubernetes/encryption-config.yaml

Use Sealed Secrets

For GitOps, use sealed secrets:

# Install sealed-secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/controller.yaml

# Seal a secret
echo -n mypassword | kubectl create secret generic mysecret --from-file=/dev/stdin --dry-run=client -o yaml | kubeseal -f -

# Save sealed secret to repo
# Unsealed only in cluster

RBAC for Secrets

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

External Secret Management

Using Vault

apiVersion: v1
kind: Pod
metadata:
  name: app-with-vault
spec:
  serviceAccountName: myapp

  initContainers:
  - name: vault-init
    image: vault:latest
    env:
    - name: VAULT_ADDR
      value: http://vault:8200
    command:
    - sh
    - -c
    - |
      vault kv get -field=password secret/database > /vault/secrets/db-password

    volumeMounts:
    - name: vault-token
      mountPath: /vault/secrets

  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password

  volumes:
  - name: vault-token
    emptyDir: {}

AWS Secrets Manager

apiVersion: v1
kind: ServiceAccount
metadata:
  name: myapp
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT_ID:role/MyAppRole

---
apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  serviceAccountName: myapp
  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: DB_PASSWORD
      value: /var/run/secrets/db-password

    command:
    - sh
    - -c
    - |
      aws secretsmanager get-secret-value --secret-id db-password --query SecretString --output text > /var/run/secrets/db-password
      node server.js

Comparison

AspectConfigMapSecret
Use CaseNon-sensitive configSensitive data
Size Limit1 MB1 MB
Access ControlRBACRBAC + encryption
EncodingPlain textBase64
VisibilityLess restrictedMore restricted

FAQ

Q: Are Secrets encrypted by default? A: Base64-encoded yes, encrypted no. Enable encryption at rest for production. Base64 is encoding, not encryption.

Q: Can I mix ConfigMaps and Secrets in one Pod? A: Yes. Use ConfigMaps for config, Secrets for passwords/keys. Both can be in same Pod.

Q: How do I rotate Secrets? A: Update the Secret, then restart Pods using it. Use rolling updates to minimize downtime.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro