ksd is a small command-line filter that decodes the base64-encoded data
field of a Kubernetes Secret manifest into a human-readable stringData
field. It reads a Secret (YAML or JSON, auto-detected) from stdin and
writes the decoded manifest back out — every other field is left untouched.
$ kubectl get secret my-secret -o yaml | ksd
kubectl krew install ksdbrew install --cask mfuentesg/tap/ksdgo install github.com/mfuentesg/ksd@latestGrab the archive for your platform (linux/darwin/windows, amd64/arm64) from
the releases page, extract it,
and put the ksd binary on your PATH.
ksd < secret.<yaml|json>
kubectl get secret <secret-name> -o <yaml|json> | ksd
Installed via Krew? Use kubectl ksd in place of ksd — same behavior,
same flags:
kubectl get secret <secret-name> -o <yaml|json> | kubectl ksd
ksd version # print the ksd version
Running ksd without piping anything into it prints a usage message to
stderr and exits non-zero — there's no separate --help flag.
secret.json
{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "kubernetes-secret-decoder",
"namespace": "ksd"
},
"type": "Opaque",
"data": {
"password": "c2VjcmV0",
"app": "a3ViZXJuZXRlcyBzZWNyZXQgZGVjb2Rlcg=="
}
}$ ksd < secret.json
{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "kubernetes-secret-decoder",
"namespace": "ksd"
},
"stringData": {
"app": "kubernetes secret decoder",
"password": "secret"
},
"type": "Opaque"
}secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-secret-decoder
namespace: ksd
type: Opaque
data:
password: c2VjcmV0
app: a3ViZXJuZXRlcyBzZWNyZXQgZGVjb2Rlcg==$ ksd < secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: kubernetes-secret-decoder
namespace: ksd
stringData:
app: kubernetes secret decoder
password: secret
type: Opaquekubectl get secret my-secret -o yaml | ksdBecause ksd preserves the full manifest shape, its output can be piped
straight back into kubectl apply — Kubernetes accepts stringData on
write, base64-encoding it for you:
kubectl get secret my-secret -o yaml | ksd | kubectl apply -f -kubectl get secret my-secret -o yaml | ksd > my-secret.decoded.yamlDecoded values are printed in plaintext — be mindful about where that output ends up (shared terminals, CI logs, committed files, etc).
Requires Go 1.27+.
git clone https://github.com/mfuentesg/ksd.git
cd ksd
go build -o ksd . # build
go test -race -cover ./... # test
go vet ./... # vet
golangci-lint run # lint (golangci-lint v2)Project layout:
main.go # CLI entrypoint: arg parsing, stdin/stdout, exit codes
internal/decoder/ # decode logic (the only place format detection/parsing lives)
testdata/ # fixtures used by both the decoder and CLI tests
.goreleaser.yml # release config: binaries, Homebrew cask, Krew manifest
Releases are automated with GoReleaser: pushing a
v* tag builds cross-platform binaries, publishes a GitHub release, updates
the Homebrew tap, and generates
the Krew plugin manifest.
- kubectl-view-secret — another kubectl plugin for viewing/decoding Kubernetes secrets, also available via Krew.