Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Decoding Helm3 resources in secrets

Helm 3 is storing description of it's releases in secrets. You can simply find them via

$ kubectl get secrets
NAME                                                TYPE                                  DATA   AGE
sh.helm.release.v1.wordpress.v1                     helm.sh/release.v1                    1      1h

If you want to get more info about the secret, you can try to describe the secret

$ kubectl describe secret sh.helm.release.v1.wordpress.v1
Name:         sh.helm.release.v1.wordpress.v1
Namespace:    default
Labels:       createdAt=1578561400
              name=wordpress
              owner=helm
              status=superseded
              version=1
Annotations:  <none>

Type:  helm.sh/release.v1

Data
====
release:  34976 bytes

Now you can see, that the secret is holding one file release which has ~35kB. In order to read that, you need to know, that kubernetes secrets are base64 encoded by default. But after decoding, you still don't get the data because Helm3 is encoding those data further.

So in order to decode the data, you have to:

  • base64 decode - Kubernetes secrets encoding
  • base64 decode (again) - Helm encoding
  • gzip decompress - Helm zipping

The final command to get the Helm's release data can look like this:

kubectl get secrets sh.helm.release.v1.wordpress.v1 -o json | jq .data.release | tr -d '"' | base64 -d | base64 -d | gzip -d 

Voilà, now you have JSON data of Helm resources. It stores every Chart's file and further encode it via base64.

@thzinc
Copy link

thzinc commented Mar 30, 2020

This was super helpful! Thanks.

One minor improvement is to use jsonpath instead of jq | tr (though I love jq):

kubectl get secrets sh.helm.release.v1.wordpress.v1 -o jsonpath='{.data.release}' | base64 -D | base64 -D | gzip -d

@wooos
Copy link

wooos commented May 22, 2020

Thanks.

@lancehunt
Copy link

lancehunt commented Jun 19, 2020

you can also do this:

helm get manifest wordpress

and

helm get values wordpress

@dguyhasnoname
Copy link

dguyhasnoname commented Aug 15, 2020

This is awesome. I was not able to decode helm release data. I tried doing base64 decode twice, but did not realise that gzip would be needed.

@skuethe
Copy link

skuethe commented Sep 25, 2020

Cool stuff, thanks for this. I went ahead and created a function for .bash_aliases just to make everyday life a bit easier.

helmsecret() {
    local fetchSecretJson
    local doesSecretExist
    if [[ -z "${1}" ]]; then
        echo "Missing secret name. Terminating"
        exit 1
    else
        if [[ "${1}" == *"sh.helm.release"* ]]; then
            fetchSecretJson=$(kubectl get secret --ignore-not-found --all-namespaces --output json --field-selector "metadata.name=${1}")
            doesSecretExist=$(echo "${fetchSecretJson}" | jq --raw-output 'if (.items | length) > 0 then "true" else empty end')
            if [[ "${doesSecretExist}" == "true" ]]; then
                echo "${fetchSecretJson}" | jq --raw-output '.items[0].data.release' | base64 -d | base64 -d | gzip -d
            else
                echo "There is no such helm secret on this cluster"
            fi
        else
            echo "This is not a helm secret :("
        fi
    fi
}

Just put it in your ~/.bash_aliases, load it and use it:

. ~/.bash_aliases
helmsecret sh.helm.release.v1.SOMERELEASE.v2 | less

Btw. another easy way to avoid piping jq output into tr is to just use raw output option in jq.
So jq --raw-output '.' or just jq -r '.'

@chulkilee
Copy link

chulkilee commented Jan 7, 2021

FYI: now you can use base64decode with go-template - thanks to kubernetes/kubernetes#60755

kubectl get secret sh.helm.release.v1.myapp.v4 -o go-template='{{.data.release | base64decode | base64decode}}' | gzip -d | jq

@smilelikeshit
Copy link

smilelikeshit commented Sep 19, 2021

thx

@wind57
Copy link

wind57 commented Oct 26, 2021

marvelous! I come to this page like once a month for that command. kudos

@AlessioCasco
Copy link

AlessioCasco commented Jan 18, 2022

Just wanted to also add the command needed in case a secret requires to be edited like in situations where the deployment is stuck with status pending-upgrade and can't be rolled back.

Considering that myapp.v1.edited.json has the decoded and edited content of .data.release from the commands above:

gzip -c myapp.v1.edited.json | base64 | base64 -w 0

goes here

    "data": {
        "release": " <<output goes here>> "

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment