CKA Study notes - ConfigMaps and Secrets - 2024 edition

Overview

Continuing with my Certified Kubernetes Administrator exam preparations I'm now going to take a look at ConfigMaps and Secrets.

This is an updated version of a similar post I created around three years ago.

ConfigMaps are a way to pass configuration to a Pod, or infact other parts of the system. For instance they can be used for configuring parts of a Kubernetes cluster.

1kubectl -n kube-system get configmaps

kube-system configmaps

The above lists the kube-system configmaps in my Kubernetes cluster.

Secrets are similar to ConfigMaps, but they are designed to hold smaller objects and meant to be used for sensitive data like passwords, tokens etc.

The reason for using ConfigMaps and Secrets is to keeping Configuration data separate from the Application code

Note #1: I'm using documentation for version 1.28 in my references below as this is the version used in the current (jan 2024) CKA exam. Please check the version applicable to your usecase and/or environment

Note #2: This is a post covering my study notes preparing for the CKA exam and reflects my understanding of the topic, and what I have focused on during my preparations.

Config maps

Kubernetes Documentation reference

Where secrets are meant to store sensitive data, ConfigMaps should only hold non-sensitive data. There's no secrecy or encryption offered with ConfigMaps

ConfigMaps are not meant to hold large data objects. The maximum size of a config map is 1 MiB.

As mentioned you can use ConfigMaps for holding Kubernetes configuration, but normally we'll come across or use them to hold data meant for use by Pods. A ConfigMap can for example hold a database host variable which your application code can use to know which database server to connect to in a dev/test/prod scenario.

Data is stored in ConfigMaps as key-value pairs. You can store data as data fields or binaryData fields where the data field are designed to hold UTF-8 byte sequences while the binaryData field holds binary data.

ConfigMaps can be used by a container inside a Pod in four different ways:

  1. Command and arguments inside a container(, set at runtime)
  2. Environment variables
  3. As a volume mounted for the container to read from
  4. Through the Kubernetes API

The fourth option requires you to write the logic yourself, but you are in more control of how to respond to any changes to the ConfigMaps. This allows you also to access ConfigMaps from different namespaces, whereas the first three options requires the ConfigMap to belong to the same namespace as the pod. The first three options are pushed to the Pod by the kubelet at launch.

Create ConfigMaps

Creating a ConfigMap (configmaps can also be created imperatively with the kubectl create configmap command) through a yaml file:

 1apiVersion: v1
 2kind: ConfigMap
 3metadata:
 4  name: configmap-name
 5data:
 6  configmap-key1: "some value"
 7  some-key2: "123"
 8  some.properties: |
 9    some.types: blue,green
10    some.key: "5"    
1kubectl apply -f <config-map-file>
2kubectl get configmaps
3kubectl describe configmaps <config-map-name>

Create config map

Map ConfigMap to Env variable

Let's see an example of a ConfigMap accessed as environment variables in a Pod:

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: config-map-demo
 5spec:
 6  containers:
 7    - name: config-map-pod
 8      image: nginx
 9      env:
10        - name: MY_ENV_VARIABLE  #Used inside the container
11          valueFrom:
12            configMapKeyRef:
13              name: configmap-name #Name of an existing configmap
14              key: configmap-key1 #A key from the specified configmap that we should use the value from

Create pod that uses configmap

So let's verify inside the Pod that we in fact are using the Configmap and that we have access to the correct value

1kubectl exec -it config-map-demo -- bash
2
3#The following is executed in the container running inside the Pod
4echo $MY_ENV_VARIABLE

Verify configmap value inside the Pod

Map ConfigMap to Volume

As mentioned previously Configmaps can also be accessed as a volume mount

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: config-map-volume-demo
 5spec:
 6  containers:
 7    - name: config-map-volume
 8      image: nginx
 9      volumeMounts:
10        - name: my-volume
11          mountPath: "/etc/folder"
12          readOnly: true
13  volumes:
14    - name: my-volume
15      configMap:
16        name: configmap-name
1kubectl apply -f <file-name>
2
3kubectl describe pod <pod-name>

Pod created with config map mounted in a volume

Again we can take a look inside the pod

1kubectl exec -it config-map-volume-demo -- bash
2
3#The following is executed in the container running inside the Pod
4ls /etc
5ls /etc/folder
6cat /etc/folder/some.properties 

Verify configmap values in Pod when mounted as a volume

Note that all contents of the ConfigMap has been added to the folder inside the Pod

If you want to mount multiple ConfigMaps you must mount multiple volumes. Since volumes are mounted to the pod they can be used by multiple containers inside the pod, but they would all need the volumeMounts to be able to access it.

One important difference between volume mounted ConfigMaps and environment variable mounted ConfigMaps is that the ConfigMaps mounted through a volume will be updated if changed. This happens on periodic syncs so it's not instant, but still, there are an update mechanism there through the kubelet. Environment variables do not update and requires a Pod restart to update. (reference)

Edit configmap

To verify we'll check the values inside the Pod

1cat /etc/folder/some.properties

Verify configmap changed

We have successfully updated the configuration inside the Pod. Again note that this happens on periodic intervals and it might take some time before the change is reflected.

Secrets

Kubernetes Documentation reference

Now let's switch over to Secrets which is a way to store sensitive configuration data.

Like a ConfigMap a Secret is used in a Pod by mounting it through a volume or specifying it as an environmental variable. A secret is also used by the kubelet when pulling images for a Pod

