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)

79799 次浏览

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

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

using kubectl-modify-secret plugin

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 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>

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.

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 :

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):

enter image description here

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.

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

In case you're wondering how to do this with k9s, I am adding here instructions on how to do this step by step:

  1. Install krew from here https://krew.sigs.k8s.io/docs/user-guide/setup/install/ (skip this step in case you have already it)

  2. Install modify-secret plugin:

    kubectl krew install modify-secret

  3. Run the following command or add it to ~/.zshrc or ~/.bashrc:

    export XDG_CONFIG_HOME=~/

  4. 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