Skip to content

Instantly share code, notes, and snippets.

@w3irdrobot
Created March 26, 2026 13:09
Show Gist options
  • Select an option

  • Save w3irdrobot/76fe8ad88c027009e12b1bc1e88b5a15 to your computer and use it in GitHub Desktop.

Select an option

Save w3irdrobot/76fe8ad88c027009e12b1bc1e88b5a15 to your computer and use it in GitHub Desktop.
Script for getting a rundown of an existing GKE cluster
#!/bin/bash
# GKE Cluster and NAT Information Script
# Usage: ./gke-nat-info.sh <cluster_name> [zone_or_region]
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Check arguments
if [ $# -lt 1 ]; then
echo -e "${RED}Usage: $0 <cluster_name> [zone_or_region]${NC}"
echo " zone_or_region: Optional. Defaults to gcloud config or prompts"
exit 1
fi
CLUSTER_NAME="$1"
LOCATION="${2:-}"
# Function to print section headers
print_header() {
echo -e "\n${CYAN}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${CYAN} $1${NC}"
echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
}
# Function to print subsection
print_subheader() {
echo -e "\n${YELLOW}► $1${NC}"
}
# Function to print info line
print_info() {
printf " %-35s " "$1:"
echo -e "$2"
}
# Function to print error
print_error() {
echo -e "${RED}✗ $1${NC}"
}
# Function to print success
print_success() {
echo -e "${GREEN}✓ $1${NC}"
}
# Check if gcloud is installed
if ! command -v gcloud &> /dev/null; then
print_error "gcloud CLI is not installed"
exit 1
fi
# Check if jq is installed
if ! command -v jq &> /dev/null; then
print_error "jq is not installed. Please install jq to run this script."
exit 1
fi
# Determine location if not provided
if [ -z "$LOCATION" ]; then
# Try to get from gcloud config
LOCATION=$(gcloud config get-value compute/zone 2>/dev/null || true)
if [ -z "$LOCATION" ]; then
LOCATION=$(gcloud config get-value compute/region 2>/dev/null || true)
fi
if [ -z "$LOCATION" ]; then
print_error "No zone or region specified and none found in gcloud config"
exit 1
fi
fi
# Detect if location is zone or region
if [[ "$LOCATION" =~ ^[a-z]+-[a-z]+[0-9]-[a-z]$ ]]; then
LOCATION_FLAG="--zone=$LOCATION"
REGION=$(echo "$LOCATION" | sed 's/-[a-z]$//')
else
LOCATION_FLAG="--region=$LOCATION"
REGION="$LOCATION"
fi
echo -e "\n${GREEN}🔍 Analyzing GKE Cluster: ${CLUSTER_NAME}${NC}"
echo -e "${GREEN}📍 Location: ${LOCATION}${NC}"
# ============================================
# CLUSTER INFORMATION
# ============================================
print_header "CLUSTER INFORMATION"
# Get cluster details
CLUSTER_INFO=$(gcloud container clusters describe "$CLUSTER_NAME" $LOCATION_FLAG --format='json' 2>/dev/null) || {
print_error "Failed to get cluster information. Check cluster name and location."
exit 1
}
# Extract basic info
CLUSTER_STATUS=$(echo "$CLUSTER_INFO" | jq -r '.status // "Unknown"')
NETWORK=$(echo "$CLUSTER_INFO" | jq -r '.network // "N/A"')
# Extract just the network name from potential URL format (e.g., "projects/PROJECT/global/networks/NAME")
NETWORK_NAME=$(echo "$NETWORK" | awk -F'/' '{print $NF}')
SUBNETWORK=$(echo "$CLUSTER_INFO" | jq -r '.subnetwork // "N/A"')
NETWORK_CONFIG=$(echo "$CLUSTER_INFO" | jq -r '.ipAllocationPolicy.useIpAliases // false')
# Check if private nodes are enabled
PRIVATE_NODES=$(echo "$CLUSTER_INFO" | jq -r '.privateClusterConfig.enablePrivateNodes // false')
# Check private endpoint
PRIVATE_ENDPOINT=$(echo "$CLUSTER_INFO" | jq -r '.privateClusterConfig.enablePrivateEndpoint // false')
# Master CIDR
MASTER_CIDR=$(echo "$CLUSTER_INFO" | jq -r '.privateClusterConfig.masterIpv4CidrBlock // "N/A"')
# Print cluster details
print_subheader "Basic Configuration"
print_info "Cluster Name" "$CLUSTER_NAME"
print_info "Location" "$LOCATION"
print_info "Network" "$NETWORK"
print_info "Subnetwork" "$SUBNETWORK"
print_info "VPC-native (IP Alias)" "$NETWORK_CONFIG"
print_subheader "Privacy Configuration"
if [ "$PRIVATE_NODES" = "true" ]; then
print_info "Private Nodes" "${GREEN}Enabled${NC}"
else
print_info "Private Nodes" "${RED}Disabled (Public)${NC}"
fi
if [ "$PRIVATE_ENDPOINT" = "true" ]; then
print_info "Private Endpoint" "${GREEN}Enabled${NC}"
else
print_info "Private Endpoint" "${YELLOW}Disabled (Public)${NC}"
fi
print_info "Master CIDR Block" "$MASTER_CIDR"
# ============================================
# NETWORK INFORMATION
# ============================================
print_header "NETWORK & SUBNET DETAILS"
if [ "$NETWORK" != "N/A" ] && [ -n "$NETWORK" ]; then
# Get subnet details
SUBNET_INFO=$(gcloud compute networks subnets describe "$SUBNETWORK" --region="$REGION" --format='json' 2>/dev/null || echo "{}")
SUBNET_RANGE=$(echo "$SUBNET_INFO" | jq -r '.ipCidrRange // "N/A"')
PRIVATE_GOOGLE_ACCESS=$(echo "$SUBNET_INFO" | jq -r '.privateIpGoogleAccess // false')
print_info "Subnet Primary Range" "$SUBNET_RANGE"
if [ "$PRIVATE_GOOGLE_ACCESS" = "true" ]; then
print_info "Private Google Access" "${GREEN}Enabled${NC}"
else
print_info "Private Google Access" "${RED}Disabled${NC}"
fi
# Get secondary ranges (pod and service ranges)
SECONDARY_RANGES=$(echo "$SUBNET_INFO" | jq -r '.secondaryIpRanges[]? | " \(.rangeName): \(.ipCidrRange)"' 2>/dev/null || echo "")
if [ -n "$SECONDARY_RANGES" ]; then
echo -e "\n ${YELLOW}Secondary IP Ranges:${NC}"
echo "$SECONDARY_RANGES"
fi
else
print_error "Could not retrieve network information"
fi
# ============================================
# CLOUD NAT & ROUTER INFORMATION
# ============================================
print_header "CLOUD NAT & ROUTER CONFIGURATION"
# Find Cloud Routers in the region
ROUTERS=$(gcloud compute routers list --regions="$REGION" --filter="network:$NETWORK_NAME" --format='table[no-heading](name)' 2>/dev/null || echo "")
if [ -z "$ROUTERS" ]; then
print_error "No Cloud Routers found in region $REGION for network $NETWORK_NAME"
echo -e "\n ${YELLOW}Note: Without Cloud NAT, private nodes will have no internet access.${NC}"
else
echo -e "\n ${GREEN}Found Cloud Routers:${NC}"
NAT_IP_ALLOCATION=""
for ROUTER in $ROUTERS; do
print_subheader "Router: $ROUTER"
# Get router details
ROUTER_INFO=$(gcloud compute routers describe "$ROUTER" --region="$REGION" --format='json' 2>/dev/null || echo "{}")
# List NAT configs
NAT_CONFIGS=$(gcloud compute routers nats list --router="$ROUTER" --region="$REGION" --format='table[no-heading](name)' 2>/dev/null || echo "")
if [ -z "$NAT_CONFIGS" ]; then
print_info "NAT Configuration" "${RED}None${NC}"
else
for NAT in $NAT_CONFIGS; do
print_info "NAT Gateway" "$NAT"
# Get NAT details
NAT_INFO=$(gcloud compute routers nats describe "$NAT" --router="$ROUTER" --region="$REGION" --format='json' 2>/dev/null || echo "{}")
NAT_IP_ALLOCATION_RAW=$(echo "$NAT_INFO" | jq -r '.natIpAllocateOption // "AUTO_ONLY"')
case "$NAT_IP_ALLOCATION_RAW" in
"MANUAL_ONLY")
NAT_IP_ALLOCATION="Manual (Static)"
;;
"AUTO_ONLY")
NAT_IP_ALLOCATION="Automatic (Dynamic)"
;;
*)
NAT_IP_ALLOCATION="$NAT_IP_ALLOCATION_RAW"
;;
esac
SOURCE_RANGES=$(echo "$NAT_INFO" | jq -r '.sourceSubnetworkIpRangesToNat // "ALL_SUBNETWORKS_ALL_IP_RANGES"')
print_info " IP Allocation" "$NAT_IP_ALLOCATION"
print_info " Source Ranges" "$SOURCE_RANGES"
# Get NAT IPs - try manual first, then auto
NAT_IPS=$(echo "$NAT_INFO" | jq -r '.natIps[]? | split("/") | last' 2>/dev/null || echo "")
if [ -z "$NAT_IPS" ]; then
# Try auto-allocated IPs
NAT_IPS=$(echo "$NAT_INFO" | jq -r '.autoAllocatedNatIps[]? | split("/") | last' 2>/dev/null || echo "")
fi
if [ -n "$NAT_IPS" ]; then
echo -e "\n ${YELLOW} NAT IP Addresses:${NC}"
for IP_NAME in $NAT_IPS; do
# Get actual IP address
IP_ADDR=$(gcloud compute addresses describe "$IP_NAME" --region="$REGION" --format='value(address)' 2>/dev/null || echo "N/A")
if [ "$IP_ADDR" != "N/A" ] && [ -n "$IP_ADDR" ]; then
echo -e " ${GREEN}→ $IP_ADDR${NC} (Name: $IP_NAME)"
else
echo -e " → $IP_NAME (IP address not found)"
fi
done
fi
# Additional NAT settings
DYNAMIC_PORT_ALLOC=$(echo "$NAT_INFO" | jq -r '.enableDynamicPortAllocation // false')
MIN_PORTS=$(echo "$NAT_INFO" | jq -r '.minPortsPerVm // "N/A"')
MAX_PORTS=$(echo "$NAT_INFO" | jq -r '.maxPortsPerVm // "N/A"')
print_info " Dynamic Port Allocation" "$DYNAMIC_PORT_ALLOC"
print_info " Min Ports per VM" "$MIN_PORTS"
print_info " Max Ports per VM" "$MAX_PORTS"
done
fi
done
fi
# ============================================
# FIREWALL RULES
# ============================================
print_header "FIREWALL RULES"
FIREWALL_RULES=$(gcloud compute firewall-rules list --filter="network:$NETWORK_NAME AND name~gke-$CLUSTER_NAME" --format='table[no-heading](name, sourceRanges.list():label=SRC_RANGES, allowed[0].ports:label=PORTS)' 2>/dev/null || echo "")
if [ -n "$FIREWALL_RULES" ]; then
echo -e " ${GREEN}GKE-related firewall rules found:${NC}\n"
gcloud compute firewall-rules list --filter="network:$NETWORK_NAME AND name~gke-$CLUSTER_NAME" --format='table(name, direction, sourceRanges.list():label=SRC_RANGES, allowed[0].ports:label=PORTS)' 2>/dev/null || echo " Could not retrieve firewall rules"
else
print_info "GKE Firewall Rules" "No specific rules found (using default or broad rules)"
fi
# ============================================
# SUMMARY
# ============================================
print_header "SUMMARY"
echo ""
if [ "$PRIVATE_NODES" = "true" ]; then
echo -e " ${GREEN}✓ Cluster has private nodes${NC}"
if [ -n "$ROUTERS" ] && [ -n "$NAT_CONFIGS" ]; then
echo -e " ${GREEN}✓ Cloud NAT is configured${NC}"
if [ "$NAT_IP_ALLOCATION" = "Manual (Static)" ]; then
echo -e " ${GREEN}✓ Using static NAT IPs - ready for IP whitelisting${NC}"
else
echo -e " ${YELLOW}⚠ Using automatic NAT IPs - IPs may change over time${NC}"
fi
else
echo -e " ${RED}✗ No Cloud NAT found - private nodes cannot reach internet!${NC}"
fi
else
echo -e " ${YELLOW}⚠ Cluster has public nodes${NC}"
echo -e " Nodes have external IPs and egress traffic bypasses NAT"
echo -e " To get static egress IP, either:"
echo -e " 1. Create private node pool (Standard clusters)"
echo -e " 2. Convert cluster to private nodes (Autopilot)"
fi
echo ""
echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
echo ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment