Kubernetes
configMap
secret
devops
configuration

Concating values from configMap and secret

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Kubernetes, combining values from a ConfigMap and a Secret is a common requirement for building connection strings or application settings. Kubernetes does not provide direct string concatenation inside manifest field values. The usual solution is to inject separate environment variables and compose them at container startup.

Inject ConfigMap and Secret Values Separately

First, load each value into its own environment variable.

yaml
1apiVersion: v1
2kind: Pod
3metadata:
4  name: app-pod
5spec:
6  containers:
7    - name: app
8      image: busybox:1.36
9      command: ["sh", "-c", "echo ready && sleep 3600"]
10      env:
11        - name: DB_HOST
12          valueFrom:
13            configMapKeyRef:
14              name: app-config
15              key: db_host
16        - name: DB_PASSWORD
17          valueFrom:
18            secretKeyRef:
19              name: app-secret
20              key: db_password

This keeps secret and non-secret configuration clearly separated.

Compose Values in the Startup Command

Build the final value at runtime in the shell command or entrypoint script.

yaml
1apiVersion: v1
2kind: Pod
3metadata:
4  name: app-pod
5spec:
6  containers:
7    - name: app
8      image: busybox:1.36
9      command:
10        - sh
11        - -c
12        - |
13          export DB_URL="postgres://user:${DB_PASSWORD}@${DB_HOST}:5432/appdb"
14          echo "$DB_URL" | sed 's/:.*@/:***@/'
15          sleep 3600
16      env:
17        - name: DB_HOST
18          valueFrom:
19            configMapKeyRef:
20              name: app-config
21              key: db_host
22        - name: DB_PASSWORD
23          valueFrom:
24            secretKeyRef:
25              name: app-secret
26              key: db_password

Do not print raw secrets in logs. The masking command above is only for demonstration.

Use an Entrypoint Script for Complex Logic

For larger applications, put composition logic in a script file. This keeps manifests readable and easier to review.

bash
1#!/usr/bin/env sh
2set -eu
3
4DB_URL="postgres://user:${DB_PASSWORD}@${DB_HOST}:5432/appdb"
5export DB_URL
6exec ./app-binary

Mount the script from your image or a ConfigMap and use it as the container command.

Alternative: Projected Volume and App-Side Composition

Another approach is mounting ConfigMap and Secret files and letting the app combine them at runtime. This avoids shell-specific behavior and keeps logic in application code.

yaml
1volumes:
2  - name: app-config-volume
3    projected:
4      sources:
5        - configMap:
6            name: app-config
7        - secret:
8            name: app-secret

This is useful when startup logic is complex or multiple services share the same composition rule.

Security and Rotation Considerations

Keep Secret data minimal and rotate credentials regularly. If your platform supports external secret managers, sync into Kubernetes as late as possible. Also ensure RBAC limits who can read Secret objects, and avoid embedding combined connection strings into ConfigMaps because that can leak sensitive data to broader audiences.

Init Container Pattern for Derived Values

If multiple containers in a pod need the same derived value, use an init container to compose it once and write it to a shared volume file.

yaml
1apiVersion: v1
2kind: Pod
3metadata:
4  name: app-with-init
5spec:
6  volumes:
7    - name: runtime-config
8      emptyDir: {}
9  initContainers:
10    - name: build-config
11      image: busybox:1.36
12      command:
13        - sh
14        - -c
15        - |
16          echo "DB_URL=postgres://user:${DB_PASSWORD}@${DB_HOST}:5432/appdb" > /config/runtime.env
17      env:
18        - name: DB_HOST
19          valueFrom:
20            configMapKeyRef:
21              name: app-config
22              key: db_host
23        - name: DB_PASSWORD
24          valueFrom:
25            secretKeyRef:
26              name: app-secret
27              key: db_password
28      volumeMounts:
29        - name: runtime-config
30          mountPath: /config

Main containers can read /config/runtime.env consistently. This avoids duplicate composition logic in multiple entrypoints.

Document this contract so platform and application teams keep configuration responsibilities aligned.

Common Pitfalls

A frequent pitfall is trying to concatenate variables directly in the env.value field, expecting shell expansion where it does not happen. Another issue is storing concatenated secret-containing values in ConfigMaps, which weakens separation and access control. Teams also sometimes echo full connection strings during startup diagnostics, exposing credentials in logs. Finally, if an app reads values before entrypoint composition runs, configuration may appear missing. Ensure initialization order is explicit and tested.

Summary

  • Kubernetes does not natively concatenate ConfigMap and Secret values in manifests.
  • Inject values separately and compose them at startup.
  • Use entrypoint scripts for readable and reusable composition logic.
  • Prefer app-side composition when logic is complex.
  • Protect secrets by avoiding raw logging and loose access policies.

Course illustration
Course illustration

All Rights Reserved.