Last active
August 15, 2023 13:34
-
-
Save augustohp/b8483ca619f99682cc4c4d6b6e313818 to your computer and use it in GitHub Desktop.
Lists secrets for all your namespaces in kubernetes, allows some filtering using "grep" patterns.
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 sh | |
# | |
# Aids listing/filtering secrets from kubernetes using kubectl. Aims to be minimal | |
# and portable. The only thing you need is this file and kubectl. | |
# | |
# Author: Augusto Pascutti <augusto.hp+oss@gmail> | |
# License: MIT | |
# URL: https://gist.github.com/augustohp/b8483ca619f99682cc4c4d6b6e313818 | |
# | |
# "The only way to make sense out of change | |
# is to plunge into it, move with it, and join the dance." - Alan Watts | |
# shellcheck disable=SC3043 | |
# vim: set ft=sh ts=4 sw=4 tw=0 noet: | |
APP_NAME=$(basename "$0") | |
APP_VERSION="1.0.0" | |
APP_AUTHOR="[email protected]" | |
APP_DEPENDENCIES="awk grep column kubectl" | |
TMP_FILE=$(mktemp /tmp/kube-secrets.XXXXXX) | |
OPTION_DECODE_SECRET="false" | |
OPTION_KEEP_TMP_FILE="false" | |
OPTION_FILTER_NS="" | |
OPTION_FILTER_SECRET="" | |
OPTION_FILTER_ENV="" | |
set -e # Stops on failure | |
trap cleanup INT TERM EXIT | |
# Usage: cleanup | |
cleanup() | |
{ | |
if [ "$OPTION_KEEP_TMP_FILE" != "true" ] | |
then | |
rm -f "$TMP_FILE" 2> /dev/null || true | |
else | |
echo "Keeping '$TMP_FILE'." >&2 | |
fi | |
exit 1 | |
} | |
# Usage: err <string> | |
err() | |
{ | |
local msg="$1" | |
echo "Error: $msg" >&2 | |
} | |
# Usage: assert_env | |
assert_env() | |
{ | |
for dependency in $APP_DEPENDENCIES | |
do | |
if [ -n "$(command -v "$dependency")" ] | |
then | |
continue | |
fi | |
err "Missing dependency '$dependency', please install it." | |
exit 2 | |
done | |
} | |
# ------------------------------------------------------------------------------ | |
# Context | |
# Usage: k8s_get_namespaces | |
k8s_get_namespaces() | |
{ | |
kubectl get ns \ | |
| grep -v "^NAME" \ | |
| awk '{ print $1 }' \ | |
| grep "$OPTION_FILTER_NS" | |
} | |
# Usage: k8s_get_secrets <namespace> | |
k8s_get_secrets() | |
{ | |
local ns="$1" | |
kubectl get secrets -n "$ns" 2>/dev/null \ | |
| grep -v "^NAME" \ | |
| awk '{ print $1 }' \ | |
| grep "$OPTION_FILTER_SECRET" | |
} | |
# Usage: k8s_describe_secrets <namespace> <secret> | |
k8s_describe_secrets() | |
{ | |
local ns="$1" | |
local secret="$2" | |
kubectl describe secret -n "$ns" "$secret" \ | |
| grep -A 9999 "====" \ | |
| grep -v "====" \ | |
| awk -F ":" '{ print $1 }' \ | |
| grep "$OPTION_FILTER_ENV" | |
} | |
# Usage: no_content_to_display && echo "No content" | |
no_content_to_display() | |
{ | |
[ ! -s "$TMP_FILE" ] | |
} | |
# Usage: decoded_secret_wanted && echo "Needs to decode secret" | |
decoded_secret_wanted() | |
{ | |
[ "$OPTION_DECODE_SECRET" = "true" ] | |
} | |
# Usage: command_list_secrets <namespace> <secret> | |
command_list_secrets() | |
{ | |
local ns="$1" | |
local secret="$2" | |
local separator="||" | |
local decoded_secret="" | |
local append_string="" | |
for ns in $(k8s_get_namespaces) | |
do | |
for secret in $(k8s_get_secrets "$ns") | |
do | |
for varname in $(k8s_describe_secrets "$ns" "$secret") | |
do | |
append_string="" | |
if decoded_secret_wanted | |
then | |
decoded_secret="$(command_decode_secret "$ns" "$secret" "$varname")" | |
append_string="$separator$decoded_secret" | |
fi | |
echo "$ns$separator$secret$separator$varname$append_string" >> "$TMP_FILE" | |
done | |
done | |
done | |
if no_content_to_display | |
then | |
return 0 | |
fi | |
if decoded_secret_wanted | |
then | |
append_string=",Value" | |
else | |
append_string="" | |
fi | |
# shellcheck disable=SC2002 # `column` and stdin are weird friends | |
cat "$TMP_FILE" \ | |
| column --table --separator "$separator" --table-columns "Namespace,Secret,Name$append_string" | |
} | |
# Usage: command_decode_secret <namespace> <secret> <envvar> | |
command_decode_secret() | |
{ | |
local ns="$1" | |
local secret="$2" | |
local envvar="$3" | |
kubectl get secret -n "$ns" "$secret" -o jsonpath="{.data.$envvar}" \ | |
| base64 --decode | |
} | |
# ------------------------------------------------------------------------------ | |
# Execution | |
# Usage: display_help_and_exit | |
display_help_and_exit() | |
{ | |
cat <<-EOF | |
Usage: $APP_NAME [options] <command> | |
$APP_NAME --help | |
$APP_NAME --version | |
$APP_NAME -n "acme*" -e "PROXY*" -d list-secrets | |
$APP_NAME -n "acme-corp" -s "api" -e "PASSWORD" decode-secret | |
Will help filtering a secret value among k8s secrets. | |
Commands: | |
ls, list-secrets List all secrets from all namespaces. | |
ds, decode-secret Decode a secret value. | |
Options: | |
-h, --help Print this help (this message). | |
-v, --version Prints version. | |
-x, --verbose Displays debug information (-x). | |
-d, --decode Decode the secret value while listing secrets. "grep" argument. | |
-e, --env Variable (envvar) name to filter values from. "grep" argument. | |
-n, --namespace Namespace name to filter secrets from. | |
-s, --secret Secret name to filter values from. Passed as "grep" argument. | |
-k, --keep Keep temporary file after execution, containing the contents | |
of the secrets. | |
You can send bugs and/or suggestions to $APP_AUTHOR. | |
EOF | |
exit 1 | |
} | |
# Usage: main "$@" | |
main() | |
{ | |
while :; do | |
case "${1-}" in | |
# Options --------------------------- | |
-h | --help) | |
display_help_and_exit | |
;; | |
-x | --verbose) | |
set -x | |
;; | |
-v | --version) | |
echo "$APP_VERSION" | |
exit 1 | |
;; | |
-n | -ns | --ns | --namespace) | |
OPTION_FILTER_NS="$2" | |
shift | |
;; | |
-s | --secret) | |
OPTION_FILTER_SECRET="$2" | |
shift | |
;; | |
-e | --env) | |
OPTION_FILTER_ENV="$2" | |
shift | |
;; | |
-d | --decode) | |
OPTION_DECODE_SECRET="true" | |
;; | |
-k | --keep) | |
OPTION_KEEP_TMP_FILE="true" | |
;; | |
# Commands -------------------------- | |
ls | list-secrets) | |
command_list_secrets "$OPTION_FILTER_NS" "$OPTION_FILTER_SECRET" | |
exit 0 | |
;; | |
ds | decode-secret) | |
command_decode_secret "$OPTION_FILTER_NS" "$OPTION_FILTER_SECRET" "$OPTION_FILTER_ENV" | |
echo "" | |
exit 0 | |
;; | |
# Treating mistakes ----------------- | |
-?*) | |
err "Unknown option '$1'." | |
exit 3 | |
;; | |
*) | |
break | |
;; | |
esac | |
shift | |
done | |
return 0 | |
} | |
assert_env | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment