#90daysofdevops #35: Mastering ConfigMaps and Secrets in Kubernetes
Table of contents
What are ConfigMaps and Secrets in k8s
In Kubernetes, ConfigMaps and Secrets are used to store configuration data and secrets, respectively. ConfigMaps store configuration data as key-value pairs, while Secrets store sensitive data in an encrypted form.
- Example :- Imagine you're in charge of a big spaceship (Kubernetes cluster) with lots of different parts (containers) that need information to function properly. ConfigMaps are like a file cabinet where you store all the information each part needs in simple, labeled folders (key-value pairs). Secrets, on the other hand, are like a safe where you keep the important, sensitive information that shouldn't be accessible to just anyone (encrypted data). So, using ConfigMaps and Secrets, you can ensure each part of your spaceship (Kubernetes cluster) has the information it needs to work properly and keep sensitive information secure!
ConfigMaps
A ConfigMap is an API object used to store non-confidential data in key-value pairs. Pods can consume ConfigMaps as environment variables, command-line arguments, or as configuration files in a volume.
A ConfigMap allows you to decouple environment-specific configuration from your container images, so that your applications are easily portable.
Caution: ConfigMap does not provide secrecy or encryption. If the data you want to store are confidential, use a Secret rather than a ConfigMap, or use additional (third party) tools to keep your data private.
ConfigMaps and Pods
You can write a Pod spec
that refers to a ConfigMap and configures the container(s) in that Pod based on the data in the ConfigMap. The Pod and the ConfigMap must be in the same namespace.
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# property-like keys; each key maps to a simple value
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# file-like keys
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
Secrets
A Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key. Such information might otherwise be put in a Pod specification or in a container image. Using a Secret means that you don't need to include confidential data in your application code.
Because Secrets can be created independently of the Pods that use them, there is less risk of the Secret (and its data) being exposed during the workflow of creating, viewing, and editing Pods. Kubernetes, and applications that run in your cluster, can also take additional precautions with Secrets, such as avoiding writing secret data to nonvolatile storage.
Secrets are similar to ConfigMaps but are specifically intended to hold confidential data.
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
optional: true
Difference between ConfigMaps and Secrets in Kubernetes
Criteria | ConfigMaps | Secrets |
Purpose | Store non-sensitive configuration data. | Store sensitive information. |
Data Types | Text files, key-value pairs, or environment variables. ConfigMaps store data as plain text | Text files, key-value pairs, or environment variables. Secrets can store data as base64-encoded or opaque. |
Data Visibility | Data is visible in plain text to anyone with access. | Data is encrypted and stored securely. |
Use Cases | Configuration files, environment variables, and command-line options. | Passwords, API keys, TLS certificates, secrets. |
Security | No encryption or protection of data. | Data is encrypted and stored securely. |
Accessing Data | Accessed as environment variables or mounted as files. | Accessed as environment variables or mounted as files. |
Update Dynamics | Changes require pod restarts to take effect. | Changes are dynamically updated without pod restarts. |
Namespaces | ConfigMaps can be shared across namespaces. | Secrets are limited to a single namespace. |
Kubernetes Objects | ConfigMaps are represented as ConfigMap objects. | Secrets are represented as Secret objects. |
Creation | Data is provided directly in the YAML file or from files. | Data is provided directly in the YAML file or from files. |
Access Control | ConfigMaps have no built-in access control mechanisms. | Secrets can be granted specific access controls. |
Use in Pods | ConfigMaps can be used in any pod. | Secrets are primarily used by pods for sensitive data. |
Volume Mounts | ConfigMaps can be mounted as volumes in pods. | Secrets can also be mounted as volumes in pods. |
Data Size | ConfigMaps can store larger amounts of data. | Secrets have size limitations based on the backend storage. |
Backup and Restore | ConfigMaps are easily backed up and restored. | Secrets require additional security measures for backup and restoration. |
Data Modification | ConfigMap data can be modified without restarting pods. | Secrets require pod restarts for data modification. |
In yesterday's blog, I got some hands on the services in Kubernetes. Let's move forward today and learn and master ConfigMaps and Secrets in Kubernetes.
ConfigMaps
According to kubernetes.io, a ConfigMap is an API object used to store non-confidential data in key-value pairs.
ConfigMaps are used to store configuration data that can be consumed by pods or other Kubernetes resources.
ConfigMaps are typically used to store non-sensitive configuration data such as environment variables, command-line arguments, or configuration files. This data can be accessed by pods as environment variables or mounted as files.
A ConfigMap is not designed to hold large chunks of data. The data stored in a ConfigMap cannot exceed 1 MiB.
There are four different ways that you can use a ConfigMap to configure a container inside a Pod:
Inside a container command and args
Environment variables for a container
Add a file in read-only volume, for the application to read
Write code to run inside the Pod that uses the Kubernetes API to read a ConfigMap
Secrets
According to kubernetes.io, a Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key.
Secrets are used to store sensitive information such as passwords, API keys, and TLS certificates. Secrets provide a secure way to store and manage this confidential data within a cluster. They are similar to ConfigMaps but are specifically designed to handle sensitive information.
There are three main ways for a Pod to use a Secret:
As files in a volume mounted on one or more of its containers.
By the kubelet when pulling images for the Pod.
Difference between ConfigMaps and Secrets in Kubernetes
Criteria | ConfigMaps | Secrets |
Purpose | Store non-sensitive configuration data. | Store sensitive information. |
Data Types | Text files, key-value pairs, or environment variables. ConfigMaps store data as plain text | Text files, key-value pairs, or environment variables. Secrets can store data as base64-encoded or opaque. |
Data Visibility | Data is visible in plain text to anyone with access. | Data is encrypted and stored securely. |
Use Cases | Configuration files, environment variables, and command-line options. | Passwords, API keys, TLS certificates, secrets. |
Security | No encryption or protection of data. | Data is encrypted and stored securely. |
Accessing Data | Accessed as environment variables or mounted as files. | Accessed as environment variables or mounted as files. |
Update Dynamics | Changes require pod restarts to take effect. | Changes are dynamically updated without pod restarts. |
Namespaces | ConfigMaps can be shared across namespaces. | Secrets are limited to a single namespace. |
Kubernetes Objects | ConfigMaps are represented as ConfigMap objects. | Secrets are represented as Secret objects. |
Creation | Data is provided directly in the YAML file or from files. | Data is provided directly in the YAML file or from files. |
Access Control | ConfigMaps have no built-in access control mechanisms. | Secrets can be granted specific access controls. |
Use in Pods | ConfigMaps can be used in any pod. | Secrets are primarily used by pods for sensitive data. |
Volume Mounts | ConfigMaps can be mounted as volumes in pods. | Secrets can also be mounted as volumes in pods. |
Data Size | ConfigMaps can store larger amounts of data. | Secrets have size limitations based on the backend storage. |
Backup and Restore | ConfigMaps are easily backed up and restored. | Secrets require additional security measures for backup and restoration. |
Data Modification | ConfigMap data can be modified without restarting pods. | Secrets require pod restarts for data modification. |
Let's start with the tasks now to learn and master ConfigMaps and Secrets.
Tasks
Task 1: Create a ConfigMap for your Deployment
Let's create a mysql-config.yml file.
COPY
apiVersion: v1
kind: ConfigMap
metadata:
name: my-configmap
labels:
app: django-todo-app
namespace: deploy1
data:
MYSQL_DB: "database_todo"
This YAML file creates a ConfigMap object that stores a single configuration setting, MYSQL_DB
with the value "database_todo"
. This ConfigMap can be used by a pod in the deploy1
namespace to access this configuration setting as an environment variable or a file in a mounted volume.
Now apply the configmap.yml file to your deployment.
COPY
kubectl apply -f configmap.yml
To verify the ConfigMap creation, use the following command:
COPY
kubectl get configmap -n <namespace>
And yes! The ConfigMap is created successfully.
Task 2: Create a Secret for your Deployment
Before jumping into creating Secrets, let us encrypt the username and password.
I am taking the following details:
Password: admin@123
In your terminal, using base64 you can encode and decode:
COPY
echo -n 'admin@123' | base64
You can verify the encrypted characters by using the following:
COPY
echo YWRtaW5AMTIz | base64 --decode
What is base64? Base64 is a binary-to-text encoding scheme that represents binary data in sequences of 24 bits that can be represented by four 6-bit Base64 digits.
It is always better to not use hardcoded values for data like usernames and passwords.
I am going to use these encoded characters in the mysql-secret.yml file that I am going to create now.
COPY
apiVersion: v1
kind: Secret
metadata:
name: my-secret
namespace: deploy1
type: Opaque
data:
password: YWRtaW5AMTIz
This YAML file creates a Secret object that stores a single piece of sensitive data, password
with the value admin@123
. This Secret can be used by a pod in the deploy1
namespace to access this sensitive data as an environment variable or a file in a mounted volume. The value is encoded in base64 format to protect it from being exposed accidentally or stored in a terminal log.
What's the type: Opaque mentioned here in the above code block?
In Kubernetes,
type: Opaque
is the default type for a Secret object.It means that the contents of the Secret are unstructured and can contain arbitrary key-value pairs.Opaque Secrets are used to store arbitrary user-defined data, such as passwords, OAuth tokens, and ssh keys.
Other types of Secrets include: Service accounts token secrets (store a token that references a service account.), Docker registry secrets (store credentials for accessing a Docker registry), and TLS secrets (store TLS certificates and keys).
Let's apply the secret to deployment.
COPY
kubectl apply -f mysql-secret.yml -n <namespace>
We can verify the creation of secrets using:
COPY
kubectl get secrets -n <namespace>
Update the sqldeployment.yml with the secrets and config map.
COPY
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-configuration
labels:
app: mysql
namespace: deploy1
spec:
replicas: 2
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql-container
image: mysql:8
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: my-configmap
key: MYSQL_DB
Let's apply this to the cluster.
COPY
kubectl apply -f sqldeployment.yml -n deploy1
Let's verify if the pods are running.
COPY
kubectl get pods -n <namespace>
And yes, the pods are created.
But we need to use the MySQL service. For that, we will have to expose the k8s cluster to a port. I will create a sqlservice.yml for that.
COPY
apiVersion: v1
kind: Service
metadata:
name: mysql-service-configuration
spec:
ports:
- name: mysql
port: 3306
clusterIP: None
selector:
app: mysql
And apply to the cluster.
COPY
kubectl apply -f sqlservice.yml -n <namespace>
Get inside the worker node and install the MYSQL client.
COPY
sudo apt install mysql-client-core-8.0
Now on the controller, connect to any node:
COPY
kubectl exec -it mysql-configuration-858b8c57ff-p52wz /bin/sh -n deploy1
Connect using the username and password you gave in the secret.yml file.
COPY
mysql -u root -p${MYSQL_ROOT_PASSWORD}
Now we are in the MYSQL console. We can see the databases in the container using show databases;