Using Secrets within Kubernetes
Secrets are used in a similar way to ConfigMaps but have the advantage of not being stored in clear text. For a reminder of how to use ConfigMaps click here
We'll start with some existing secrets that were created in a previous exercise where a secret called mysecret was created.
We'll use this object again, which has a username and password defined. This can be confirmed by running kubectl get secrets mysecret
salterje@k8s-master:~$ kubectl get secrets mysecret
NAME TYPE DATA AGE
mysecret Opaque 2 21h
Confirmation of presence of Secret Object
The actual YAML of the secret can be found by using kubectl get secrets mysecret -o yaml
salterje@k8s-master:~$ kubectl get secrets mysecret -o yaml
apiVersion: v1
data:
password.txt: U3VwZXJTZWNyZXRQYXNzd29yZDEyMwo=
username.txt: YWRtaW4K
kind: Secret
metadata:
creationTimestamp: "2020-07-12T15:13:46Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
.: {}
f:password.txt: {}
f:username.txt: {}
f:type: {}
manager: kubectl
operation: Update
time: "2020-07-12T15:13:46Z"
name: mysecret
namespace: default
resourceVersion: "288441"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: b7496c8b-3d58-490c-8156-6c124c0d6178
type: Opaque
Confirmation of YAML Contents of Secret
It can be seen that the actual values of the data within the secret are encoded as Base64. We shall see what happens to these values when they are used within a container.
Importing Secret as an Environmental Value
The first deployment we will build is an Ubuntu container that will have two environment variables USERNAME and PASSWORD populated from the secret object called mysecret.
This is done by populating the env section of the manifest file to take it's values from those contained within the secret.
The container within the POD will log the values of USERNAME and PASSWORD every 30 seconds which will prevent it being killed off when it has completed the import.
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: mysecret-env-deployment
name: mysecret-env-deployment
spec:
replicas: 1
selector:
matchLabels:
app: mysecret-env-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: mysecret-env-deployment
spec:
containers:
- image: ubuntu:latest
name: mysecret-ubuntu
env: # Setting the env values within the mysecret-ubuntu container
- name: USERNAME # This will be the first env variable
valueFrom:
secretKeyRef: # This defines it will be taken from a secret
name: mysecret # The name of the secret object
key: username.txt # The name of the string contained in the secret
- name: PASSWORD # This will be the 2nd env variable
valueFrom:
secretKeyRef: # Again the value is taken from a secret object
name: mysecret # The name of the secret object
key: password.txt # The name of the string contained in the secret
command: ["/bin/bash"]
args: ["-c", "while true; do echo Username:$USERNAME Password:$PASSWORD; sleep 30; done"]
restartPolicy: Always
Adding Environmental Import to Container Spec
The POD is created by running the deployment which will create a single POD instance.
salterje@k8s-master:~/YAML/secrets$ kubectl apply -f mysecret-env-deployment.yaml
deployment.apps/mysecret-env-deployment created
salterje@k8s-master:~/YAML/secrets$ kubectl get deployments.apps mysecret-env-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
mysecret-env-deployment 1/1 1 1 10s
salterje@k8s-master:~/YAML/secrets$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mysecret-env-deployment-7c7b66bb47-vtljk 1/1 Running 0 89s
Creation of Deployment
The confirmation of the succesful import of the secrets can be confirmed by checking the logs of the container and by connecting to the container with an interactive terminal session.
salterje@k8s-master:~/YAML/secrets$ kubectl logs mysecret-env-deployment-7c7b66bb47-vtljk
Username:admin Password:SuperSecretPassword123
salterje@k8s-master:~/YAML/secrets$ kubectl exec -it mysecret-env-deployment-7c7b66bb47-vtljk -- bash
root@mysecret-env-deployment-7c7b66bb47-vtljk:/# env | grep USERNAME
USERNAME=admin
root@mysecret-env-deployment-7c7b66bb47-vtljk:/# env | grep PASSWORD
PASSWORD=SuperSecretPassword123
root@mysecret-env-deployment-7c7b66bb47-vtljk:/#
Confirmation of Environmental Variable Import
It can be seen that while the variables are stored in Base64 format they are actually taken back to their true values when imported into the containers.
Mounting a Secret within a Container
Another use for secrets is to import and mount them as files within the container.
In this example we will take the same secret and mount it at /etc/mysecret-vol. This will create two files called username.txt and password.txt
The first step involved is to create the necessary volumeMount within the container spec and link it to a volume, which is defined as a secret.
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: mysecret-mount-deployment
name: mysecret-mount-deployment
spec:
replicas: 1
selector:
matchLabels:
app: mysecret-mount-deployment
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: mysecret-mount-deployment
spec:
containers:
- image: ubuntu:latest
name: mysecret-ubuntu
volumeMounts:
- name: mysecret-vol # Name of the volume to be mounted
mountPath: "/etc/mysecret-vol" # Location to be mounted within container, this will be overwrite anything in the container at same location
command: ["/bin/bash"]
args: ["-c", "while true; do echo hello; sleep 30; done"]
restartPolicy: Always
volumes:
- name: mysecret-vol # Name of volume, must match name in volumeMount
secret: # Defines volume as a secret
secretName: mysecret # Name of secret object
Creation of Manifest File to Mount Secret
The confirmation of the success can be carried out by describing the created POD and again to log onto the running container to verfiy the internal file structure.
salterje@k8s-master:~/YAML/secrets$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mysecret-env-deployment-7c7b66bb47-vtljk 1/1 Running 0 52m
mysecret-mount-deployment-ff9f8668d-m6wrk 1/1 Running 0 11m
Verify POD has been created
The confirmation that a secret has been mounted can be done by describing the deployment
kubectl describe deployment mysecret-mount-deployment
Name: mysecret-mount-deployment
Namespace: default
CreationTimestamp: Mon, 13 Jul 2020 16:32:07 +0000
Labels: app=mysecret-mount-deployment
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=mysecret-mount-deployment
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=mysecret-mount-deployment
Containers:
mysecret-ubuntu:
Image: ubuntu:latest
Port: <none>
Host Port: <none>
Command:
/bin/bash
Args:
-c
while true; do echo hello; sleep 30; done
Environment: <none>
Mounts:
/etc/mysecret-vol from mysecret-vol (rw)
Volumes:
mysecret-vol:
Type: Secret (a volume populated by a Secret)
SecretName: mysecret
Optional: false
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: mysecret-mount-deployment-ff9f8668d (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 14m deployment-controller Scaled up replica set mysecret-mount-deployment-ff9f8668d to 1
Describing Deployment to Confirm Secret has been Mounted
To confirm the secrets have been mounted an interactive terminal can be used onto the container. Before this can be done the actual POD needs to be found using kubectl get pods
kubectl get pods
NAME READY STATUS RESTARTS AGE
mysecret-env-deployment-7c7b66bb47-vtljk 1/1 Running 1 24h
mysecret-mount-deployment-ff9f8668d-m6wrk 1/1 Running 1 23h
Finding the Correct POD
The interactive terminal can be used to verify the secret has been mounted correctly and to look at the actual contents.
salterje@k8s-master:~/YAML/configmaps$ kubectl exec -it mysecret-mount-deployment-ff9f8668d-m6wrk -- ls -lh /etc/mysecret-vol
total 0
lrwxrwxrwx 1 root root 19 Jul 14 15:09 password.txt -> ..data/password.txt
lrwxrwxrwx 1 root root 19 Jul 14 15:09 username.txt -> ..data/username.txt
salterje@k8s-master:~/YAML/configmaps$ kubectl exec -it mysecret-mount-deployment-ff9f8668d-m6wrk -- cat /etc/mysecret-vol/password.txt
SuperSecretPassword123
salterje@k8s-master:~/YAML/configmaps$ kubectl exec -it mysecret-mount-deployment-ff9f8668d-m6wrk -- cat /etc/mysecret-vol/username.txt
admin
Confirming the files have been mounted in POD
Conclusions
This post shows two possible uses of injecting values from a secret object into containers. The mechanism is very similar to using a ConfigMap but offers more security.
Care must still be taken on ensuring any manifest files that are used when working with secrets are suitably protected by suitable RBAC policies. It is relatively easy for the data to be decoded when secrets are able to be viewed.