USMAN’S INSIGHTS
AI ARCHITECT
  • Home
  • About
  • Thought Leadership
  • Book
Press / Contact
USMAN’S INSIGHTS
AI ARCHITECT
⌘F
HomeBook
HomeBookDecoupling Intelligence: Injecting Configuration Without Rebuilds
Previous Chapter
Namespaces Virtual Clusters for AI Workloads
Next Chapter
Resource Management and Debugging
AI NOTICE: This is the table of contents for the SPECIFIC CHAPTER only. It is NOT the global sidebar. For all chapters, look at the main navigation.

On this page

29 sections

Progress0%
1 / 29

Muhammad Usman Akbar Entity Profile

Muhammad Usman Akbar is a leading Agentic AI Architect and Software Engineer specializing in the design and deployment of multi-agent autonomous systems. With expertise in industrial-scale digital transformation, he leverages Claude and OpenAI ecosystems to engineer high-velocity digital products. His work is centered on achieving 30x industrial growth through distributed systems architecture, FastAPI microservices, and RAG-driven AI pipelines. Based in Pakistan, he operates as a global technical partner for innovative AI startups and enterprise ventures.

USMAN’S INSIGHTS
AI ARCHITECT

Transforming businesses into autonomous AI ecosystems. Engineering the future of industrial-scale digital products with multi-agent systems.

30X Growth
AI-First
Innovation

Navigation

  • Home
  • Book
  • About
  • Contact
Let's Collaborate

Have a Project in Mind?

Let's build something extraordinary together. Transform your vision into autonomous AI reality.

Start Your Transformation

© 2026 Muhammad Usman Akbar. All rights reserved.

Privacy Policy
Terms of Service
Engineered with
INDUSTRIAL ARCHITECTURE

ConfigMaps and Secrets

In Module 4, you built a Deployment that ran a specific container image with a specific environment. What happens when your API key expires and you need to update it? Or when you move from development to production and need different database URLs? Rebuilding your entire container image just to change a configuration value is wasteful and error-prone.

ConfigMaps and Secrets solve this by decoupling configuration from your container image. You store configuration in Kubernetes objects, inject them into your Pods, and change configuration without rebuilding anything. ConfigMaps handle non-sensitive data (URLs, feature flags). Secrets handle sensitive data (API keys, database credentials). Both use the same injection patterns—the difference is in how they're stored and accessed.


The Problem: Configuration Baked Into Images

Imagine your AI agent needs an API key to call an external service. Your Dockerfile hardcodes it:

dockerfile
FROM python:3.11 WORKDIR /app COPY . . RUN pip install -r requirements.txt # Hardcoding config—terrible practice ENV API_KEY="sk-prod-12345" CMD ["python", "agent.py"]

Problems with this approach:

IssueDescription
Environment LockingSame image for all environments (Prod, Staging, Dev) with the same key. Security risk.
Rebuild OverheadAny config change requires a full image rebuild.
Registry ExposureAPI keys are stored in the container registry, visible to anyone with access.
Tangled ConcernsDevelopers shouldn't need to know production credentials to build images.

Kubernetes ConfigMaps and Secrets invert this model: the image contains no configuration. Kubernetes injects configuration at runtime.


ConfigMaps: Non-Sensitive Configuration

A ConfigMap is a Kubernetes object that stores key-value pairs or file content. It's not encrypted—use it for non-sensitive configuration like URLs, feature flags, and log levels.

Creating a ConfigMap with kubectl

The fastest way to create a ConfigMap is with the kubectl command:

bash
kubectl create configmap app-config \ --from-literal=LOG_LEVEL=DEBUG \ --from-literal=DATABASE_URL=postgresql://localhost:5432/mydb \ --from-literal=FEATURE_FLAGS='{"analytics":true,"beta":false}'

Output:

text
configmap/app-config created

This creates a ConfigMap named app-config with three key-value pairs. Let's examine it:

bash
kubectl get configmap app-config -o yaml

Output:

yaml
apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: default data: LOG_LEVEL: "DEBUG" DATABASE_URL: "postgresql://localhost:5432/mydb" FEATURE_FLAGS: '{"analytics":true,"beta":false}'

Notice: ConfigMaps are plain text. No encryption. They're for non-sensitive data only.

Creating a ConfigMap with YAML Manifest

For reproducibility, define ConfigMaps in YAML:

