Last active
July 29, 2025 15:15
-
-
Save depau/ca3bfd3fd2fa2fd1f9d8242bab12f310 to your computer and use it in GitHub Desktop.
Kubernetes secret decoder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ | |
| Read one or more Kubernetes Secret YAML documents from stdin (e.g. the output of | |
| `kubectl get secret -o yaml`) and emit the same documents with every `.data` | |
| map moved to `.stringData`, base64-decoding all values. | |
| """ | |
| import sys | |
| import base64 | |
| from typing import Any | |
| try: | |
| # ruamel.yaml keeps ordering/comments better than PyYAML | |
| from ruamel.yaml import YAML | |
| from ruamel.yaml.scalarstring import LiteralScalarString | |
| except ImportError: # pragma: no cover | |
| print("This script needs ruamel.yaml. Install it with: pip install ruamel.yaml", file=sys.stderr) | |
| sys.exit(1) | |
| yaml = YAML() | |
| yaml.preserve_quotes = True | |
| docs = list(yaml.load_all(sys.stdin)) | |
| def process_secret(d: dict) -> None: | |
| data = d.get("data") | |
| if not isinstance(data, dict): | |
| return | |
| metadata: dict = d.get("metadata") | |
| metadata.pop("ownerReferences", None) | |
| metadata.pop("resourceVersion", None) | |
| metadata.pop("creationTimestamp", None) | |
| metadata.pop("uid", None) | |
| string_data = {} | |
| for k, v in data.items(): | |
| if v is None: | |
| continue | |
| s = str(v) | |
| try: | |
| decoded_bytes = base64.b64decode(s, validate=True) | |
| except Exception: | |
| # Fall back to non-validating decode; ignore undecodable bytes. | |
| decoded_bytes = base64.b64decode(s) | |
| decoded = decoded_bytes.decode("utf-8", "ignore") | |
| if "\n" in decoded: | |
| decoded = LiteralScalarString(decoded) | |
| string_data[k] = decoded | |
| if string_data: | |
| d["stringData"] = string_data | |
| d.pop("data", None) | |
| def walk(obj: Any) -> None: | |
| if isinstance(obj, dict): | |
| if obj.get("kind") == "Secret": | |
| process_secret(obj) | |
| for v in obj.values(): | |
| walk(v) | |
| elif isinstance(obj, list): | |
| for i in obj: | |
| walk(i) | |
| for d in docs: | |
| walk(d) | |
| yaml.dump_all(docs, sys.stdout) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment