What are secrets?
More often than not, your applications would need to connect to some external system like a database, a messaging queue, some SaaS tools etc. These external tools would need authentication or some sort - token, username/ password, certificate etc.
Kubernetes has a resource called configMaps which allows you to have these configurations as key-value pairs. But these configMaps are plain text and can be read anyone. So, k8s came up with another resource called secrets which essentially do the same job, except they’re base64 encoded.
That obviously isn’t as secure.
Show me your secrets
“I got a little secret for you. Come here. No, closer. I don’t make deals with peasants!” - From the movie ‘Emperor’s new Groove’
In order to read secrets, you need to have the correct roles and permissions in the namespace (or cluster wide) to be able to do so. Which, in case you already have, you’re a couple of commands away from reading them secrets anyways - they’re simply base64 encoded data - remember?
So this post is about a few ways in which you can do that :-)
At the time of this writing, there are 3 types of secrets that you can create using the kubernetes API:
- generic
- docker-registry
- tls
Pre-req
I like using a nice little tool called yq
which is like a jq
or sed
for yaml files, that can be used to query through yaml documents rather neatly. You can download it here: Mike Farah’s yq github repo
Common Step - Finding what you’re looking for
Create a secret as follows:
$ kubectl create secret generic my-random-password --from-literal=username=test --from-literal=password=test # a generic type secret maybe used to call a DB or a SaaS app etc.
$ kubectl create secret docker-registry my-pvt-reg-creds --docker-username=admin --docker--password=password --docker-server=https://my-registry.com # Credentials to a potentially private image repository
Once that’s out of the way, you can list and get some basic info about the secrets you created as follows:
$ kubectl get secrets # Lists all secrets
$ kubectl get secret <secret-name> -o yaml # Select the name of the secret you want to open up
# Here, you must look at the field names inside the data key of the secret. The values of the sub-fields under data are what are base64 encoded. For example you could have field names like .dockerconfigjson, username, password, token etc. depending on the kind of secret created.
Example: Let’s assume you’re trying to crack open a secret called github-creds with username and password in them.
$ kubectl get secrets
NAME TYPE DATA AGE
default-token-k5g8j kubernetes.io/service-account-token 3 93s
github-creds Opaque 2 18s
$ kubectl get secret github-creds -o yaml
apiVersion: v1
data:
password: T2J2aW91c2x5Tm90TXlQYXNzd29yZA==
username: T2J2aW91c2x5Tm90TXlVc2VybmFtZQ==
kind: Secret
metadata:
creationTimestamp: "2020-10-20T07:25:39Z"
name: github-creds
namespace: bs
resourceVersion: "11464930"
selfLink: /api/v1/namespaces/bs/secrets/github-creds
uid: ca8b5074-718f-4496-85b5-9db94cd60ad0
type: Opaque
1. Manually Copy pasting and getting cracking the data
Copy the base64 encoded data using your cursor and put it into the following command
$ echo T2J2aW91c2x5Tm90TXlVc2VybmFtZQ== | base64 --decode # decoding the username
ObviouslyNotMyUsername # Output
$ echo T2J2aW91c2x5Tm90TXlQYXNzd29yZA== | base64 --decode # decoding the password
ObviouslyNotMyPassword # Output
2. Using with or without yq and decoding
With yq
$ kubectl get secret github-creds -o yaml | yq r - data.username | base64 --decode
ObviouslyNotMyUsername # Output
$ kubectl get secret github-creds -o yaml | yq r - data.password | base64 --decode
ObviouslyNotMyPassword # Output
Without yq
$ kubectl get secret github-creds -o="jsonpath={.data.username}" | base64 --decode
A secret of type docker-registry has a key called
.dockerconfigjson
including the preceding.
. In order to use the aforementioned command without yq to work, you must escape the.
as such:kubectl get secret github-creds -o="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
3. Consuming inside another pod
Admittedly you’d probably never be using it if all you want is to view secrets, but I thought this was cool if you wanted to so some tomfoolery with someone else’s database credentials :-)
Create a busybox pod –> mount the secrets as a volume –> access the code inside the container
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: busybox
name: busybox
spec:
containers:
- image: busybox
name: busybox
command: ["sleep"]
args: ["60000"]
resources: {}
volumeMounts:
- name: creds # mounting the volume creds into this specific container in the pod
mountPath: '/etc/creds' # path inside the container where the creds will be present
readOnly: false
dnsPolicy: ClusterFirst
restartPolicy: Never
volumes:
- name: creds
secret:
secretName: github-creds # mounting the github-creds secret as a volume on the pod
And then sh into the container and cat /etc/creds/username
or run the following command directly:
$ kubectl exec busybox -c busybox -i -t -- cat /etc/creds/username # run the cat command inside the container and print the output
ObviouslyNotMyUsername # Output
$ kubectl exec busybox -c busybox -i -t -- cat /etc/creds/password
ObviouslyNotMyPassword
Personally, I like using approach #2.
A solution
The good news is, that besides the best practices mentioned in the official kubernetes documentation, there are alternative solutions out there like hashicorp vault (Example usage) and Kamus.
Do you use some other ways to do this? Comment and tell me how!