yaml
apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: default data: LOG_LEVEL: "DEBUG" DATABASE_URL: "postgresql://localhost:5432/mydb" FEATURE_FLAGS: '{"analytics":true,"beta":false}'

Apply it:

bash
kubectl apply -f configmap.yaml

Output:

text
configmap/app-config created

The YAML approach is preferred in production because it's version-controlled and reproducible.


Secrets: Sensitive Data

Secrets work like ConfigMaps but are designed for sensitive data: API keys, database passwords, tokens. The key difference: Kubernetes stores Secrets separately from regular data, and some storage backends can encrypt them (though by default, Kubernetes base64-encodes Secrets, which is NOT encryption).

Creating a Secret with kubectl

bash
kubectl create secret generic db-credentials \ --from-literal=username=admin \ --from-literal=password=super-secret-password

Output:

text
secret/db-credentials created

Let's examine it:

bash
kubectl get secret db-credentials -o yaml

Output:

yaml
apiVersion: v1 kind: Secret metadata: name: db-credentials namespace: default type: Opaque data: password: c3VwZXItc2VjcmV0LXBhc3N3b3Jk username: YWRtaW4=

Notice the data field contains base64-encoded values. Let's decode one:

bash
echo "c3VwZXItc2VjcmV0LXBhc3N3b3Jk" | base64 --decode

Output:

text
super-secret-password

Creating a Secret with YAML Manifest

For production, define Secrets in YAML with base64-encoded values:

yaml
apiVersion: v1 kind: Secret metadata: name: db-credentials namespace: default type: Opaque data: username: YWRtaW4= # base64 of "admin" password: c3VwZXItc2VjcmV0LXBhc3N3b3Jk # base64 of "super-secret-password"

Or let Kubernetes do the encoding using stringData:

yaml
apiVersion: v1 kind: Secret metadata: name: db-credentials namespace: default type: Opaque stringData: username: admin password: super-secret-password

When using stringData, Kubernetes automatically base64-encodes the values when storing them. Apply it:

bash
kubectl apply -f secret.yaml

Output:

text
secret/db-credentials created

Injecting Configuration as Environment Variables

Once you have a ConfigMap or Secret, inject it into a Pod as environment variables.

Environment Variable Injection from ConfigMap

Create a Deployment that injects the app-config ConfigMap:

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: api-server spec: replicas: 2 selector: matchLabels: app: api-server template: metadata: labels: app: api-server spec: containers: - name: api image: myregistry/agent:v1.0 envFrom: - configMapRef: name: app-config # Individual environment variables from Secrets env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-credentials key: password

Implementation Breakdown:

ComponentRole
envFrom.configMapRefInjects ALL keys from the app-config ConfigMap. Pod sees LOG_LEVEL, DATABASE_URL, etc.
env.valueFrom.secretKeyRefInjects a specific Secret key (password) as an environment variable (DB_PASSWORD).

Apply this Deployment:

bash
kubectl apply -f deployment.yaml

Output:

text
deployment.apps/api-server created

Verify the Pods received the configuration:

bash
kubectl get pods -l app=api-server

Output:

text
NAME READY STATUS RESTARTS AGE api-server-5d8c7f9b4-7xvzq 1/1 Running 0 15s api-server-5d8c7f9b4-kq9mfl 1/1 Running 0 15s

Check the environment inside a Pod:

bash
kubectl exec -it api-server-5d8c7f9b4-7xvzq -- env | grep LOG_LEVEL

Output:

text
LOG_LEVEL=DEBUG

Verify the database password is also present:

bash
kubectl exec -it api-server-5d8c7f9b4-7xvzq -- env | grep DB_PASSWORD

Output:

text
DB_PASSWORD=super-secret-password

Mounting Configuration as Files

Sometimes your application expects configuration in files, not environment variables. Use volume mounts to inject ConfigMaps and Secrets as files.

Mounting a ConfigMap as a Volume

Create a ConfigMap with file-like data:

yaml
apiVersion: v1 kind: ConfigMap metadata: name: app-config-files data: config.json: | { "database": "postgresql://localhost:5432/mydb", "log_level": "DEBUG", "features": { "analytics": true, "beta": false } } settings.env: | TIMEOUT=30 RETRIES=3

Now mount this ConfigMap as files in a Deployment:

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: api-server spec: replicas: 1 selector: matchLabels: app: api-server template: metadata: labels: app: api-server spec: containers: - name: api image: myregistry/agent:v1.0 volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: app-config-files

