Managing kubeconfig files across multiple Rancher clusters
When you manage several Kubernetes clusters through Rancher, you quickly end up with a pile of kubeconfig files. Downloading them by hand from the Rancher UI is tedious, keeping track of which ones are loaded is error-prone, and testing connectivity after a VPN change or token rotation is a chore.
Here is the setup I landed on: a download script, a directory convention, auto-discovery in the shell, and a parallel connectivity tester.
- Directory layout
- Downloading kubeconfigs from Rancher
- Auto-discovery in .bashrc
- Testing connectivity
- Putting it all together
Directory layout
~/.kube/
config # default kubectl config (GKE, kind, etc.)
clusters/
rancher_kubeconfig_dl.sh # download script
test-kubeconfigs.sh # connectivity tester
local.yaml # kubeconfig files live here
cluster-us-east-1.yaml
cluster-us-west-2.yaml
cluster-eu-west-1.yaml
cluster-ap-south-1.yaml
The scripts and kubeconfig files all live in ~/.kube/clusters/. The test script filters by kind: Config so it ignores non-kubeconfig files like itself.
Downloading kubeconfigs from Rancher
Rancher exposes a generateKubeconfig action on its v3 API. The following script lists all clusters your token has access to and downloads each kubeconfig into a directory.
First, create an API key in Rancher: top-right avatar, Account & API Keys, Create API Key. You get a token like token-xxxxx:yyyyyyy.
#!/usr/bin/env bash
# rancher_kubeconfig_dl.sh
# Downloads all kubeconfig YAML files from a Rancher instance.
#
# Usage:
# RANCHER_TOKEN=token-xxxxx:yyyyyyy ./rancher_kubeconfig_dl.sh
#
# To get a token manually:
# Rancher UI -> top-right avatar -> Account & API Keys -> Create API Key
set -euo pipefail
RANCHER_URL="${RANCHER_URL:-https://rancher.example.com}"
RANCHER_TOKEN="${RANCHER_TOKEN:-}"
OUTPUT_DIR="${OUTPUT_DIR:-.}"
# -- Auth --
if [[ -z "$RANCHER_TOKEN" ]]; then
echo "ERROR: Set RANCHER_TOKEN (e.g. token-xxxxx:yyyyyyy)"
echo " Rancher UI -> Avatar -> Account & API Keys -> Create API Key"
exit 1
fi
CURL_OPTS=(-sSf -H "Authorization: Bearer ${RANCHER_TOKEN}")
# -- Fetch cluster list --
echo "-> Fetching cluster list from ${RANCHER_URL} ..."
clusters_json=$(curl "${CURL_OPTS[@]}" "${RANCHER_URL}/v3/clusters")
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
echo "$clusters_json" | jq -r '.data[] | .id + "\t" + .name' > "$tmp"
count=$(wc -l < "$tmp" | tr -d ' ')
[[ "$count" -eq 0 ]] && { echo "No clusters found (check your token permissions)."; exit 1; }
echo "-> Found ${count} cluster(s)"
mkdir -p "$OUTPUT_DIR"
# -- Download kubeconfig per cluster --
while IFS=$(printf '\t') read -r id name; do
safe=$(echo "$name" | tr -cs '[:alnum:]-_.' '-' | sed 's/-$//')
out="${OUTPUT_DIR}/${safe}.yaml"
echo " ${name} (${id}) -> ${out}"
curl "${CURL_OPTS[@]}" \
-X POST \
"${RANCHER_URL}/v3/clusters/${id}?action=generateKubeconfig" \
| jq -r '.config' \
> "$out"
done < "$tmp"
echo ""
echo "Done. Kubeconfigs saved to: ${OUTPUT_DIR}/"
ls -lh "$OUTPUT_DIR"
Run it once, or whenever you add a new cluster to Rancher:
RANCHER_TOKEN=token-xxxxx:yyyyyyy ./rancher_kubeconfig_dl.sh
Each cluster gets its own file, named after the cluster. No manual copy-pasting from the Rancher UI.
Auto-discovery in .bashrc
kubectl merges all files listed in the KUBECONFIG environment variable (colon-separated). Instead of maintaining a hardcoded list that goes stale every time you add or remove a cluster, use find to discover them at shell startup:
# In ~/.bashrc or ~/.zshrc
export KUBECONFIG=~/.kube/config:$(find ~/.kube/clusters -name '*.yaml' 2>/dev/null | tr '\n' ':' | sed 's/:$//')
This starts with the default ~/.kube/config (for GKE, kind, minikube, or anything else) and appends every YAML file found in the clusters directory. find, tr, and sed are all POSIX — this works on macOS, Linux, and BSDs. Avoid find -printf which is a GNU extension and won't work on macOS.
Drop a new file in, open a new terminal, and kubectx sees it immediately. Remove a file and it disappears. No editing required.
Testing connectivity
After a VPN reconnect, a token rotation, or just to check that everything is reachable, run the test script. It finds all kubeconfig files in a directory, extracts every context from each file, and tests them all in parallel:
#!/usr/bin/env bash
# test-kubeconfigs.sh
# Test connectivity for all kubeconfig YAML files in a directory.
# Usage: ./test-kubeconfigs.sh [directory]
# directory: path containing kubeconfig YAML files (default: script directory)
set -euo pipefail
shopt -s nullglob
dir="${1:-$(dirname "$0")}"
if [[ ! -d "$dir" ]]; then
echo "Error: '$dir' is not a directory" >&2
exit 1
fi
test_context() {
local f="$1" ctx="$2" name
name="$(basename "$f")"
if kubectl --kubeconfig="$f" --context="$ctx" cluster-info --request-timeout=5s &>/dev/null; then
echo "OK $name context=$ctx"
else
echo "FAIL $name context=$ctx"
fi
}
pids=()
found=0
for f in "$dir"/*.yaml "$dir"/*.yml; do
[[ -f "$f" ]] || continue
grep -q 'kind: Config' "$f" 2>/dev/null || continue
found=$((found + 1))
contexts=$(kubectl --kubeconfig="$f" config get-contexts -o name 2>/dev/null)
if [[ -z "$contexts" ]]; then
echo "SKIP $(basename "$f") (no contexts found)" &
pids+=($!)
continue
fi
for ctx in $contexts; do
test_context "$f" "$ctx" &
pids+=($!)
done
done
if [[ $found -eq 0 ]]; then
echo "No kubeconfig files (kind: Config) found in $dir"
exit 1
fi
fail=0
for pid in "${pids[@]}"; do
wait "$pid" || fail=$((fail + 1))
done
pass=$(( ${#pids[@]} - fail ))
echo ""
echo "Results: $pass ok, $fail failed (from $found files)"
[[ $fail -eq 0 ]]
Each test runs as a background job, so checking six clusters takes as long as the slowest one (typically the 5-second timeout for an unreachable cluster), not six times that.
$ ./test-kubeconfigs.sh
OK cluster-us-east-1.yaml context=cluster-us-east-1
OK cluster-us-west-2.yaml context=cluster-us-west-2
OK cluster-eu-west-1.yaml context=cluster-eu-west-1
FAIL cluster-ap-south-1.yaml context=cluster-ap-south-1
OK local.yaml context=local
Results: 4 ok, 1 failed (from 5 files)
Putting it all together
The workflow is:
- Run
rancher_kubeconfig_dl.shonce (or after adding clusters in Rancher) to download all kubeconfigs into~/.kube/clusters/. - Open a new terminal. The
find-basedKUBECONFIGexport picks up all files automatically.kubectxlists every context. - Run
test-kubeconfigs.shto verify connectivity to all clusters in parallel.
No manual list to maintain, no UI clicking, and a quick way to verify everything is reachable.