Decoding Kubernetes Secrets with jq

It's been a while since I've posted, and I generally post about things I've learned / have helped me in my day to day role. This is a quick blog post about easily decoding base64 encoded secrets in kubernetes, using Kubectl and jq.

Before diving into decoding Kubernetes secrets, let's set up a local development environment using kind (Kubernetes in Docker). If you haven't used kind before, it's a fantastic tool for local Kubernetes development. Here's how to create a basic cluster:

kind create cluster

That's it! Once your cluster is ready (usually takes about a minute), you can verify it's working:

kubectl cluster-info --context kind-kind

Now, let's explore how to work with Kubernetes secrets. We'll create a simple secret and learn different ways to decode it.

First, let's create a secret with a few key-value pairs:

❯ kubectl create secret generic decode-example \
--from-literal=key1=value1 \
--from-literal=key2=value2 \
--from-literal=key3=value3
secret/decode-example created

When we examine this secret using kubectl get secret with JSON output, we can see our values are base64 encoded:

❯ kubectl get secret/decode-example -ojson | jq
{
"apiVersion": "v1"
,
"data": {
"key1": "dmFsdWUx"
,
"key2": "dmFsdWUy",
"key3": "dmFsdWUz"
}
,
"kind": "Secret",
"metadata": {
"creationTimestamp": "2025-01-07T18:06:56Z"
,
"name": "decode-example",
"namespace": "default",
"resourceVersion": "674",
"uid": "d0369e58-089c-4ea3-8998-4c931b904ef2"
}
,
"type": "Opaque"
}

Here's where things get fun. We can use jq to decode these values in several ways, depending on what information we need:

For a simple list of decoded values:

❯ kubectl get secret/decode-example -ojson | jq -r '.data | to_entries | .[] | .value | @base64d'
value1
value2
value3

If you need specific keys with their decoded values (notice we're only selecting key1 and key3):

❯ kubectl get secret/decode-example -ojson | jq '{key1: .key1 | @base64d, key3: .key3 | @base64d}'
{
"key1": "value1"
,
"key3": "value3"
}

But the ez-mode approach to get all keys and values decoded in a clean JSON format is to use map_values() as seen here:

❯ kubectl get secret/decode-example -ojson | jq '.data | map_values(@base64d)'
{
"key1": "value1"
,
"key2": "value2",
"key3": "value3"
}

This last command is useful as it preserves the structure while giving us human-readable values, and reduces the labor intensive method of the previous example.

By leveraging kubectl and jq together, we can quickly decode and inspect Kubernetes secrets without needing additional tools or complex scripts. Pretty neat, right?

Don't forget to clean up your kind cluster when you're done:

kind delete cluster

-BadgerOps