This blog post is a follow-up to a previous blog post titled “Simplify Spring Boot Access to Secrets Using Spring Cloud Kubernetes“. Despite the downsides I mentioned, I already hinted at a more straightforward solution that utilizes environment variables. The plan is to get everything into the Pod with as little configuration effort as possible.
So, I promised a twist, and here it is, thanks to one of my colleagues who pushed me in this direction. Kubernetes gives you yet another tool to handle Secrets in environment variables. This time, it is more convenient since you only point it to the complete Secret, not just a single value. Kubernetes will then make all key-value pairs available as individual environment variables.
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-gunslinger
spec:
replicas: all
template:
metadata:
spec:
containers:
- name: the-gunslinger
...
env:
- ...
envFrom:
- secretRef:
name: the-gunslinger-secret
optional: false
As you can see, envFrom
coexists alongside your other env
definitions. What does it look like in the Pod?
application_user@the-gunslinger-56d4d44b4c-b64gw:/opt/application$ env | grep aad
application_user@the-gunslinger-56d4d44b4c-b64gw:/opt/application$
application_user@the-gunslinger-56d4d44b4c-nw975:/opt/application$ env | grep spring
application_user@the-gunslinger-56d4d44b4c-nw975:/opt/application$
Success? No. But why? Reasons, I guess. There is a way around this, though. Have you heard of Spring’s relaxed binding? That means we change the secret from “lower.case” to “UPPER_SNAKE_CASE”, and everything will work as expected. It is the same value only with a different coat of paint, like lipstick on a pig. No, wait! That’s what Windows 11 is to Windows 10.
apiVersion: v1
kind: Secret
metadata:
name: the-gunslinger-secret
namespace: platform
type: Opaque
data:
AAD_PASSWORD: VGhlIG1hbiBpbiBibGFjayBmbGVkIGFjcm9zcyB0aGUgZGVzZXJ0LCBhbmQgdGhlIGd1bnNsaW5nZXIgZm9sbG93ZWQu
SPRING_DATASOURCE_PASSWORD: SSBkbyBub3QgYWltIHdpdGggbXkgaGFuZDsgaGUgd2hvIGFpbXMgd2l0aCBoaXMgaGFuZCBoYXMgZm9yZ290dGVuIHRoZSBmYWNlIG9mIGhpcyBmYXRoZXIu
Now, the output in the Pod looks as expected, and Spring Boot will find and use the values automatically due to its relaxed binding.
application_user@the-gunslinger-56d4d44b4c-b64gw:/opt/application$ env | grep AAD
AAD_PASSWORD=The man in black fled across the desert, and the gunslinger followed.
application_user@the-gunslinger-56d4d44b4c-nw975:/opt/application$ env | grep SPRING
SPRING_DATASOURCE_PASSWORD=I do not aim with my hand; he who aims with his hand has forgotten the face of his father.
What do we gain compared to Spring Cloud Kubernetes Config? There is no additional dependency with its own compatibility issues or security vulnerabilities.
On the downside, your key-value pairs do not look like the data you refer to in your application, which is typically “lower.case”. You must be aware of Spring’s relaxed binding for it to make sense.
Epilogue
The minimalist solution for simplifying the use of Secrets in a Spring Boot application would be Option #2 with the twist. Although you must be more deliberate in naming the Secret key-value pairs, it is a huge plus that no additional dependencies are required. Unless you have a use for Spring Cloud Kubernetes’ other functionality, there is no reason to utilize it just for the Secrets.
Other than that, the initial effort to set it up is basically identical. It is even shorter since mounting a volume requires two settings to be made.
Thank you for reading. I hope this was helpful.
[…] This is a simple enough approach when looking at it in isolation. Imagine your service communicates with ten or more platform services in a Cloud environment like Azure or AWS. It suddenly becomes tedious. There is a slight twist coming, though, which I will explain in a follow-up blog post (it is already written, I swear!). […]
LikeLike