ConfigMaps and Secrets in Kubernetes

ConfigMaps and Secrets in Kubernetes

Introduction

Configuration⚙️ is essential for any application to function properly. Any data that controls or influences how an application works can be considered configuration. Before jumping to ConfigMaps and Secrets let's understand something about environment variables.

Environment variables are name-value pairs that are stored and used by the operating system. They contain various information that programs need to run properly. Most commonly they are used for storing configuration settings, passing credentials & controlling program behavior

We know about the ENV variables in Docker - they are set using the ENV instruction in a Dockerfile or using the -e flag when running a container which can be used to configure applications inside Docker containers. For example, in a Dockerfile you can do:

  ENV MY_VARIABLE=some_value
  ENV PORT=80

Then when running the container you can override PORT:

  docker run -e PORT=8080 my_image

env in Kubernetes

Just like the Dockerfile, you can specify environment variables directly in your Kubernetes Deployment YAML file. This means each deployment can get a customized environment. Let's see an example below. The environment variables will be passed to all Nginx containers started by this deployment.

  apiVersion: apps/v1 
  kind: Deployment
  metadata:
    name: nginx-deployment
  spec:
    replicas: 3  
    selector:
      matchLabels:
        app: nginx
    template:
      metadata:
        labels: 
          app: nginx
      spec:
        containers:
        - name: nginx
          image: nginx:1.14.2
          ports:
          - containerPort: 80
          env:
          - name: LANG
            value: "English" 
          - name: API_URL
            value: "http://localhost:5000/deploy"

One major shortfall is that the environment variables are tied to the specific container or deployment. This makes it inflexible in several ways.

Kubernetes ConfigMaps and Secrets are two ways to inject configuration data into your Pods and Containers. ConfigMaps allows you to separate configuration artifacts from image content to keep containerized applications portable. Secrets work similarly to ConfigMaps but are specifically meant to hold sensitive information like passwords, keys, and tokens.
💁‍♂️Let's understand more about each of them

ConfigMaps

ConfigMaps allows you to store configuration data in a key-value pair format and expose those variables as environment variables to your Containers.

Some common use cases for ConfigMaps are:

  • Storing configuration data for applications running in Containers

  • Storing configuration data for templating Pod definitions

  • Storing database credentials, API keys, passwords, etc.

Use the kubectl create configmap command to create ConfigMaps from directories, files, or literal values:

kubectl create configmap <map-name> <data-source>

You can write a ConfigMap .yaml file like this:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config 
data:
  LOG_LEVEL: INFO
  PORT: "8080"

Then you can mount the ConfigMap as an environment variable in a Pod like this:

env:
- name: LOG_LEVEL
  valueFrom:
    configMapKeyRef:
      name: app-config  
      key: LOG_LEVEL

Or mount it as a volume in a Pod and access the data as files:

volumeMounts:
- name: config-volume
  mountPath: /etc/config
volumes:
- name: config-volume
  configMap:
    name: app-config

You can pass in the --from-file argument multiple times to create a ConfigMap from multiple data sources.

You can use the following command to create a ConfigMap from an individual file, or from multiple files.

For example,

kubectl create configmap <name> --from-file=SOME_PATH/.properties

which would produce the following ConfigMapYou can display details of the ConfigMap using the following command:

kubectl describe configmap app-config

Output:

When a ConfigMap currently consumed in a volume is updated, projected keys are eventually updated as well. The kubelet checks whether the mounted ConfigMap is fresh on every periodic sync.

You can get more detailed information on all this here:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

The Kubernetes feature Immutable Secrets and ConfigMaps provides an option to set individual Secrets and ConfigMaps as immutable. You can create an immutable ConfigMap by setting the immutable field to true. For example:

apiVersion: v1
kind: ConfigMap
metadata:
  ...
data:
  ...
immutable: true

Secrets

Secrets allow you to store and manage sensitive information like passwords, OAuth tokens, and SSH keys.

They work similarly to ConfigMaps, but have some differences:

  • Secrets are stored as base64 encoded strings

  • Only root and kubelet service accounts have permission to read Secret objects by default

  • Secrets are mounted as volumes or environment variables in Pods the same way as ConfigMaps

You can create a Secret like this:

apiVersion: v1 
kind: Secret
metadata:
  name: mysql-pass
type: Opaque
data:
  password: cGFzc3dvcmQ=

Get the output as follows from this command kubectl get secret

or use the command to create from literals

kubectl create secret generic apikey --from-literal=API_KEY=123–456

Here is a YAML file to deploy Nginx using ConfigMaps and Secrets:

# ConfigMap 
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  log_level: INFO
  index.html: |
    <h1>Hello from Nginx!</h1>

# Secret    
apiVersion: v1
kind: Secret
metadata:
  name: nginx-secret 
data:
  username: YWRtaW4=
  password: cGFzc3dvcmQxMjM=

# Deployment
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: nginx-deployment
spec:
  replicas: 3 
  selector:
     matchLabels: 
       app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        envFrom:
        - configMapRef:
            name: nginx-config
        - secretRef:
            name: nginx-secret 
        ports:
        - containerPort: 80

This does the following:

  • Defines a ConfigMap called nginx-config with two keys: log_level and index.html

  • Defines a Secret called nginx-secret with username and password

  • In the Deployment:

    • It uses envFrom to populate environment variables from the ConfigMap and Secret

    • The Nginx container will have:

      • LOG_LEVEL env var from log_level key in ConfigMap

      • USERNAME and PASSWORD env vars from Secret

The main benefits are:

  • Easy updates - You can update the ConfigMap/Secret without modifying the Deployment

  • Separation of configuration - Configuration is not baked into the image

Conclusion

To conclude, The big difference between Secrets and ConfigMaps is that Secrets are obfuscated with a Base64 encoding. Since configurations are decoupled from container images, it's easier to troubleshoot configuration-related issues. It helps make applications deployed to Kubernetes more cloud-native and manageable at scale.

Thanks for reading! See you all in the next blog 🙂