Is there a recommended way to use Kubernetes Secrets? They can be exposed as environment variables or using a volume mount. Is one more secure than the other?
Mounted Secrets are updated automatically
When a secret being already consumed in a volume is updated, projected keys are eventually updated as well. Kubelet is checking whether the mounted secret is fresh on every periodic sync. However, it is using its local cache for getting the current value of the Secret.
in an multi container pod, each container inside a pod has to request the secret volume in its volumeMounts for it to be visible within the container. This can be used to construct useful security partition at pod level.
With above finding from official docs secret by volume mount look a better option.
Secrets
are by default safer than environment variables
, since they are encrypted and have a thinner scope than an environment variable which is exposed in the underlying environment where a process is run.
In Kubernetes
if I'm not mistaken that functionality is definitely limited to base64 encoding/decoding, so in practice it does not provide real encryption-as-a-service.
But if you are lean on providing a better security control over your application's secrets and integrating it seamlessly with Kubernetes, you should definitely check out Vault by Hashicorp, which I think it's an amazing tool and one of it's main objectives is to provide as easily as possible encryption-as-a-service and reduce problems such as the phenomenon of secret sprawling.
kubernetes secrets as the name, are objects used to store sensitive data such as user name and passwords with encryption.
example :
kubectl create secret generic cloudsql-user-credentials --from-literal=username=[user] --from-literal=password=[password]
ConfigMaps can be used to store fine-grained information: properties. yaml example:
apiVersion: v1
kind: ConfigMap
metadata:
name: example
namespace: docker4openshift
data:
app.database.name: [instance.db.name]
In general secrets are used for pass & user, configmap for database name etc.
I've also had the same question and have been looking for a definitive answer regarding environment variables vs. volumes. I can't find anything, just discussions like these. The Kuberentes documentation doesn't address this either, except to noted by DT. above, and even that is lacking a bit. Addressing some of what's discussed here I have my opinions, which aren't necessarily correct, just what I've been able to surmise. If I'm misunderstanding something I welcome corrections. Here's my understanding:
I agree with TMCs answer, but wanted to add a note for those that are thinking, "But what about 12-factor??". Objections are sometimes raised against using volume-mounted secrets because 12F seemingly requires configs be stored as ENV vars. First, these are suggested, voluntary, your-mileage-may-vary best-practices suggestions. Second, there is this section:
In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.
source: https://12factor.net/config
Basically, coupled with the rest of the description I understand the guiding principles of 12F Config management to be:
In my humble opinion, volume mounted Kubernetes Secrets can accomplish these goals depending on what sort of Secret objects you create and how you manage them.
https://www.oreilly.com/library/view/velocity-conference-2017/9781491985335/video316233.html
Kubernetes secrets exposed by environment variables may be able to be enumerated on the host via /proc/. If this is the case it's probably safer to load them via volume mounts.
I don't think there is any difference in safety. Because If a node is compromised, they can see the secret.
example:
---
apiVersion: v1
kind: Secret
metadata:
name: mount
type: Opaque
data:
foo: ""
---
apiVersion: v1
kind: Secret
metadata:
name: env
type: Opaque
data:
BAR: "BAR"
---
apiVersion: v1
kind: Pod
metadata:
name: mount
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
envFrom:
- secretRef:
name: env
volumeMounts:
- name: mount
mountPath: "/opt/mount"
readOnly: true
volumes:
- name: mount
secret:
secretName: mount
$ kubectl exec mount -- ls -la /opt/mount
total 0
drwxrwxrwt 3 root root 100 Jan 8 03:00 .
drwxr-xr-x 1 root root 19 Jan 8 03:00 ..
drwxr-xr-x 2 root root 60 Jan 8 03:00 ..2020_01_08_03_00_13.066710719
lrwxrwxrwx 1 root root 31 Jan 8 03:00 ..data -> ..2020_01_08_03_00_13.066710719
lrwxrwxrwx 1 root root 10 Jan 8 03:00 foo -> ..data/foo
$ kubectl exec mount -- env | grep BAR
BAR=
$ docker ps | grep mount
8dbde26864a4 nginx "nginx -g 'daemon of…" 8 minutes ago Up 8 minutes k8s_nginx_mount_default_3438a94b-e4af-41a7-8d85-7668fcbd9928_0
$ docker inspect 8dbde26864a4 | grep -A 1 '"Env"'
"Env": [
"BAR=",
$ docker inspect 8dbde26864a4 | grep '"Source"' | grep mount
"Source": "/var/lib/kubelet/pods/3438a94b-e4af-41a7-8d85-7668fcbd9928/volumes/kubernetes.io~secret/mount"
$ ls -la /var/lib/kubelet/pods/3438a94b-e4af-41a7-8d85-7668fcbd9928/volumes/kubernetes.io~secret/mount
合計 0
drwxrwxrwt 3 root root 100 1月 8 12:00 .
drwxr-xr-x 4 root root 46 1月 8 12:00 ..
drwxr-xr-x 2 root root 60 1月 8 12:00 ..2020_01_08_03_00_13.066710719
lrwxrwxrwx 1 root root 31 1月 8 12:00 ..data -> ..2020_01_08_03_00_13.066710719
lrwxrwxrwx 1 root root 10 1月 8 12:00 foo -> ..data/foo
And you can see the secret design proposal https://github.com/kubernetes/community/blob/master/contributors/design-proposals/auth/secrets.md
It is written like this
If a node is compromised, the only secrets that could potentially be exposed should be the secrets belonging to containers scheduled onto it
So I think the secret does not seem to guarantee the protection of the container's secret when a node is compromised.