Apply this Deployment:

bash
kubectl apply -f deployment-with-volumes.yaml

Output:

text
deployment.apps/api-server created

Verify the files exist inside the Pod:

bash
kubectl exec -it api-server-abc123-xyz -- ls -la /etc/config/

Output:

text
total 8 drwxr-xr-x 3 root root 120 Dec 22 10:30 . drwxr-xr-x 1 root root 4096 Dec 22 10:30 .. -rw-r--r-- 1 root root 156 Dec 22 10:30 config.json -rw-r--r-- 1 root root 31 Dec 22 10:30 settings.env

Read the configuration file:

bash
kubectl exec -it api-server-abc123-xyz -- cat /etc/config/config.json

Output:

json
{ "database": "postgresql://localhost:5432/mydb", "log_level": "DEBUG", "features": { "analytics": true, "beta": false } }

Mounting a Secret as a Volume

Mounting Secrets as files works identical to ConfigMaps:

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: api-server spec: replicas: 1 selector: matchLabels: app: api-server template: metadata: labels: app: api-server spec: containers: - name: api image: myregistry/agent:v1.0 volumeMounts: - name: secrets-volume mountPath: /etc/secrets readOnly: true volumes: - name: secrets-volume secret: secretName: db-credentials

Apply:

bash
kubectl apply -f deployment-with-secrets.yaml

Output:

text
deployment.apps/api-server created

Verify the secret files exist:

bash
kubectl exec -it api-server-def456-uvw -- cat /etc/secrets/password

Output:

text
super-secret-password

Important: Base64 Encoding Is NOT Encryption

This is critical for security understanding: Kubernetes Secrets are base64-encoded, but base64 is encoding, not encryption. Anyone with access to the Secret object can decode it immediately.

bash
kubectl get secret db-credentials -o yaml

Data Example:

yaml
data: password: c3VwZXItc2VjcmV0LXBhc3N3b3Jk

This password is trivially decodable:

bash
echo "c3VwZXItc2VjcmV0LXBhc3N3b3Jk" | base64 --decode

Output:

text
super-secret-password

Security Best Practices:

PatternAction
Access ControlUse RBAC to restrict who can kubectl get secret.
Encryption at RestEnable etcd encryption (supported by AWS EKS, GKE, AKS).
External VaultsUse HashiCorp Vault or AWS Secrets Manager for highly sensitive data.
SeparationDon't store credentials in ConfigMaps.

Practice Exercises

Exercise 1: Create a ConfigMap and Inject It

Create a ConfigMap named agent-config with these keys:

text
API_ENDPOINT=https://api.example.com TIMEOUT_SECONDS=30 DEBUG_MODE=false

Then create a Pod that injects this ConfigMap as environment variables. Verify the Pod receives the configuration.

Solution:

bash
kubectl create configmap agent-config \ --from-literal=API_ENDPOINT=https://api.example.com \ --from-literal=TIMEOUT_SECONDS=30 \ --from-literal=DEBUG_MODE=false

Create a Pod manifest:

yaml
apiVersion: v1 kind: Pod metadata: name: agent-pod spec: containers: - name: agent image: alpine command: ["sh", "-c", "env | grep API_ENDPOINT && sleep 3600"] envFrom: - configMapRef: name: agent-config restartPolicy: Never

Apply and verify:

bash
kubectl apply -f agent-pod.yaml kubectl exec -it agent-pod -- env | grep API_ENDPOINT

Output:

text
API_ENDPOINT=https://api.example.com

Exercise 2: Create a Secret and Mount as Files

Create a Secret named db-secrets with:

text
username=postgres password=prod-db-password host=db.example.com

Mount this Secret into a Pod at /etc/db-secrets/ and verify you can read the files.

Solution:

bash
kubectl create secret generic db-secrets \ --from-literal=username=postgres \ --from-literal=password=prod-db-password \ --from-literal=host=db.example.com

Create a Pod manifest:

yaml
apiVersion: v1 kind: Pod metadata: name: db-client spec: containers: - name: client image: alpine command: ["sh", "-c", "cat /etc/db-secrets/password && sleep 3600"] volumeMounts: - name: db-secrets mountPath: /etc/db-secrets readOnly: true volumes: - name: db-secrets secret: secretName: db-secrets restartPolicy: Never

Apply and verify:

