Showing posts with label kubeconfig. Show all posts
Showing posts with label kubeconfig. Show all posts

Friday, April 17, 2026

Managing kubeconfig files + download from Rancher

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.

  1. Directory layout
  2. Downloading kubeconfigs from Rancher
  3. Auto-discovery in .bashrc
  4. Testing connectivity
  5. 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:

  1. Run rancher_kubeconfig_dl.sh once (or after adding clusters in Rancher) to download all kubeconfigs into ~/.kube/clusters/.
  2. Open a new terminal. The find-based KUBECONFIG export picks up all files automatically. kubectx lists every context.
  3. Run test-kubeconfigs.sh to verify connectivity to all clusters in parallel.

No manual list to maintain, no UI clicking, and a quick way to verify everything is reachable.