Kubernetes / kubectl print all secrets - kubernetes

I would like to use kubectl to print out all key-value pairs in my Secrets. I cannot figure out how to do this in one line with the -o --jsonpath flag or by piping into jq. I could certainly make a script to do this but I feel there must be a better way, given that the kubernetes GUI is pretty straightforward and liberal when it comes to letting you view Secrets.
Say I create secret like so:
kubectl create secret generic testsecret --from-literal=key1=val1 --from-literal=key2=val2
Now I can run kubectl get secret testsecret -o json to get something like:
{
"apiVersion": "v1",
"data": {
"key1": "dmFsMQ==",
"key2": "dmFsMg=="
},
...
}
I can do something like
kubectl get secret testsecret -o jsonpath='{.data}'
or
kubectl get secret testsecret -o json | jq '.data'
to get my key-value pairs in non-list format then I'd have to base64 --decode the values.
What is the easiest way to get a clean list of all my key-value pairs? Bonus points for doing this across all Secrets (as opposed to just one specific one, as I did here).

Sufficiently recent versions of jq have a filter for decoding base64 but it can only be used if the value that was encoded is a valid JSON string.
Anyway, you could start by trying:
.data | map_values(#base64d)

I read this question as asking for how to decode all secrets in one go. I built on the accepted answer to produce a one-liner to do this:
kubectl get secrets -o json | jq '.items[] | {name: .metadata.name,data: .data|map_values(#base64d)}'
This has the added benefit of listing the name of the secret along with the decoded values for readability.

If you need to extract tls certificates and/or keys from a kubernetes secret and you have an older jq version not supporting map_values(#base64d):
kubectl get secrets tls-cert -o json | jq '.data' | cut -d '"' -f 4 | tr -d '{}' | base64 --decode

When using the accepted answer you may come across exception
jq: error (at <stdin>:96): Cannot iterate over null (null)
This might be because some json might not be fully formed, use an additional filter
kubectl get secrets -o json | jq '.items[] | select(null != .data) | {name: .metadata.name,data: .data|map_values(#base64d)}'
The above will ensure to produce expected results

Related

decode base64 in kubectl jsonpath

I have a command similar to this
kubectl get secrets \
--selector='my-selector' \
-o jsonpath='{range .items[*] }{"\n"}{.metadata.labels.cluster-name}{"."}{.metadata.namespace {":"}{"5432"}{"postgres" }{":"}{.data.password}{end}'
which outputs a list like this (format required)
cluster-name.namespace:5432:postgres:YbHF....==
cluster-name.namespace:5432:postgres:YbHF....==
cluster-name.namespace:5432:postgres:YbHF....==
I need to decode the base64 for this file and using the kubectl cheat sheet as a reference which gives this example:
# Output decoded secrets without external tools
kubectl get secret my-secret -o go-template='{{range $k,$v := .data}}{{"### "}}{{$k}}{{"\n"}}{{$v|base64decode}}{{"\n\n"}}{{end}}'
I tried the following
kubectl get secrets \
--selector='my-selector' \
-o jsonpath='{range .items[*] }{"\n"}{.metadata.labels.cluster-name}{"."}{.metadata.namespace {":"}{"5432"}{"postgres" }{":"}{.data.password|base64decode}{end}'
The result is that everything appears apart from the password field which is now blank, for example:
cluster-name.namespace:5432:postgres:
Any pointers would be appreciated.
As per #mdaniel suggestion I used the -o go-template
My main syntaxal changes were removing the [ ], ie, {range .items[*] } to {{range .items}}'
And if a key contained a - then {.metadata.labels.cluster-name} became {{index .metadata.labels "cluster-name"}}
My solution below which enabled the base64 decode to work:
kubectl get secrets \
--selector='my-selector' \
-o go-template='{{range .items}}{{"\n"}}{{index .metadata.labels "cluster-name"}}{{"."}}{{.metadata.namespace }}{{":"}}{{"5432"}}{{"postgres"}}{{":"}}{{.data.password|base64decode}}{{end}}'

How to replace JSON value in kubectl output using go-template?

I have a configMap and I want to create a backup configMap by using the last applied configuration from that.
I use the following command to get the last applied configuration:
kubectl get cm app-map -n app-space \
-o go-template \
--template='{{index .metadata "annotations" "kubectl.kubernetes.io/last-applied-configuration"}}' > backup.json
It returns something like this [the content of backup.json]:
{"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"app-map","creationTimestamp":null},"data":{"app.yml":"xxxxxxxxx","config.yml":"yyyyyyyyy"}}
Now, I want my backup configMap to have a different name. So, I want to change the .metadata.name from app-map to app-map-backup.
Is there a way I can achieve that with kubectl and -o go-template? I want to have the name changed before I write it to the backup.json file.
I know I can do that using jq but I do not have permission to install jq on the server where I am using kubectl.
you could use kubectl bulk plugin. The below command will replicate your config map
# get resource(s) and create with field(name) change
kubectl bulk configmap app-map -n app-space create name app-mapp-backup
Kubectl bulk is very powerful to use, I suggest to check samples.
You cannot do this just using kubectl. But there are other ways.
You can download statically linked jq binary from official jq website:
wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod +x jq-linux64
and then you can use this binary like following:
kubectl -o go-template [...] | ./jq-linux64 ...
or you can use sed:
kubectl -o go-template [...] | sed 's/"name":"app-map"/"name":"app-map-backup"/'

kubectl: get specific value from a secret in plaintext

I want to get the value of a specific field of a secret in a shell script.
From the kubectl get secret documentation, it seems the standard way to get a secret returns the whole thing, in a specified format, with the values base64 encoded.
So, to get the bar field of the foo secret, output as an unencoded string, I'm doing this:
kubectl get secret foo -o json | jq -r ".data.bar" | base64 --decode
That is
get the whole foo secret as JSON
pipe to jq to read the bar field from the JSON
decode the value using base64
Is there a way to do this only using kubectl?
Or an elegant way in POSIX-compliant shell that doesn't rely on any dependencies like jq?
Try this
kubectl get secret foo --template={{.data.bar}} | base64 --decode
No need of jq.
In cases when key contains dots:
apiVersion: v1
metadata:
name: foo
data:
bar.baz: RnVja2VkIFVwIEJleW9uZCBBbGwgUmVjb2duaXRpb24=
the syntax would be:
kubectl get secret foo -o jsonpath="{.data['bar\.baz']}" | base64 -d
This should work since Kubernetes 1.11 (see PR 60755):
kubectl get secret foo -o go-template='{{ .data.bar | base64decode }}'
kubectl get secret foo -o jsonpath={.data.bar} | base64 --decode
https://kubernetes.io/docs/reference/kubectl/jsonpath/
You can try the following command, it will decode all the values in the secret.
kubectl get secret <secret-name> -o json | jq '.data | map_values(#base64d)'
For a hyphenated key, here's the escaping trick to get the decoded value directly from kubectl:
kubectl get secret foo -o go-template='{{ index .data \"bar-baz\" | base64decode }}'
(Tested with kubectl 1.21.5)
For those of you guys coming here via Google and want to do it from PowerShell, where base64 ist not available, use the following:
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($(kubectl get secret foo -o jsonpath='{.data.bar}')))

What command can I run to get the oldest pod's name?

I want to get the name of the oldest pod as part of a script. It seems like I should be able to run kubectl get po --no-headers=true, sort-by AGE, and then just pipe to head -n1|awk '{print $1}', but I can't seem to get sort-by working. I'm running kubectl 1.7.9.
The AGE times are in an irregular format (23m, 2d) that’s hard to sort on, but you can ask kubectl to write out the time a pod started instead. The times will come out in the very sortable ISO 8601 format. This recipe to get the single oldest pod might work for you:
kubectl get pods \
--no-headers \
--output=custom-columns=START:.status.startTime,NAME:.metadata.name \
| sort \
| head -1 \
| awk '{print $2}'
The kubectl command asks to only print out the start time and name, in that order, for each pod.
Also consider kubectl get pods -o json, which will give you a very large very detailed JSON record. If you have a preferred full-featured scripting language you can pick that apart there, or use a command-line tool like jq to try digesting it further. Any field path can also be inserted into the custom-columns output spec.
This can be accomplished with:
kubectl get pods --sort-by=.metadata.creationTimestamp -o=name | head -1
I'm not sure what version this started work in, but I'm using it in kubectl 1.12.

Kubernetes: modify a secret using kubectl?

How can I modify the values in a Kubernetes secret using kubectl?
I created the secret with kubernetes create secret generic, but there does not seem to be a way to modify a secret. For example, to add a new secret-value to it, or to change a secret-value in it.
I assume i can go 'low-level', and write the yaml-file and do a kubectl edit but I hope there is a simpler way.
(I'm using kubernetes 1.2.x)
The most direct (and interactive) way should be to execute kubectl edit secret <my secret>. Run kubectl get secrets if you'd like to see the list of secrets managed by Kubernetes.
In case you prefer a non-interactive update, this is one way of doing it:
kubectl get secret mysecret -o json | jq '.data["foo"]="YmFy"' | kubectl apply -f -
Note that YmFy is a base64-encoded bar string. If you want to pass the value as an argument, jq allows you to do that:
kubectl get secret mysecret -o json | jq --arg foo "$(echo bar | base64)" '.data["foo"]=$foo' | kubectl apply -f -
I'm more comfortable using jq but yq should also do the job if you prefer yaml format.
As I found myself in the need of modifying a secret, I landed up here.
Here is the most convenient way I found for editing a (one-line) secret.
This elaborates on kubectl edit secret <my secret> of Timo Reimann above.
kubectl edit secret <my secret> will (in my case) invoke vi.
Now I move the cursor to the space after the colon of the secret I want to edit.
Then I press r and [enter] which will put the base64 encoded value onto a line of its own.
Now I enter :. ! base64 -D which will decode the current line.
After making my changes to the value, I enter :. ! base64 which will encode the changed value.
Pressing k [shift]J will rejoin the secret name and its new value.
:wq will write the new secretfile and quit vi.
P.S. If the secret has a multi-line value, switch on line numbers (:set nu) and, after changing the decoded value, use A,B ! base64 where A and B are the line numbers of the first and last line of the value.
P.P.S I just learned the hard way that base64 will receive the text to encode with an appended newline :( If this is no issue for your values - fine. Otherwise my current solution is to filter this out with: .!perl -pe chomp | base64
Deriving from 'Skeeves' answer:
Base64 encode your value:
echo -n 'encode_My_Password' | base64
Open the secret in edit mode:
kubectl edit secret my-secret
The default editor will open, replace the value of an exiting key or add a new line and a new key with the encoded value.
Save and close the file. The updated value or new key-value pair has now been added to the secret.
The easiest way from the command line:
echo "This is my secret" | base64 | read output;kubectl patch secret my_secret_name -p="{\"data\":{\"secret_key\": \"$output\"}}" -v=1
It will encode value This is my secret and update your my_secret_name secret by adding secret_key key and encoded values as a last key-value pair in that secret.
I implemented a kubectl plugin just for this.
To install using krew
kubectl krew update
kubectl krew install modify-secret
To run it
kubectl modify-secret xyz -n kube-system
Demo
The Easy Way : Delete and recreate the secret
After looking at all these answers, for my needs the best solution was to delete and recreate :
kubectl delete secret generic
kubectl create secret generic # or whatever ..
If you want to do it the hard way :
Using edit to change a docker-registry secret
I came to this question looking to modify a "docker-registry" style secret.
Simply editing it using kubectl edit secret seemed fraught as I didn't know what the secret value looked like.
I had created it with a command like kubectl create secret docker-registry generic-registry-secret --docker-server=docker.server --docker-username='my-cloud-usernname' --docker-password='my-auth-token' --docker-email='my#email.com'
I could have edited it, I figured out after looking at the other various answers here how that could be done - I'm including my notes here in case they help others.
List secrets : kubectl get secrets
Details of specific secret : kubectl describe secrets/generic-registry-secret
Get value of secret : kubectl get secret generic-registry-secret -o jsonpath={.data}
Decode secret value : First get everything between "map[.dockerconfigjson:" and "]" and then do :
echo "x9ey_the_secret_encoded_value_here_X0b3=" | base64 --decode
I could then take from that the specific auth token value I was seeking, and replace it with a new one. And then run that new full entire string through a | base 64 to get the base 64 encoding, and now I could finally, confidently, change the value by using kubectl edit secret generic-registry-secret and put in the new correct value.
But a delete and recreate is the simpler option.
References :
https://kubernetes.io/docs/concepts/configuration/secret/
https://kubernetes.io/docs/tasks/configmap-secret/managing-secret-using-kubectl/
Add a new key to an existing secret.
kubectl patch secret $SECRET_NAME --type=json \
-p='[{
"op" : "add" ,
"path" : "/data/'$KEY'" ,
"value" : "'$(base64 <<< "$VALUE")'"
}]'
Update an existing key in a secret
kubectl patch secret $SECRET_NAME --type=json \
-p='[{
"op" : "replace" ,
"path" : "/data/'$KEY'" ,
"value" : "'$(base64 <<< "$VALUE")'"
}]'
I was only able to find the replace operation in documentation, with no mention of the add operation. However, it looked like it was RFC 6902 compliant, so I tested with add and it works fine. I would expect other operations defined by RFC 6902 to work as well, though I haven't tested them.
The fastest way I found:
# You need a version of micro that includes this commit https://github.com/zyedidia/micro/commit/9e8d76f2fa91463be660737d1de3bff61258c90d
kubectl get secrets my-secret -o json | jq -r .data.config | base64 -d | micro | base64 -w 0 | xclip -selection clipboard && kubectl edit secrets my-secret
And using a bash function that you can put in your profile:
function ks-edit { kubectl -n $1 get secrets $2 -o json | jq -r '.data."'$3'"' | base64 -d | micro | base64 -w 0 | xclip -selection clipboard && kubectl -n $1 edit secrets $2; }
You can call it like this:
ks-edit <namespace> <secret> <key>
Before editing secrets with kubectl...
I would highly recommend on using k9s (not only for this purpose, but also as a lightweight k8s CLI management tool).
As you can see below (ignore all white rectangles), when your cluster's context is set on terminal you just type k9s and you will hit a nice terminal where you can inspect all cluster resources.
Just type ":" and enter the resource name (secrets in this case) which will appear in the middle of screen.
Then you can choose a secret with the up and down arrows and type e to edit it (green arrow):
By far the easiest way to do this is to mantain a local .env file for each of your secrets.
e.g
MY_SECRET=something
PASSWORD=anotherthing
Just run
kubectl create secret generic <name> --from-env-file=.env
And when you need to change it - just delete it and run the above command again.
No messing with base64
Always get the copy of secrets before editing it -
kubectl get secrets <your-secret-name> -n <namespace> -o yaml > mysecret.yaml
Now you can edit run edit command to edit your secret -
kubectl edit secrets <your-secret-name> -n <namespace>
or you can make copy of your mysecret.yaml file & exit the secrets inside that & run -
kubectl apply -f mysecret.yaml
Make sure you are decoding & encoding with base64 for viewing & adding secrets respectively.
Here's my one liner:
$ kubectl get secrets/my-secret -o yaml | yq '.dataStrings = (.data | map_values(#base64d)) | del(.data)' | vipe | yq '.data = (.dataStrings | map_values(#base64)) | del(.dataStrings)' | kubectl apply -f -
In case you're wondering how to do this with k9s, I am adding here instructions on how to do this step by step:
Install krew from here https://krew.sigs.k8s.io/docs/user-guide/setup/install/ (skip this step in case you have already it)
Install modify-secret plugin:
kubectl krew install modify-secret
Run the following command or add it to ~/.zshrc or ~/.bashrc:
export XDG_CONFIG_HOME=~/
Add the following to ~/k9s/plugin.yml
plugin:
edit-secret:
shortCut: Ctrl-X
confirm: false
description: "Edit Decoded Secret"
scopes:
- secrets
command: kubectl
background: false
args:
- modify-secret
- --namespace
- $NAMESPACE
- --context
- $CONTEXT
- $NAME