Description: In this lab, participants will learn how to create and use Secrets.
Duration: ±40m
At the end of this laboratory, each participant will be able to_
- Create a Secret object
- Use the same Secret in applications
- LAB-K8S-01 - Basic Setup
- LAB-K8S-03 - PODs
- LAB-K8S-04 - Services
- LAB-K8S-05 - Deployments
- LAB-K8S-06 - ConfigMaps
Secrets allow to store and manage sensitive information on a (key/value) model. They are commonly used for passwords, OAuth token ... Secrets objects are very similar to ConfigMaps.
⚠️ Kubernetes Secrets are not secure at all as they rely on base64 encoding, and should be avoided as much as possible in production environments. There are secure alternatives to native Secrets, such as Hashicorp Vault.Such a tool setup and usage would require a dedicated lab.
We've just been informed that a droid has just delivered under cover an encoded message in the form of a Secret inside your namespace. Let's check it out...
-
✅ Read documentation on Secrets
-
✅ Can you see the Secret object inside your namespace?
kubectl get secrets
-
✅ What does the describe command show ?
kubectl describe secrets secret-transmission-from-droid
-
✅ Show the secret content using the YAML format
kubectl get secrets secret-transmission-from-droid -o yaml
-
✅ Retrieve the content of the message entry in the data section, and decode it
kubectl get secrets secret-transmission-from-droid -o yaml | \ grep -oP "message: \K(.*)" | base64 --decode
We've been assigned an important mission, bring the Death Star plans to the Rebels. We've immediately tasked our application team to develop a way to access our broadcast message containing the plans.
This is the message we want to store safely as a Secret (we've covered already the topic of how secure this is)
MENACE! "Message from {{planet}} to all Rebels: Please bring the Death Star plans attached to this message to someone named Obi-Wan-Kenobi" + this ascii code (after the text) : https://github.com/sokube/kubernetes-training/blob/master/LAB-K8S-07/death-star-ascii
-
✅ Encode this message (base64) and insert it in a new secret named secret-transmission, inside the data field secret-transmission.txt :
kubectl create -f secret-transmission-2.yml
-
✅ Verify it's been created:
kubectl get secrets
Our Rebel-loving dev application team has quickly rushed a new version of our landing zone application and provided us a quick and dirty way to offer the transmission my mounting the secret as a file inside the container filesystem at /usr/src/app/static/transmission/. They've also provided a new link on the main page to facilitate the job of the Rebels.
- ✅ Deploy a new version of our application (image: sokubedocker:simple-todo:v2.2) and check this new "feature".
TIPS: If you don't have the previous deployments yaml files, Export your old deployment and simply add the new entries. | kubectl get deployment my-todo-deployment -o yaml > my-todo-deployment-with-secret-volume.yml
Frightening. Time to put the real message.
-
✅ Read the documentation on Pods and Secrets as volumes
-
✅ Update the deployment to mount the secret's content as files under /usr/src/app/static/transmission/ in the container. (solution here)
-
✅ Check that our message can be seen correctly
🍸 Congratulations, you've reached mastery in the management of Secrets 🍸
-
✅ Create the debug pod that we've used in LAB-K8S-08 - Persistence for debugging purposes.
kubectl create -f debug-pod.yml
-
✅ Check its description... What is this Secret that we have not defined by ourselves ?
... Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-gb7gb (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-gb7gb: Type: Secret (a volume populated by a Secret) SecretName: default-token-gb7gb Optional: false ...
-
✅ Check the default Service Account and have a look at the secret it has defined to store a token to this service. Looks familiar ?
kubectl get sa default -o yaml
apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2020-06-08T15:57:17Z" name: default namespace: tatooine resourceVersion: "554637" selfLink: /api/v1/namespaces/tatooine/serviceaccounts/default uid: ff5f1745-76a4-4790-9132-cbac285a1530 secrets: - name: default-token-gb7gb
So by default, Kubernetes will mount the token information for the Service Account that is used to run the POD in the /var/run/secrets/kubernetes.io/serviceaccount path on the containers of the POD.
-
✅ Explore the contents of this secret
kubectl get secret default-token-gb7gb -o yaml
From https://medium.com/better-programming/k8s-tips-using-a-serviceaccount-801c433d0023
There are several key/value pairs under the data key of this Secret. Basically:
- ca.crt is the Base64 encoding of the cluster certificate.
- namespace is the Base64 encoding of the current namespace
- token is the Base64 encoding of the JWT used to authenticate against the API server.
-
✅ Copy the content of the token field, and use jwt.io to parse it.
{ "iss": "kubernetes/serviceaccount", "kubernetes.io/serviceaccount/namespace": "tatooine", "kubernetes.io/serviceaccount/secret.name": "default-token-gb7gb", "kubernetes.io/serviceaccount/service-account.name": "default", "kubernetes.io/serviceaccount/service-account.uid": "ff5f1745-76a4-4790-9132-cbac285a1530", "sub": "system:serviceaccount:tatooine:default" }
-
✅ Go inside the mounted secret:
cd /run/secrets/kubernetes.io/serviceaccount/
-
✅ Copy the content of the JWT token inside a variable TOKEN (for clarity)
TOKEN=$(cat token)
-
✅ Now we can curl the kubernetes API Service using the DNS notation we've seen in LAB-K8S-04 - Services. Remember that we're not in the default namespace where this ClusterIP service is running, so we need to use the servicename.namespace notation.
curl -H "Authorization: Bearer $TOKEN" \ "https://kubernetes.default/api/v1/" --cacert ca.crt
With this mechanism, we could for example implement a monitoring application that performs queries against the Kubernetes Cluster.