Lesson 06 Secrets & ConfigMaps
Theme:
Lesson 06 · Slide 1

Secrets & ConfigMaps

Externalising configuration and protecting sensitive data in Helm charts

Lesson 06 · Slide 2

ConfigMaps in Helm

ConfigMaps decouple configuration from container images. Helm templates them from values.yaml or external files.

# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "myapp.fullname" . }}-config
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
data:
  APP_ENV: {{ .Values.config.env | quote }}
  LOG_LEVEL: {{ .Values.config.logLevel | quote }}
  # Load an entire file from the chart
  nginx.conf: |-
{{ .Files.Get "files/nginx.conf" | indent 4 }}
Files.Glob — Use {{ range $path, $bytes := .Files.Glob "files/**.conf" }} to load multiple config files into a single ConfigMap automatically.
Lesson 06 · Slide 3

Mounting ConfigMaps

As Environment Variables

env:
  - name: APP_ENV
    valueFrom:
      configMapKeyRef:
        name: {{ include "myapp.fullname" . }}-config
        key: APP_ENV
# Or load all keys at once:
envFrom:
  - configMapRef:
      name: {{ include "myapp.fullname" . }}-config

As a Volume

volumes:
  - name: config-vol
    configMap:
      name: {{ include "myapp.fullname" . }}-config
containers:
  - volumeMounts:
      - name: config-vol
        mountPath: /etc/myapp
        readOnly: true
Tip: Volume-mounted ConfigMaps update automatically (kubelet sync period ~60s). Environment variables require a pod restart.
Lesson 06 · Slide 4

Secrets in Helm

Kubernetes supports three common Secret types: Opaque, kubernetes.io/tls, and kubernetes.io/dockerconfigjson.

# templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: {{ include "myapp.fullname" . }}-secret
type: Opaque
# Option A: base64-encoded data
data:
  DB_PASSWORD: {{ .Values.secrets.dbPassword | b64enc | quote }}
# Option B: plaintext stringData (Kubernetes base64-encodes it)
stringData:
  API_KEY: {{ .Values.secrets.apiKey | quote }}

data — Values must be base64-encoded. Use the b64enc Helm function.

stringData — Accepts plaintext. Kubernetes encodes it on creation. Convenient but shows plaintext in the template.

Lesson 06 · Slide 5

The Plaintext Problem

Warning: If secrets live in values.yaml, they are plaintext in Git. This is the #1 Helm security mistake.

Solutions

Lesson 06 · Slide 6

External Secrets Pattern

# templates/external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: {{ include "myapp.fullname" . }}-es
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: {{ include "myapp.fullname" . }}-secret
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: prod/myapp/db
        property: password
    - secretKey: API_KEY
      remoteRef:
        key: prod/myapp/api
        property: key
Result: The operator creates a regular Kubernetes Secret from the external store. Your Deployment references it normally — no plaintext in Git.
Lesson 06 · Slide 7

Immutable Resources & Rollout Tricks

Immutable ConfigMaps/Secrets

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "myapp.fullname" . }}-config
immutable: true
data:
  APP_ENV: {{ .Values.config.env | quote }}

Immutable resources reduce API server load. To update, delete and recreate (Helm handles this on upgrade).

Checksum Annotation

# templates/deployment.yaml
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}

When config changes, the annotation changes, triggering a rolling update automatically.

Lesson 06 · Slide 8

Secret Rotation Patterns

Best practice: Combine the checksum annotation trick with External Secrets' refreshInterval for fully automated secret rotation without manual helm upgrade calls.

Key Takeaways

  1. ConfigMaps for non-sensitive config; Secrets for credentials
  2. Never commit plaintext secrets to Git — use External Secrets or Sealed Secrets
  3. Use the checksum annotation to auto-roll pods on config changes
  4. Plan for secret rotation from day one
1 / ?