Last active
May 16, 2023 14:51
-
-
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
This file contains 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 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that there are no external IPs for any VMs in the project (cluster or bastion)