Retrieve Kubernetes Secrets mounted as volumes

3/7/2019

Hi I am playing around with Kubernetes secrets. My deployment file is :

---
apiVersion: v1
kind: Secret
metadata:
  name: my-secrets
  labels:
    app: my-app
data:
  username: dXNlcm5hbWU=
  password: cGFzc3dvcmQ=

I am able to create secrets and I am mounting them in my deployments as below:

---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-service
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: NodePort

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-service
  labels:
    app: spring-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-service
  template:
    metadata:
      labels:
        app: spring-service
    spec:
      containers:
      - name: spring-service
        image: my-image:tag
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: my-secret-vol
          mountPath: "/app/secrets/my-secret"
          readOnly: true            
      volumes:
      - name: my-secret-vol
        secret:
          secretName: my-secrets

My question is how can I access username and password I created in secret in spring-boot app?

I have tried loading in with ${my-secrets.username} and ${username}, but it fails to find values.

I also tried adding secrets as enviroment variables as below in deployment.yml:

env:
- name: username
  valueFrom:
    secretKeyRef:
      name: my-secrets
      key: username
- name: password
  valueFrom:
    secretKeyRef:
      name: my-secrets
      key: password

In this case, values are loaded from secrets and when I change values of secrets in minikube dashboard, it does not reflect the changes.

Please help me to understand how this works.

I am using minikube and docker as containers

-- Nirav
kubernetes
kubernetes-secrets
mounted-volumes
spring-boot

2 Answers

3/7/2019

For the first approach you'll find the values on:

- /app/secrets/my-secret/username
- /app/secrets/my-secret/password 

and for the second approach you can't change the value of env vars during runtime, you need to restart or redeploy the pod

-- Hernan Garcia
Source: StackOverflow

3/11/2019

You don't inject the secret into properties.yml. Instead, you use the content of the secret as properties.yml. The process is look like the following:

  • Create a properties.yml with the sensitive data (e.g. password)
  • Base64 encode this file (e.g. base64 properties.yml).
  • Take the base64 encoded value and put that in the secret under the key properties.yaml.

You should end up with a secret in the following format:

apiVersion: v1
kind: Secret
metadata:
  name: my-secrets
  labels:
    app: my-app
data:
  properties.yml: dXNlcm5hbWU=

Now when you mount this secret on your pod, Kubernetes will decrypt the secret and put the value under the relevant path and you can just mount it.

The pattern is to have 2 configuration files - one with non-sensitive configurations that is stored with the code, and the second (which includes sensitive configurations) stored as a secret. I don't know if that possible to load multiple config files using Spring Boot.

And one final comment - this process is cumbersome and error-prone. Each change to the configuration file requires decoding the original secret and repeating this manual process. Also, it's very hard to understand what changed - all you see is the entire content has changed. For that reason, we build Kamus. It let you encrypt only the sensitive value instead of the entire file. Let me know if that could be relevant for you :)

-- Omer Levi Hevroni
Source: StackOverflow