1

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
  • 602
  • 1
  • 10
  • 28

2 Answers2

2

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
  • 1,416
  • 1
  • 13
  • 24
  • In both approaches, you'll have to restart your pod to see the content changed. Also, some people ended up storing one config file in one key on the secret (instead of one key per secret), because they want to read only one file from the disk. – Omer Levi Hevroni Mar 08 '19 at 06:13
  • @hernan-garcia, Thank You for the answer. Although,can you please tell me where and how to use these values? I am trying to specify in `application.yml` file as `username: /app/secrets/my-secret/username` which is obviously wrong. – Nirav Mar 08 '19 at 13:20
  • @omer-levi-hevroni, Thanks for suggestion which makes sense as I don't have to load multiple files if I store secrets in one file. Also, in [Kubernetes Docs](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-files-from-a-pod), it says `Mounted Secrets are updated automatically`. Is it something I am doing wrong? or how to mount secrets so they get updated without restarting pods? – Nirav Mar 08 '19 at 13:25
  • @nirav I wasn't aware of that. Have you checked if it working? – Omer Levi Hevroni Mar 09 '19 at 18:28
  • @OmerLeviHevroni I am not sure how to use values. Can you please tell me how to read value from `/app/secrets/my-secret/username`? – Nirav Mar 09 '19 at 19:26
  • Yes, this will be a plain text containing the value of the key "username" in the secret. This is why so many people are ending up putting a JSON in this key. Does that answer your question? – Omer Levi Hevroni Mar 09 '19 at 21:20
  • @OmerLeviHevroni, I am not sure about how to use in Spring Boot app. Can I inject it in `properties.yml` file? If yes, how it would be done? I have tried injecting in similar way to environment variable, but it is undefined. Thank you for the help. – Nirav Mar 11 '19 at 12:09
  • Let me answer that as a new answer. Can you add this specific question to the original question? e.g. how to inject the secret into secret.yaml? – Omer Levi Hevroni Mar 11 '19 at 13:58
2

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
  • 1,935
  • 1
  • 15
  • 33
  • `Kamus` would be helpful to encrypt secrets easily. Thanks for giving more information about process of creating secrets. However, in my case, I successfully created secrets and mounted them in directory. I just don't know how to read them in Spring Boot application. – Nirav Mar 11 '19 at 14:45
  • WDYM? If you follow the process I described above you'll end up with a file called `properties.yml` on the application directory and you can read that. Can you elaborate on why it does not help? – Omer Levi Hevroni Mar 11 '19 at 17:21
  • 1
    I am kind of confused how it will work. I am going to try it out today and let you know. Thank you. – Nirav Mar 12 '19 at 12:56
  • 1
    Thank you, Omer. I have tried this and works perfectly fine. I can read it from the file and use the content of the file. However, I will try to inject as configuration values in Spring Boot app. I think, I am clear from kubernetes side how it works. I just need to figure out how to use data in my application. Once I do that, I will edit question and accept your answer. – Nirav Mar 12 '19 at 15:47
  • Yay! I'm happy to hear that :) – Omer Levi Hevroni Mar 12 '19 at 17:39
  • 1
    Hi Omer, By following your answer, I was able to get properties file as mounted volumes. I have to read the file in order to get values from it. In this case, whenever secret values change, k8s will update files values after some random time. But, when I inject properties.yml file as `spring.config.location` argument, it just read once and does not update values automatically upon secret changes. I think that would be an another question. I am really thankful for this answer. – Nirav Mar 13 '19 at 13:36
  • I glad to hear you were able to solve your issue :) – Omer Levi Hevroni Mar 13 '19 at 20:00