Load mounted secrets as spring boot properties
motivation
Sometimes it is forbidden by platform or security teams to consume secrets as environments varibales (which would be the easiest way). Mounting secrets is generally considered (a little bit) more secure than using them as environmental variables in Kubernetes. Here's why:
Environmental Variables:
- Exposure in Logs: When an application logs information about its environment, which can be common during debugging or errors, any secret values set as environment variables could be accidentally leaked.
- Process Visibility: Any process running within the pod can potentially access environment variables, which could be a security risk if a process has elevated privileges.
Mounted Secrets:
Limited Access: Secrets mounted as files are typically only accessible to the application process itself, reducing the risk of unauthorized access. No Accidental Leaks: Since the secret value isn't directly embedded in the application code or configuration, accidental leaks through logging or code exposure are less.
solutions utilizing secrets
You can test the following solutions in the PoprertyLogger projekt inside your boilerplate repo.
You got the following secrets:
apiVersion: v1
kind: Secret
metadata:
name: secret-properties
stringData:
spring.datasource.url: jdbc://bla.de
password.super: secret###########
---
apiVersion: v1
kind: Secret
metadata:
name: secret-properties-2
stringData:
second_secret_entry: also_secret
Import with with spring.config.import=configtree:/
noteworthy:
- runs out of the box
- is able to read
- property keys from directory paths + filename
- or only from filename
# e.g. Deplyoment
#...
env:
- name: SPRING_CONFIG_IMPORT
# use * to use all directories on this level and start searching one layer deeper
value: "optional:configtree:/app/config/*/"
volumeMounts:
- mountPath: /app/config/firstsecret/
name: secret-properties
- mountPath: /app/config/secondsecret/
name: secret-properties-2
volumes:
- name: secret-properties
secret:
secretName: secret-properties
# using path
items:
# use same property
- key: spring.datasource.url
path: spring/datasource/url
# remap property
- key: password.super
path: spring/datasource/password
- name: secret-properties-2
secret:
secretName: secret-properties-2
# using plain files
items:
# remap property
- key: second_secret_entry
path: second.secret.entry
DEPRECATED Import with k spring.cloud.kubernetes.secrets.paths
DEPRECATED in favor of spring.config.import
see issue.
noteworthy:
- The spring boot application needs the following dependency:
org.springframework.cloud:spring-cloud-starter-kubernetes-client-config
spring.cloud.kubernetes.secrets.paths
searches recursivly so you can create one mountpoint where every secret is mounted- if you want to deactivate other features:
- management.health.kubernetes.enabled: false
- spring.cloud.kubernetes.config.enabled: true
Example yaml and conf:
# e.g. Deplyoment
#...
env:
# to prevent automatic config map discovery and stacktraces
- name: SPRING_CLOUD_KUBERNETES_CONFIG_ENABLED
value: "false"
# searches recursivly
- name: SPRING_CLOUD_KUBERNETES_SECRETS_PATHS
value: /app/secrets/
volumeMounts:
# this create one file per secret entry
- name: secret-properties
mountPath: /app/secrets/firstsecret/
- name: secret-properties-2
mountPath: /app/secrets/secondsecret/
volumes:
- name: secret-properties
secret:
secretName: secret-properties
- name: secret-properties-2
secret:
secretName: secret-properties-2
Addtional application.yaml with spring.config.additional-location
TODO
programmatically with @ConfigurationProperties
TODO
alternatives without secrets
spring cloud config server
TODO but my own expirience with this is approach is bulky.
?
TODO what other mechanismn/operators are there?