
- Kubernetes Tutorial
- Kubernetes - Home
- Kubernetes - Overview
- Kubernetes - Architecture
- Kubernetes - Setup
- Kubernetes - Setup on Ubuntu
- Kubernetes - Images
- Kubernetes - Jobs
- Kubernetes - Labels & Selectors
- Kubernetes - Namespace
- Kubernetes - Node
- Kubernetes - Service
- Kubernetes - POD
- Kubernetes - Replication Controller
- Kubernetes - Replica Sets
- Kubernetes - Deployments
- Kubernetes - Volumes
- Kubernetes - Secrets
- Kubernetes - Network Policy
- Advanced Kubernetes
- Kubernetes - API
- Kubernetes - Kubectl
- Kubernetes - Kubectl Commands
- Kubernetes - Creating an App
- Kubernetes - App Deployment
- Kubernetes - Autoscaling
- Kubernetes - Dashboard Setup
- Kubernetes - Helm Package Management
- Kubernetes - CI/CD Integration
- Kubernetes - Persistent Storage and PVCs
- Kubernetes - RBAC
- Kubernetes - Logging & Monitoring
- Kubernetes - Service Mesh with Istio
- Kubernetes - Backup and Disaster Recovery
- Managing ConfigMaps and Secrets
- Running Stateful Applications
- Kubernetes Useful Resources
- Kubernetes - Quick Guide
- Kubernetes - Useful Resources
- Kubernetes - Discussion
Managing ConfigMaps and Secrets in Kubernetes
In a Kubernetes environment, managing application configuration and secrets is crucial for smooth, secure operations. We often encounter situations where we need to store non-sensitive dataâlike configuration files, environment variables, or command-line argumentsâand sensitive dataâlike passwords, API tokens, or SSL certificates. Kubernetes provides two native resources to handle these scenarios: ConfigMaps for non-sensitive data and Secrets for sensitive data.
In this chapter, weâll explore the differences between these two resources, look at the latest best practices, and walk through step-by-step commands to create, use, and update them. By the end, we will have a firm grasp on how to manage our cluster configurations more effectively and securely.
Why ConfigMaps and Secrets Matter
In a microservices environment, applications are typically containerized and ephemeral. We donât want to bake environment-specific details (like database URLs, external service endpoints, or debug flags) directly into our container images. Doing so can lead to inflexible images and increased maintenance overhead. Instead, we can externalize these details with ConfigMaps or Secrets, which are dynamically injected into Pods at runtime.
What are ConfigMaps?
A ConfigMap is a key-value store for non-sensitive configuration data. We can store entire configuration files, single variables, or even partial files. ConfigMaps allow us to update configurations without rebuilding our images, giving us a flexible and modular approach to application deployment.
Creating a ConfigMap
We can create ConfigMaps from literal values, files, or directories. Here are a few examples using kubectl:
From Literal Values:
$ kubectl create configmap my-config \ --from-literal=APP_MODE=development \ --from-literal=APP_DEBUG=true
Output
configmap/my-config created
In this command, weâve created a ConfigMap named my-config with two key-value pairs: APP_MODE and APP_DEBUG.
From a File:
Suppose we have a file named app-config.yaml with the following contents:
app: name: demo-application environment: development debug: "true" version: "1.0.0" database: host: db-service port: 5432 user: demo-user password: change-me
We can create a ConfigMap from this file:
$ kubectl create configmap app-config \ --from-file=app-config.yaml
Output
configmap/app-config created
Now, our ConfigMap app-config contains the contents of app-config.yaml.
From a Directory:
If we have multiple configuration files in a directory called config/, we can run:
$ kubectl create configmap my-config-dir \ --from-file=config/
Output
configmap/my-config-dir created
To verify, run:
$ kubectl get configmaps
Output
NAME DATA AGE app-config 1 2m22s kube-root-ca.crt 1 50m my-config 2 4m15s my-config-dir 2 37s
$ kubectl describe configmap app-config
Output
Name: app-config Namespace: default Labels: <none> Annotations: <none> Data ==== app-config.yaml: ---- app: name: demo-application environment: development debug: "true" version: "1.0.0" database: host: db-service port: 5432 user: demo-user password: change-me
BinaryData: ==== Events: <none>
Injecting the ConfigMap into a Pod
We will now create a Pod that references the ConfigMap as a mounted volume, so our application can read the file at runtime. Below is a sample Pod YAML (pod-with-configmap.yaml):
apiVersion: v1 kind: Pod metadata: name: configmap-demo spec: containers: - name: demo-container image: nginx:latest volumeMounts: - name: config-volume mountPath: /etc/app-config volumes: - name: config-volume configMap: name: app-config items: - key: app-config.yaml path: app-config.yaml
Apply the Pod:
$ kubectl apply -f pod-with-configmap.yaml
Output
pod/configmap-demo created
We can then exec into the Pod to confirm the file is mounted:
$ kubectl exec -it configmap-demo -- cat /etc/app-config/app-config.yaml
Output
app: name: demo-application environment: development debug: "true" version: "1.0.0" database: host: db-service port: 5432 user: demo-user password: change-me
As we can see the content is originally the same as the one placed in app-config.yaml, meaning everything is working as expected.
Updating ConfigMaps
We can update our app-config.yaml file by editing it and then re-creating or applying the ConfigMap:
$ kubectl create configmap app-config \ --from-file=app-config.yaml \ --dry-run=client -o yaml | kubectl apply -f -
Output
configmap/app-config configured
This pattern ensures we apply changes to the existing ConfigMap rather than creating a new one from scratch. Keep in mind that existing Pods using this ConfigMap wonât automatically reload the changes unless we restart or roll them out again.
What are Secrets in Kubernetes?
A Secret in Kubernetes is a resource used to store and manage sensitive information. By default, Kubernetes stores Secrets in base64-encoded form, which isnât fully secure on its own but prevents casual exposure in logs or CLI outputs. For more advanced security, we can enable Encryption at Rest or integrate with external vault solutions like HashiCorp Vault or AWS KMS.
Creating a Secret
We have several ways to create Secrets:
1. From Literal Values:
We can create a Secret directly from literal key-value pairs. For example:
$ kubectl create secret generic my-secret \ --from-literal=username=admin \ --from-literal=password=secretpass
Output
secret/my-secret created
In this example, we will end up with a Secret named my-secret that has base64-encoded values for username and password.
2. From a File:
We can also create a Secret from one or more files on our local machine. This is especially common for TLS certificates:
$ kubectl create secret generic tls-secret \ --from-file=tls.crt=./mycert.crt \ --from-file=tls.key=./mykey.key
Output
secret/tls-secret created
Here, tls-secret will contain two keys: tls.crt and tls.key, each storing the contents of the respective files.
3. From a Manifest:
We can define a Secret directly in a YAML file if we prefer to keep it in version control (though we should be cautious about storing sensitive data in plain text). For instance:
apiVersion: v1 kind: Secret metadata: name: my-manual-secret type: Opaque data: username: YWRtaW4= password: c2VjcmV0cGFzcw==
In this example, username and password are already base64-encoded values (admin and secretpass respectively). We can apply this manifest with:
$ kubectl apply -f my-manual-secret.yaml
Output
secret/my-manual-secret created
We can verify the secret was created:
$ kubectl get secrets Output: db-secret Opaque 2 5m14s my-manual-secret Opaque 2 20m my-secret Opaque 2 25m tls-secret Opaque 2 22m
Using Secrets in a Pod
We often mount Secrets into our Pods, either as environment variables or as files, much like ConfigMaps. Below is a Pod snippet that demonstrates using Secrets as environment variables:
apiVersion: v1 kind: Pod metadata: name: secret-demo spec: containers: - name: demo-container image: nginx:latest env: - name: DB_USERNAME valueFrom: secretKeyRef: name: db-secret key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password
Apply the File:
$ kubectl apply -f secret-demo.yaml
Output
pod/secret-demo created
When the Pod starts, it will have DB_USERNAME and DB_PASSWORD set from the db-secret resource. We can confirm:
$ kubectl exec -it secret-demo -- env | grep DB_ Output: DB_PASSWORD=secretpass DB_USERNAME=admin
Updating a Secret
Similarly, if we need to rotate our credentials:
$ kubectl create secret generic db-secret \ --from-literal=username=demo-user \ --from-literal=password=newSecretPass \ --dry-run=client -o yaml | kubectl apply -f -
Output
secret/db-secret configured
Best Practices for ConfigMaps and Secrets
Enable Encryption at Rest
For an added layer of security, enable Encryption at Rest in Kubernetes so that Secrets are encrypted on disk.
Least Privilege Access
Use RBAC rules to restrict who can read or modify ConfigMaps and Secrets. This helps reduce the risk of accidental or malicious changes.
Separate Sensitive and Non-Sensitive Data
If you mix sensitive data into a ConfigMap, it can be exposed inadvertently. Keep them in a Secret if thereâs any doubt.
Rolling Updates and Managing Changes
One of the challenges with ConfigMaps and Secrets is that changes donât automatically trigger a rolling update of our Pods. We have two main approaches:
Manual Rolling Update
After updating a ConfigMap or Secret, we can manually roll our Deployment by running:
kubectl rollout restart deployment
This ensures our Pods restart and pick up the new configuration.
Hash Annotation Trick
Another approach is to annotate our Pod or Deployment spec with a hash of the ConfigMap/Secret data. Whenever the data changes, the hash changes, prompting a new rollout. This technique can be automated with a GitOps workflow or a small script.
Conclusion
ConfigMaps and Secrets are core building blocks for managing configuration and sensitive data in Kubernetes. By using them properly, we can decouple our application code from environment-specific settings, reduce the risk of exposing sensitive information, and keep our containers as generic as possible.
By following these steps and guidelines, we will have a more secure and flexible Kubernetes environment, enabling us to focus on delivering robust applications without worrying about configuration drift or credential leakage.