Snippets: Kubernetes secrets base64 decoder

It is very common that we need to see the secret content when working with Kubernetes. Imagine that you have installed a Helm chart in your cluster with auto-generated credentials and you need to get them to login to the app UI, or maybe you are troubleshooting and you want to make sure that the secret has the data it is supposed to have. If that sounds familiar, you might find this snippet particularly useful.

Problem

Extracting values from a Kubernetes secret is quite easy but requires quite a bit of typing. Here’s one of the ways you can do it:

kubectl get secret someapp-credentials -o jsonpath='{.data.username}' | base64 -d
kubectl get secret someapp-credentials -o jsonpath='{.data.password}' | base64 -d

Not so bad. Though for a person like me, who prefers to have k as an alias to kubectl because it’s just too much to type, doing this task regularly can become annoying pretty fast.

This is actually something I used to do a lot. But one day the level of frustration when typing all these commands reached the threshold so I sit to come up with a simple script that could become my “Swiss Army Knife” when it comes to working with Kubernetes secrets.

Solution

The core idea here is to support two use cases:

  1. Print the decoded value of a single key in a secret

  2. Print the entire data section of a secret with all values being decoded

Ideally it should support both getting secrets from the namespace of the current context and any other namespace in a very concise manner(typing -n namespace every time is just too much trouble). Below is the script itself. It utilizes a bit of bash, basic linux commands, and jq.

#!/bin/bash

if [ -z "$1" ]; then
  echo "Usage: $0 [<namespace>/]<secret> [<key>]"
  exit 1
fi

namespace_or_secret=$(echo $1 | awk -F '/' '{print $1}')
secret=$(echo $1 | awk -F '/' '{print $2}')

result=""
if [ -z "$secret" ]; then
  secret=$namespace_or_secret
  result=$(kubectl get secret $secret -o jsonpath='{.data}' | jq 'map_values(@base64d)')
else
  namespace=$namespace_or_secret
  result=$(kubectl -n $namespace get secret $secret -o jsonpath='{.data}' | jq 'map_values(@base64d)')
fi

if [ -z "$2" ]; then
  echo $result | jq '.'
else
  echo $result | jq -r --arg k "$2" '.[$k]'
fi

Now I can get a decrypted content of any secret I need in any namespace with one very simple command(assuming you put it in /usr/local/bin/ksecret or $HOME/.local/bin/ksecret and grant chmod +x):

ksecret kube-system/default-token-bf4vd

the output looks like this:

{
  "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIC/jCCAeagAwIBAgIBADANBgkqhkiG9...",
  "namespace": "kube-system",
  "token": "eyJhbGciOiJSUzx1NiIsImtpZCI6ImRvTHJHVHZqWjNhU05pYlpDYl84cUlscTN..."
}

or if I need just the token:

ksecret kube-system/default-token-bf4vd token

the output will be raw string ready for copy/paste:

eyJhbGciOiJSUzI1NiI...

It also supports getting keys with characters reserved by jq like .:

ksecret kube-system/default-token-bf4vd ca.crt

the output will be a properly formatted certificate:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----