Managing Configuration with ConfigMaps and Secrets

Managing application configuration is essential for building scalable and secure Kubernetes deployments. Kubernetes provides native objects like ConfigMaps and Secrets to externalize configuration data and sensitive credentials from your application code. This separation supports better security practices, portability, and easier updates.

In this guide, you’ll learn how to manage configuration with ConfigMaps and Secrets, understand how they integrate with Pods, and apply best practices for real-world usage. You’ll also explore supporting components like Volumes, the Container Storage Interface (CSI), PersistentVolumes (PVs), and PersistentVolumeClaims (PVCs), which are critical for managing stateful workloads.

Volumes

Containers in Pods are ephemeral. When a container restarts, all data stored inside it is lost. To preserve data, Kubernetes uses Volumes—storage abstractions that support various backends.

In Kubernetes, an ephemeral Volume is linked to a Pod and can be shared among the containers of that Pod. Although the ephemeral Volume has the same life span as the Pod, meaning that it is deleted together with the Pod, the ephemeral Volume outlives the containers of the Pod – this allows data to be preserved across container restarts. 

A volume plugin built using a standardized Container Storage Interface (CSI) designed to work on different container orchestrators with a variety of storage providers.

Ephemeral Volume Types

A directory which is mounted inside a Pod is backed by the underlying Volume Type. A Volume Type decides the properties of the directory, like size, content, default access modes, etc. Some examples of Volume Types that support ephemeral Volumes are:

Volume typeDescription
emptyDirTemporary storage created when a Pod is scheduled to a node. Deleted when the Pod is removed.
hostPathMounts a file or directory from the host node. Data persists after Pod deletion.
secretInjects sensitive data such as tokens and passwords into containers.
configMapProvides configuration data as files or environment variables.
nfs, iscsiMounts external shared file systems or block devices.
cephfsMounts CephFS volumes. Data persists after the Pod is deleted.
gcePersistentDisk, awsElasticBlockStore, azureDisk, azureFileMounts disks or file shares from cloud providers.

Persistent Storage in Kubernetes

To manage long-term storage, Kubernetes provides the PersistentVolume (PV) subsystem. This separates storage provisioning (by admins) from storage consumption (by developers).

PersistentVolumes

To manage the Volume, it uses the PersistentVolume API resource type, and to consume it, it uses the PersistentVolumeClaim API resource type.

A PersistentVolume is a cluster-managed storage resource. It abstracts storage backends such as:

  • Local disk
  • NFS
  • Cloud block/file storage (e.g., GCEPersistentDisk, AWSElasticBlockStore)
  • Distributed storage (e.g., CephFS)
PersistentVolume
Image credits : https://trainingportal.linuxfoundation.org

PersistentVolumes can be:

  • Statically provisioned by administrators
  • Dynamically provisioned using a StorageClass

PersistentVolumeClaims

A PersistentVolumeClaim is a developer request for storage. You specify:

  • Access mode
  • Size
  • Volume mode (Filesystem or Block)
  • StorageClass
ModeDescription
ReadWriteOnceOne node can read and write
ReadOnlyManyMany nodes can read
ReadWriteManyMany nodes can read and write
ReadWriteOncePodOne Pod can read and write (Kubernetes 1.22+)

Kubernetes binds the claim to a suitable PersistentVolume automatically.

Image credits : https://trainingportal.linuxfoundation.org

Storage Reclaim Policies

When a PVC is released, Kubernetes follows the PV’s reclaim policy:

PolicyBehavior
RetainKeeps the volume and data. Manual cleanup is required.
DeleteDeletes the volume and its data.

In this example, two containers run in the same Pod:

  • A Debian container writes a welcome message to a shared directory.
  • An NGINX container serves that file as a web page.

YAML Configuration

apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blue-app
  template:
    metadata:
      labels:
        app: blue-app
        type: canary
    spec:
      volumes:
        - name: host-volume
          hostPath:
            path: /home/docker/blue-shared-volume
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: /usr/share/nginx/html
              name: host-volume
        - name: debian
          image: debian
          command: ["/bin/sh", "-c", "echo Welcome to BLUE App! > /host-vol/index.html ; sleep infinity"]
          volumeMounts:
            - mountPath: /host-vol
              name: host-volume

ConfigMaps

A ConfigMap lets you externalize configuration from container images. You can pass configuration data to Pods using key-value pairs. These values can be exposed as:

  • Environment variables
  • Command-line arguments
  • Mounted volumes