The Secrets are stored as key-value pairs, as they are in the case of ConfigMaps. We can specify the value as a data and/or a stringData field (technically all stringData fields are converted to a data field internally). Values in a data field has to be a base64 encoded string, whereas a stringData field can hold arbitrary strings.

There are a few built-in secret types available, where the Opaque type is the default and what is used for arbitrary user-data. We can also specify custom types if needed. There's also types for service-accounts, certificates and more.

Create Secret

By default I have no Secrets created in my default namespace so we'll create one as an example

1kubectl get secrets
2kubectl create secret <secret-type> <secret-name>
3kubectl get secrets

Create empty secret

We haven't specified any data in the Secret so for now it's empty (Data is 0).

Let's recreate the Secret with values from the command line. For that we use the --from-literal parameter

1kubectl delete secret my-secret
2kubectl create secret generic my-secret --from-literal=username=admin --from-literal=password=MySuperPassword123
3kubectl get secret
4kubectl describe secret my-secret

Re-create secret with some data

As we can see the actual values have been base64 encoded. Notice also that the Secret type is set to Opaque which is the default/generic.

Decode Secret

Let's try to decode the password value. First we'll examine the yaml output of the Secret, and then extract the .data.password value and pipe it through a base64 decoder

1kubectl get secret my-secret -o yaml
2kubectl get secret my-secret -o jsonpath='{.data}'
3echo $(kubectl get secret my-secret -o jsonpath='{.data.password}' | base64 --decode )

Decode secret

As this shows, be careful with who can access the Secrets in the cluster as it's fairly easy to retrieve the values.

Create Secret from file

Data can be added from a text file as well. We use the --from-file parameter instead of the --from-literal as we saw in the previous example.

First we'll create two files, one for holding the username, and the other for holding the password

File contents

Note that the files doesn't have a new line character at the end which is important because kubectl would have added that to the secret and potentially making the data invalid when used.

1kubectl create secret generic my-secret-file --from-file=username=./username.txt --from-file=password=./password.txt
2kubectl describe secret my-secret-file
3echo $(kubectl get secret my-secret-file -o jsonpath='{.data.password}' | base64 --decode )

Create Secret from file

Secrets can of course also be created from a yaml (or json) file. Note that you have to add the data fields with base64 encoded values

1echo -n "MyThirdPassword1234" | base64
1apiVersion: v1
2kind: Secret
3metadata:
4  name: my-secret-file2
5type: Opaque
6data:
7  password: TXlUaGlyZFBhc3N3b3JkMTIzNA==
1cat my-secret-file2.yaml
2kubectl apply -f my-secret-file2.yaml
3echo $(kubectl get secret my-secret-file2 -o jsonpath='{.data.password}' | base64 --decode )

Create Secret from yaml file

Use secret in a Pod

Let's see how we can use a secret inside a Pod. We'll make use of the Secret we just created

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: secret-pod-demo
 5spec:
 6  containers:
 7  - name: secret-pod
 8    image: nginx
 9    env:
10    - name: MY_PASSWORD  #Used inside the container
11      valueFrom:
12        secretKeyRef:
13          name: my-secret-file2 #Name of an existing configmap
14          key: password #A key from the specified configmap that we should use the value from
1kubectl apply -f <file-name>

Create Pod that uses Secret

Now let's check if we have access to the secret inside our pod

1kubectl exec -it secret-pod-demo -- bash
2
3#This is executed in the container inside the Pod
4echo $MY_PASSWORD

Verify that Secret has been mapped in Pod

We'll only look at an Environment variable example, but we could mount secrets as a volume as we did with our ConfigMaps earlier

ImagePullSecrets

Kubernetes Documentation reference

One very common use case for Secrets is storing the credentials needed to pull container images from registries like DockerHub etc. These can then be referenced in the imagePullSecrets section in a Pod definition. (reference)

An image pull secret can also be assigned to a service account.(reference)

Immutable Secrets and ConfigMap

Kubernetes Documentation reference

Kubernetes version 1.19 introduced a new feature called Immutable Secrets and ConfigMaps which was added as a stable feature in version 1.21.

This feature prevents the change of a ConfigMap or a Secret. This is something you might would want to prevent unwanted updates of config data. It also has the advantage of improving performance of your cluster since the apiserver doesn't have to watch the configmap for changes

1apiVersion: v1
2kind: ConfigMap
3metadata:
4  name: immutable-configmap-name
5data:
6  some-key: "some value"
7  some-other-key: "some other value"
8immutable: true #This makes the configmap immutable
1kubectl apply -f <file-name>
2kubectl get configmaps
3kubectl describe configmaps <config-map-name>

Create immutable ConfigMap

Our immutable ConfigMap has been created. Interestingly the describe command doesn't mention the immutable field.

So what happens if we try to edit the ConfigMap?

1kubectl edit configmap <config-map-name>

Change immutable ConfigMap fails

So I tried to change the value of the two keys, but I couldn't save the file and I get a forbidden message stating that the data field is immutable.

Let's try to be creative and remove the immutable field entirely

Try to remove immutable field

No luck there either. We'll exit out of the file with no changes

Cancel editing and no changes saved

The only way to change the ConfigMap is to delete it and recreate it with updated values.

Summary

ConfigMaps and Secrets is a very important concept in Kubernetes as it allows us to decouple configuration and application code. This allows our applications to be used in many environments and clusters without having to change anything but the references to the configuration objects.

There's more to both ConfigMaps and Secrets than shown in this post. As mentioned in the start of this post I'm using this post as a way to reinforce studying for the CKA exam. Be sure to check out the documentation for more info

This page was modified on January 7, 2024: Updated CM and Secrets post