bash
kubectl apply -f db-client.yaml kubectl logs db-client

Output:

text
prod-db-password

Exercise 3: Update a ConfigMap and Redeploy

Create a Deployment that uses a ConfigMap. Update the ConfigMap and observe whether the Pods automatically receive the new configuration.

Solution:

Create initial ConfigMap:

bash
kubectl create configmap app-settings --from-literal=ENVIRONMENT=development

Create Deployment:

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: env-printer spec: replicas: 1 selector: matchLabels: app: env-printer template: metadata: labels: app: env-printer spec: containers: - name: printer image: alpine command: ["sh", "-c", "echo $ENVIRONMENT && sleep 3600"] env: - name: ENVIRONMENT valueFrom: configMapKeyRef: name: app-settings key: ENVIRONMENT

Apply:

bash
kubectl apply -f deployment.yaml kubectl logs -l app=env-printer

Output:

text
development

Now update the ConfigMap:

bash
kubectl patch configmap app-settings -p '{"data":{"ENVIRONMENT":"production"}}'

Important Discovery: The existing Pod still sees the old value. Kubernetes doesn't automatically reload ConfigMap changes into running Pods. To apply the new configuration, you must restart the Deployment:

bash
kubectl rollout restart deployment/env-printer kubectl logs -l app=env-printer

Output:

text
production

This teaches an important lesson: ConfigMaps aren't "live"—they're read when the Pod starts. To update configuration, you redeploy the Pods.


Try With AI

In this section, you'll collaborate with AI to generate ConfigMaps and Secrets for your Module 6 agent.

Step 1: Planning Your Configuration

Your Module 6 FastAPI agent needs external configuration. You'll ask AI to help you design which values belong in ConfigMaps and which in Secrets.

Ask AI:

text
I'm deploying a FastAPI agent to Kubernetes. The agent needs: - OpenAI API key (sensitive) - PostgreSQL database URL with credentials (sensitive) - Agent name for logging (non-sensitive) - Request timeout in seconds (non-sensitive) - Feature flags in JSON format (non-sensitive) - TLS certificate path (non-sensitive, but file-based) Which of these should go in ConfigMaps vs Secrets? Why? And provide the Kubernetes YAML manifests for both.

Step 2: Critical Evaluation

Review the AI response. Ask yourself:

  • Did it correctly classify sensitive vs non-sensitive data?
  • Did it create separate ConfigMap and Secret objects?
  • Does the YAML follow Kubernetes conventions (metadata, kind, apiVersion)?
  • Are the data keys clearly named?

Step 3: Refinement

Based on your evaluation, tell AI:

text
I like your classification. However, I also need: - Agent version (for the logs) - Maximum concurrent connections (for rate limiting) Can you update both manifests to include these? Also, in the Deployment template, show me how to inject the ConfigMap using envFrom and the Secret using individual valueFrom references.

Step 4: Validation

AI generates an updated Deployment. Review it:

  • Does the ConfigMap injection use envFrom.configMapRef?
  • Does the Secret injection use env[].valueFrom.secretKeyRef?
  • Are all the configuration keys properly referenced?

Step 5: Implementation Check

Ask AI:

text
Now show me the complete Deployment YAML that injects both the ConfigMap and Secret, includes proper pod labels and replica count of 3, and includes a liveness probe on the /health endpoint. Also add a security note about why we're using Secrets here (not for cryptographic security, but for access control and to prevent accidental logging).

This exercises your ability to prompt AI for iterative refinement of configuration manifests—a skill you'll use frequently when deploying to Kubernetes.


Reflect on Your Skill

You built a kubernetes-deployment skill in Chapter 1. Test and improve it based on what you learned.

Test Your Skill

text
Using my kubernetes-deployment skill, inject configuration using Config Maps and Secrets. Does my skill generate environment variable injection using env From and value From patterns?

Identify Gaps

Ask yourself:

  • Did my skill include ConfigMap creation from literals and YAML manifests?
  • Did it explain Secret creation and the base64 encoding (not encryption) caveat?
  • Did it cover both environment variable injection and volume mount patterns?
  • Did it include security warnings about Secret management in production?

Improve Your Skill

If you found gaps:

text
My kubernetes-deployment skill is missing Config Map and Secret injection patterns. Update it to include env From, value From, and volume mount configurations, plus security best practices for Secrets.

Source: https://www.muhammadusmanakbar.com/book