You can create a ConfigMap from literal values, configuration files, or a manifest.

Create a ConfigMap from Literal Values

Use the kubectl create configmap command to define key-value pairs directly.

kubectl create configmap my-config \
--from-literal=key1=value1 \
--from-literal=key2=value2

Verify the ConfigMap:

kubectl get configmaps my-config -o yaml

The -o yaml flag outputs the object in YAML format. The data field lists key-value pairs. Metadata includes the name and other configuration details.

Create a ConfigMap from a Manifest

You can use a declarative approach by defining a ConfigMap in a YAML manifest.

File: customer1-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
name: customer1
data:
TEXT1: Customer1_Company
TEXT2: Welcomes You
COMPANY: Customer1 Company Technology Pct. Ltd.

Create the ConfigMap:

kubectl create -f customer1-configmap.yaml

Create a ConfigMap from a File

You can generate a ConfigMap from a file that contains configuration values.

File: permission-reset.properties

permission=read-only
allowed="true"
resetCount=3

Create the ConfigMap:

kubectl create configmap permission-config \ --from-file=path/to/permission-reset.properties

Use ConfigMaps in Pods

You can use ConfigMap data in a Pod as environment variables.

Load All Keys as Environment Variables

containers:
- name: myapp-full-container
  image: myapp
  envFrom:
  - configMapRef:
      name: full-config-map

Load Specific Keys as Environment Variables

containers:
- name: myapp-specific-container
  image: myapp
  env:
  - name: SPECIFIC_ENV_VAR1
    valueFrom:
      configMapKeyRef:
        name: config-map-1
        key: SPECIFIC_DATA
  - name: SPECIFIC_ENV_VAR2
    valueFrom:
      configMapKeyRef:
        name: config-map-2
        key: SPECIFIC_INFO

Secrets

Kubernetes Secrets let you store and manage sensitive information—such as passwords, tokens, and SSH keys—separately from your application code. Secrets work like ConfigMaps but are designed specifically for confidential data and help reduce the risk of accidental exposure.

Note: By default, Secret data is stored as plain text in etcd. Protect it by restricting access to the API server and enabling encryption at rest.

You can create Secrets using literal values, YAML manifests, or files. Kubernetes stores Secret data as key-value pairs.

Create a Secret from Literal Values

Use the following command to create a Secret from a string literal:

kubectl create secret generic my-password \--from-literal=password=mysqlpassword

To inspect the Secret:

kubectl get secret my-password
kubectl describe secret my-password

Create a Secret from a Manifest File

You can define Secrets in YAML using either base64-encoded data or raw stringData. Kubernetes encodes stringData automatically.

Option 1: Use data (Base64-encoded)

First, encode the value:

echo -n 'mysqlpassword' | base64

Then create the manifest file mypass.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: my-password
type: Opaque
data:
  password: bXlzcWxwYXNzd29yZA==

Apply the manifest:

kubectl apply -f mypass.yaml

Note: Base64 encoding is not encryption. Avoid committing this file to version control.

Option 2: Use stringData (Plain text)

apiVersion: v1
kind: Secret
metadata:
  name: my-password
type: Opaque
stringData:
  password: mysqlpassword

Apply the manifest:

kubectl apply -f mypass.yaml

Create a Secret from a File

To create a Secret from a file, first create the file:

echo -n 'mysqlpassword' > password.txt

Then run:

kubectl create secret generic my-file-password \--from-file=password.txt

Inspect the Secret:

kubectl get secret my-file-password
kubectl describe secret my-file-password

Use Secrets in Pods

You can inject Secrets into Pods using environment variables or mount them as volumes.

Option 1: Use Secrets as Environment Variables

Reference a specific key from the Secret:

containers:
- name: wordpress
  image: wordpress:4.7.3-apache
  env:
  - name: WORDPRESS_DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: my-password
        key: password

Option 2: Mount Secrets as Volumes

Mount the entire Secret. Each key becomes a file with the Secret value as its content.

containers:
- name: wordpress
  image: wordpress:4.7.3-apache
  volumeMounts:
  - name: secret-volume
    mountPath: "/etc/secret-data"
    readOnly: true

volumes:
- name: secret-volume
  secret:
    secretName: my-password

Best Practices for Using Secrets

  • Avoid hardcoding Secrets in application manifests.
  • Never commit Secrets to version control systems.
  • Enable encryption at rest for etcd in production clusters.
  • Use RBAC to control access to Secrets.

2 thoughts on “Managing Configuration with ConfigMaps and Secrets

Leave a comment