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.
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.
One thought on “Simplify Spring Boot Access to Kubernetes Secrets Using Environment Variables”
[…] 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!). […]