Skip to content

Instantly share code, notes, and snippets.

@mikesparr
Last active May 16, 2023 14:51
Show Gist options
  • Save mikesparr/aabe1bd2b43b44632308811770d4febd to your computer and use it in GitHub Desktop.
Save mikesparr/aabe1bd2b43b44632308811770d4febd to your computer and use it in GitHub Desktop.
Google Cloud bastion jump host with Cloud IAP tunneling over private network example
#!/usr/bin/env bash
# set vars
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_USER=$(gcloud config get-value core/account) # set current user
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export IDNS=${PROJECT_ID}.svc.id.goog # workflow identity domain
export REGION="us-central1"
export ZONE="us-central1-a"
export NETWORK_NAME="default"
export BASTION_TEMPLATE_NAME="bastion-template"
export BASTION_GROUP_NAME="bastion"
export GKE_CLUSTER_NAME="central"
export GKE_MASTER_CIDR="172.16.0.0/28"
export GKE_NODES_PER_ZONE="1"
export GKE_CLUSTER_VERSION="1.17.13-gke.600"
export CLOUD_ROUTER_NAME="router-1"
export CLOUD_ROUTER_ASN="64520"
export NAT_GW_NAME="internet-gw"
# confirm they are installing in right project
while true; do
read -p "Create bastion on project ${PROJECT_ID} as user ${PROJECT_USER}? " -n 1 -r yn
echo
case $yn in
[Yy]* ) break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
# enable APIs
gcloud services enable compute.googleapis.com \
container.googleapis.com \
iap.googleapis.com
# grant SSH access
gcloud compute firewall-rules create allow-ssh-ingress-from-iap \
--direction=INGRESS \
--action=allow \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20
# grant user tunneling (one for each user or group [preferred])
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=user:$PROJECT_USER \
--role=roles/iap.tunnelResourceAccessor
# create cloud router and nat gateway
gcloud compute routers create $CLOUD_ROUTER_NAME \
--network $NETWORK_NAME \
--asn $CLOUD_ROUTER_ASN
--region $REGION
gcloud compute routers nats create $NAT_GW_NAME \
--router=$CLOUD_ROUTER_NAME \
--region=$REGION \
--auto-allocate-nat-external-ips \
--nat-all-subnet-ip-ranges \
--enable-logging
# create private gke regional cluster
gcloud beta container --project "${PROJECT_ID}" clusters create $GKE_CLUSTER_NAME \
--region "${REGION}" \
--no-enable-basic-auth \
--cluster-version "1.17.13-gke.600" \
--machine-type "e2-small" --image-type "COS" \
--disk-type "pd-standard" --disk-size "100" \
--node-labels role=gke-cluster \
--metadata disable-legacy-endpoints=true \
--scopes "https://www.googleapis.com/auth/cloud-platform" \
--preemptible \
--num-nodes $GKE_NODES_PER_ZONE \
--enable-stackdriver-kubernetes \
--enable-private-nodes \
--enable-private-endpoint \
--master-ipv4-cidr $GKE_MASTER_CIDR \
--enable-ip-alias \
--network "projects/${PROJECT_ID}/global/networks/${NETWORK_NAME}" \
--subnetwork "projects/${PROJECT_ID}/regions/${REGION}/subnetworks/${NETWORK_NAME}" \
--default-max-pods-per-node "110" \
--enable-autoscaling --min-nodes "0" --max-nodes "5" \
--enable-network-policy \
--enable-master-authorized-networks \
--addons HorizontalPodAutoscaling,HttpLoadBalancing,NodeLocalDNS \
--enable-autoupgrade --enable-autorepair --max-surge-upgrade 2 --max-unavailable-upgrade 1 \
--workload-pool $IDNS \
--enable-shielded-nodes \
--shielded-secure-boot
# create bastion jump host instance template (with NO external IP)
gcloud beta compute --project=$PROJECT_ID instance-templates create $BASTION_TEMPLATE_NAME \
--machine-type=e2-micro \
--subnet=projects/${PROJECT_ID}/regions/${REGION}/subnetworks/${NETWORK_NAME} \
--network-tier=STANDARD \
--no-address \
--maintenance-policy=MIGRATE \
--service-account=${PROJECT_NUMBER}[email protected] \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--region=$REGION \
--tags=bastion \
--image=ubuntu-2004-focal-v20201028 \
--image-project=ubuntu-os-cloud \
--boot-disk-size=10GB \
--boot-disk-type=pd-standard \
--boot-disk-device-name=$BASTION_TEMPLATE_NAME \
--shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring \
--labels=role=bastion \
--reservation-affinity=any
# create bastion jump host managed instance group (1)
gcloud compute --project=$PROJECT_ID instance-groups managed create $BASTION_GROUP_NAME \
--base-instance-name=$BASTION_GROUP_NAME \
--template=$BASTION_TEMPLATE_NAME \
--size=1 \
--zone=$ZONE
# wait for instance to start
sleep 45
# fetch bastion instance name
export BASTION_NAME=$(gcloud compute instance-groups managed list-instances $BASTION_GROUP_NAME --zone $ZONE --format="value(instance)")
# connect to bastion via IAP tunnel
gcloud beta compute ssh $BASTION_NAME \
--project $PROJECT_ID \
--zone $ZONE \
--tunnel-through-iap
# after first login ...
# initialize instance (will need NAT gateway enabled for network to access public Internet)
# google-cloud-sdk (man-db) will take a while for this small machine so be patient
# echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
# sudo apt-get install apt-transport-https ca-certificates gnupg
# curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
# sudo apt-get update && sudo apt-get upgrade && sudo apt-get install google-cloud-sdk && sudo apt-get install kubectl
# enjoy!
# users (or users in group) enabled with IAM role ( roles/iap.tunnelResourceAccessor )
# will be able to log in to bastion using gcloud beta ssh --zone $ZONE $BASTION_NAME and interact
@mikesparr
Copy link
Author

Note that there are no external IPs for any VMs in the project (cluster or bastion)

Screen Shot 2020-11-08 at 11 41 30 AM

@mikesparr
Copy link
Author

Once you log into the bastion using Cloud IAP, however, you can access the private network and your clusters (see after first login... steps above to configure your bastion first).

Screen Shot 2020-11-08 at 11 45 50 AM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment