Decode and Inspect Kubernetes Docker Secrets
Decode base64-encoded dockerconfigjson secrets to verify registry credentials, troubleshoot ImagePullBackOff errors, and audit pull secret configurations.
π‘ Quick Answer: Use
kubectl get secret <name> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jqto decode any docker-registry Secret, then pipe theauthfield throughbase64 -dagain to see the plainusername:password.
The Problem
Youβre troubleshooting ImagePullBackOff errors and need to verify that your Kubernetes pull secret contains the right registry credentials. But the secret data is double base64-encoded:
- The
.dockerconfigjsonvalue is base64-encoded (Kubernetes stores all secret data in base64) - Inside the decoded JSON, each
authfield is also base64-encoded (base64(username:password))
You need to decode both layers to inspect the actual credentials.
The Solution
Decode the Full Secret
# Decode the entire .dockerconfigjson
kubectl get secret my-pull-secret \
-n my-namespace \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .Output:
{
"auths": {
"quay.io": {
"auth": "bXlvcmcrazhzX3Byb2RfcHVsbGVyOkFCQzEyMw==",
"email": "robot@myorg.example.com"
}
}
}Decode the Auth Credential
The auth field is base64(username:password) β decode it to see the actual credentials:
# Extract and decode the auth for a specific registry
kubectl get secret my-pull-secret \
-n my-namespace \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d \
| jq -r '.auths["quay.io"].auth' \
| base64 -dOutput:
myorg+k8s_prod_puller:ABC123One-Liner: Show All Registries and Credentials
# Decode all registry credentials in a secret
kubectl get secret my-pull-secret -n my-namespace \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d \
| jq -r '.auths | to_entries[] | "\(.key) β \(.value.auth | @base64d)"'Output:
quay.io β myorg+k8s_prod_puller:ABC123ROBOTTOKEN
gcr.io β _json_key:{...service-account-json...}OpenShift: Inspect the Cluster-Wide Pull Secret
# Decode the cluster-wide pull secret
oc get secret pull-secret -n openshift-config \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .
# Decode a specific registry's auth
oc get secret pull-secret -n openshift-config \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d \
| jq -r '.auths["quay.internal.example.com"].auth' | base64 -dAlternative: Decode with Python
If jq isnβt available:
python3 -c "
import base64, json, sys
data = json.loads(base64.b64decode(sys.stdin.read()))
for host, creds in data['auths'].items():
username_password = base64.b64decode(creds['auth']).decode()
print(f'{host} β {username_password}')
" <<< "$(kubectl get secret my-pull-secret -n my-namespace -o jsonpath='{.data.\.dockerconfigjson}')"Audit All Pull Secrets in a Namespace
#!/bin/bash
# audit-pull-secrets.sh β List all pull secrets and their registries
NAMESPACE="${1:-default}"
echo "=== Pull secrets in namespace: $NAMESPACE ==="
for secret in $(kubectl get secrets -n "$NAMESPACE" \
-o jsonpath='{range .items[?(@.type=="kubernetes.io/dockerconfigjson")]}{.metadata.name}{"\n"}{end}'); do
echo ""
echo "Secret: $secret"
kubectl get secret "$secret" -n "$NAMESPACE" \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d \
| jq -r '.auths | to_entries[] | " Registry: \(.key) User: \(.value.auth | @base64d | split(":")[0])"'
doneOutput:
=== Pull secrets in namespace: production ===
Secret: quay-pull-secret
Registry: quay.io User: myorg+k8s_prod_puller
Secret: gcr-pull-secret
Registry: gcr.io User: _json_keyflowchart LR
A[K8s Secret<br/>type: dockerconfigjson] -->|"base64 -d (layer 1)"| B[JSON with auths]
B -->|"jq .auths[].auth"| C[auth field<br/>base64 encoded]
C -->|"base64 -d (layer 2)"| D["username:password<br/>in plaintext"]Common Issues
jq Not Installed
Use python3 as shown above, or decode manually:
# Without jq β raw decode
kubectl get secret my-pull-secret -n my-namespace \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -dPermission Denied
You need get permission on secrets in the target namespace:
kubectl auth can-i get secrets -n my-namespaceSecret Type Mismatch
Ensure youβre inspecting a kubernetes.io/dockerconfigjson type secret, not Opaque:
kubectl get secret my-pull-secret -n my-namespace -o jsonpath='{.type}'Best Practices
- Never log decoded credentials β inspect interactively, donβt pipe to files or CI logs
- Use
jqfor safe parsing β donβt rely on string splitting for JSON - Audit pull secrets periodically β verify credentials havenβt expired or been rotated
- Check both layers β a valid-looking secret can still have wrong credentials in the
authfield - Clean up shell history β
history -dorhistory -cafter decoding sensitive data
Key Takeaways
- Docker registry secrets have two layers of base64: Kubernetes secret encoding and the
authfield itself - Use
base64 -d | jqto decode the first layer, thenbase64 -dagain for the auth credential - The
authfield format is alwaysbase64(username:password)separated by a colon - Audit all pull secrets in a namespace with a simple loop script

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses β