How to mount Kubernetes Secrets and ConfigMaps in a Pod as a file

Here’s a quick and simple explanation on how to mount Kubernetes Secrets and ConfigMaps in a Pod as files. Imagine you have the following Kubernetes Secret:

apiVersion: v1
kind: Secret
metadata:
  name: my-secrets
stringData:
  username: admin
  password: password
  "config.toml": |
    [settings]
    enable-health-checks = true    

Mounting specific secrets by key

There are two ways to mount a Secret in a Kubernetes Pod. The first one is to mount the entire Secret as multiple files, where each key creates a single file. The second one is to mount specific keys in the Secret declaratively.

Mounting all secrets individually

Imagine now you want to mount the username field to /app/username, the password field to /app/password and the config.toml to /app/config.toml, or, in different words, using a format like /app/{secretKey} where {secretKey} is the key of the secret inside the manifest.

To mount these files explicitly, you would write the following Pod:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: nginx-container
    image: nginx:latest
    volumeMounts:
    - name: my-secrets
      mountPath: /app
      readOnly: true
  volumes:
  - name: my-secrets
    secret:
      secretName: my-secrets
      items:
      - key: username
        path: username
      - key: password
        path: password
      - key: config.toml
        path: config.toml

Accessing the pod and checking all the files in the /app directory shows the correct files:

$ kubectl exec -it my-pod -- ls -l /app
total 0
lrwxrwxrwx 1 root root 18 Apr  7 03:38 config.toml -> ..data/config.toml
lrwxrwxrwx 1 root root 15 Apr  7 03:38 password -> ..data/password
lrwxrwxrwx 1 root root 15 Apr  7 03:38 username -> ..data/username

The files are symbolic links to the actual files mounted from the Secret. This is so Kubernetes can update the files when the Secret changes and avoid restarting the Kubernetes Pod to have the pod pick up the changes.

Mounting all secrets inside the Secret

You can also avoid specifying each key and have Kubernetes load all the keys in the Secret:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: nginx-container
    image: nginx:latest
    volumeMounts:
    - name: my-secrets
      mountPath: /app
      readOnly: true
  volumes:
  - name: my-secrets
    secret:
      secretName: my-secrets

This has the benefit that any new key added to the Secret will be automatically mounted in the Pod without having to update the Pod manifest. The outcome is the same as the previous example: all the files are mounted in the /app directory as symlinks to the actual files.

Using subPath

Mounting Secrets or ConfigMaps as described before means that the folder, /app, must not exist in the container image. If it does, the contents of that folder will be removed and replaced with the contents of the Secret or ConfigMap.

To perform a more incisive mount without deleting existing files, you can use the subPath option. This option allows you to mount a Secret or ConfigMap in a subdirectory of the container image.

For example, if you want to mount the username field to /app/username, the password field to /app/password and the config.toml to /app/config.toml, you would write the following Pod:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: nginx-container
    image: nginx:latest
    volumeMounts:
    - name: my-secrets
      mountPath: /app/username
      subPath: username
      readOnly: true
    - name: my-secrets
      mountPath: /app/password
      subPath: password
      readOnly: true
    - name: my-secrets
      mountPath: /app/config.toml
      subPath: config.toml
      readOnly: true
  volumes:
  - name: my-secrets
    secret:
      secretName: my-secrets

This solution is more verbose, and you will have to define your volumeMounts for each key in the Secret or ConfigMap. However, it allows you to mount the Secret or ConfigMap in a subdirectory of the container image without deleting the existing files. You can verify this by checking the Pod:

$ kubectl exec -it my-pod -- ls -l /app
total 12
-rw-r--r-- 1 root root 39 Apr  7 03:51 config.toml
-rw-r--r-- 1 root root  8 Apr  7 03:51 password
-rw-r--r-- 1 root root  5 Apr  7 03:51 username

Note how the files are not symbolic links anymore, but actual files.