Spring boot version: 2.4.1 Tested on Kubernetes v1.18.8 and locally reproduced on Windows file system

Kubernetes volume projection can be used to aggregate many secrets or configmaps under the same root folder to facilitate configuration usage and filtering.

This problem arises when subpaths are used to project the value. Since the first directory level is a symbolic link, Spring does not follow it, and no properties are loaded past it.

For example, following pod:

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: projected-volume
      mountPath: "/etc/config"
      readOnly: true
  volumes:
  - name: projected-volume
    projected:
      sources:
      - secret:
          name: user-secret
          items:
            - key: username
              path: my/application/credentials/username
          name: pass-secret
          items:
            - key: password
              path: my/application/credentials/password

Will generate this directory tree:

etc/
  +- config/ (volume mount point)
    +- my/ (secret projected/symlink)
      +- application/
        +- credentials/
          +- username
          +- password

Using the following application.yaml

spring:
  config:
    import:
      - configtree:/etc/config/

Spring will not load any values past the my directory and will eventually throw an exception when the property is referenced.

As a workaround we added two other levels to the projection path and added it to the configtree option forcing Spring to read past the symlink directory.

For example, following pod:

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: projected-volume
      mountPath: "/etc/config"
      readOnly: true
  volumes:
  - name: projected-volume
    projected:
      sources:
      - secret:
          name: user-secret
          items:
            - key: username
              path: a/b/my/application/credentials/username
          name: pass-secret
          items:
            - key: password
              path: a/b/my/application/credentials/password

Will generate this directory tree:

etc/
  +- config/ (volume mount point)
    +- a/  (secret projected/symlink)
      +- b/
        +- my/
          +- application/
            +- credentials/
              +- username
              +- password

Using the following application.yaml

spring:
  config:
    import:
      - configtree:/etc/config/a/b/

The two directory levels were necessary because the a directory itself is a symlink. Since b is a regular folder the properties past it will be loaded successfully.

I suspect the problem could be in the method call Files.find here where it does not use the java.nio.file.FileVisitOption.FOLLOW_LINKS option.