Secrets and ConfigMaps

KubernetesBeginner
Practice Now

Introduction

In software, hard-coding settings such as database URLs or passwords into application code is a bad practice. It makes changes harder and increases security risk.

Kubernetes addresses this with two objects:

  1. ConfigMap: Think of this as a Public Notice Board. You pin information here (like "The background color is blue" or "The database address is 10.0.0.1"). Anyone in the office (Pods) can read it.
  2. Secret: Used for sensitive values such as passwords or tokens.

This separation between application code and runtime configuration is a major platform design principle, not just a Kubernetes feature.

In this lab, you will:

  • Write a note on the Notice Board (ConfigMap).
  • Put a password in the Safe (Secret).
  • Teach a Pod how to read both.

Create a ConfigMap

Let's create a configuration file for a web server. Instead of baking it into the image, we will store it in a ConfigMap.

This pattern is part of a bigger container design principle: build one reusable image, then supply environment-specific configuration at runtime. That keeps the image more portable because development, staging, and production can use the same container but different settings.

First, create a simple Nginx configuration file named nginx.conf:

echo 'events {} http { server { listen 80; location / { return 200 "Hello from ConfigMap!"; } } }' > nginx.conf

Now, create a ConfigMap named nginx-config from this file. This effectively "pins" the file to the Kubernetes cluster's notice board.

kubectl create configmap nginx-config --from-file=nginx.conf

Verify it exists:

kubectl describe configmap nginx-config

You should see the content of your nginx.conf listed under the "Data" section.

Create a Secret

Now, let's store something sensitive. A Secret works similarly to a ConfigMap, but Kubernetes treats it with extra care (it obfuscates the data in storage).

It is important to be precise here: a Secret is safer than hard-coding passwords into manifests or images, but base64 encoding is not real encryption. In production, Secret handling is often combined with encryption at rest, tighter RBAC, and external secret-management systems.

Create a Secret named app-secret to store a dummy password:

kubectl create secret generic app-secret --from-literal=password=SuperSecretPass123

Verify it exists:

kubectl get secret app-secret

If you look at the details, you won't see the password directly. It will be hidden (encoded).

kubectl get secret app-secret -o yaml

Notice the password field is a scramble of characters. This is base64 encoding, designed to prevent "shoulder surfing" or accidental display in logs.

Mount ConfigMap as File

Now, let's teach a Pod how to read the Notice Board.

The most common way to use a ConfigMap is to Mount it as a file. It appears inside the container just like a regular file on disk.

This file-based approach is useful when an application already expects a configuration file at a certain path. Kubernetes projects the ConfigMap data into the container filesystem so the application can keep using its normal file-reading behavior.

Create a file named pod-config.yaml:

nano pod-config.yaml

Paste the following. This Pod mounts the nginx-config map into /etc/nginx/nginx.conf.

apiVersion: v1
kind: Pod
metadata:
  name: config-pod
spec:
  containers:
    - name: nginx
      image: nginx:alpine
      volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
  volumes:
    - name: config-volume
      configMap:
        name: nginx-config

Save and exit (Ctrl+X, Y, Enter).

Apply it:

kubectl apply -f pod-config.yaml

Wait a few seconds for it to start. Now, let's peek inside the container to see if the file is there:

kubectl exec config-pod -- cat /etc/nginx/nginx.conf

You should see your custom configuration! The Pod essentially "read the notice board" and used that file.

Inject Secret as Env Var

Now for the Secret. A common way to pass passwords is via Environment Variables.

This method is convenient, but it also teaches a tradeoff. Environment variables are easy for applications to read, yet they can be exposed by diagnostic commands or process inspection. Kubernetes supports both file-based and environment-variable injection because different applications and risk profiles need different approaches.

Create a file named pod-secret.yaml:

nano pod-secret.yaml

Paste the following. This Pod grabs the password from the app-secret and assigns it to an environment variable called APP_PASSWORD.

apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
    - name: busybox
      image: busybox
      command: ["sleep", "3600"]
      env:
        - name: APP_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: password

Save and exit (Ctrl+X, Y, Enter).

Apply it:

kubectl apply -f pod-secret.yaml

Once running, let's check the environment variables inside the container:

kubectl exec secret-pod -- env | grep APP_PASSWORD

You should see APP_PASSWORD=SuperSecretPass123.

The magic here is that the Pod definition doesn't contain the password. The password lives in the "Safe" (Secret), and the Pod just has a key to open it at runtime.

Summary

In this lab, you practiced separating code from configuration.

You successfully:

  1. Used a ConfigMap (Notice Board) to inject a config file into a server.
  2. Used a Secret (Safe) to inject a hidden password into an application.

By doing this, you can now update your configuration or rotate your passwords without ever having to rebuild your Docker images!