ConfigMaps + Secrets cheatsheet.

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata: { name: app-config }
data:
  DATABASE_URL: postgres://...
  LOG_LEVEL: info
  config.yaml: |
    server:
      port: 8000
kubectl create configmap app-config \
  --from-literal=LOG_LEVEL=info \
  --from-literal=PORT=8000

kubectl create configmap app-config --from-file=config.yaml
kubectl create configmap app-config --from-env-file=.env

Secret

apiVersion: v1
kind: Secret
metadata: { name: app-secrets }
type: Opaque
stringData:                       # plaintext (auto-encoded)
  DB_PASSWORD: supersecret
  API_KEY: sk-abc
# OR
data:                             # base64 encoded
  DB_PASSWORD: c3VwZXJzZWNyZXQ=
kubectl create secret generic app-secrets \
  --from-literal=DB_PASSWORD=supersecret

kubectl create secret tls web-tls --cert=cert.pem --key=key.pem
kubectl create secret docker-registry ghcr-secret \
  --docker-server=ghcr.io \
  --docker-username=USER \
  --docker-password=TOKEN

Use as env vars

spec:
  containers:
    - name: app
      env:
        - name: LOG_LEVEL
          valueFrom: { configMapKeyRef: { name: app-config, key: LOG_LEVEL } }
        - name: DB_PASSWORD
          valueFrom: { secretKeyRef: { name: app-secrets, key: DB_PASSWORD } }

envFrom

spec:
  containers:
    - name: app
      envFrom:
        - configMapRef: { name: app-config }
        - secretRef: { name: app-secrets }

All keys become env vars.

Use as mounted files

spec:
  containers:
    - name: app
      volumeMounts:
        - name: config
          mountPath: /etc/app
          readOnly: true
        - name: secrets
          mountPath: /etc/app/secrets
          readOnly: true
  volumes:
    - name: config
      configMap: { name: app-config }
    - name: secrets
      secret: { secretName: app-secrets }

Each key becomes a file.

Subpath

volumeMounts:
  - name: config
    mountPath: /etc/app/config.yaml
    subPath: config.yaml

Mount single file (doesn’t auto-update like dir mount).

Specific items

volumes:
  - name: config
    configMap:
      name: app-config
      items:
        - key: config.yaml
          path: app.yaml         # rename

Immutable

apiVersion: v1
kind: ConfigMap
metadata: { name: app-config }
immutable: true
data: { ... }

Can’t update. Force redeploy to change. Better for prod (prevents accidental modification).

Reload on change

Volume-mounted configs update in-place (with ~minute delay). Apps must re-read files.

For env vars: pod must restart. Use:

  • Manually kubectl rollout restart deploy/web.
  • Tools: stakater/reloader.

reloader

helm install reloader stakater/reloader
metadata:
  annotations:
    reloader.stakater.com/auto: "true"

Auto-restarts deploy on ConfigMap / Secret change.

Generic mount permissions

volumes:
  - name: secrets
    secret:
      secretName: app-secrets
      defaultMode: 0400

DockerConfigJson

kubectl create secret docker-registry ghcr \
  --docker-server=ghcr.io \
  --docker-username=USER \
  --docker-password=TOKEN \
  --docker-email=[email protected]
spec:
  imagePullSecrets:
    - name: ghcr

TLS

apiVersion: v1
kind: Secret
metadata: { name: web-tls }
type: kubernetes.io/tls
data:
  tls.crt: ...
  tls.key: ...

External Secrets Operator

For prod, store secrets in Vault / AWS Secrets Manager / GCP Secret Manager:

helm install external-secrets external-secrets/external-secrets
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata: { name: aws-secrets }
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth: { jwt: { serviceAccountRef: { name: external-secrets } } }
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata: { name: app-secrets }
spec:
  refreshInterval: 1m
  secretStoreRef: { name: aws-secrets, kind: SecretStore }
  target: { name: app-secrets }
  data:
    - secretKey: DB_PASSWORD
      remoteRef: { key: prod/db, property: password }

Auto-syncs from AWS to K8s Secret.

sealed-secrets

helm install sealed-secrets sealed-secrets/sealed-secrets
kubeseal < secret.yaml > sealed-secret.yaml

Sealed secrets safe to commit to git. Controller decrypts in-cluster.

SOPS

Encrypt YAML files with age/PGP/KMS. Decrypt in CI before apply.

sops -e -i secret.yaml

Secrets at runtime (in-app)

Don’t bake secrets into images. Either:

  • Mounted secrets.
  • Env vars from secret.
  • Pulled from external manager at startup.

Common mistakes

  • Plaintext secrets in git (Secrets are base64, not encrypted).
  • ConfigMap with binary file > 1MB — limit exceeded.
  • Forgetting to rotate Secrets after deploy.
  • env vs file mount confusion (env doesn’t update without restart).
  • Same ConfigMap mounted but pod uses cached env values.

Read this next

If you want my external-secrets + reloader setup, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .