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.