GKE - Terraform through bastion - the best solution

GKE - Terraform through bastion - the best solution

Access Kubernetes cluster in Terraform using bastion host as a proxy

Terraform documentation for the GKE module mentions bastion host access as an alternative to VPN. Of course, that topic does not exist if you use GKE with a public endpoint. A private cluster is recommended, so in this article, I will describe how to use Terraform through the bastion host.


There are 2 ways for accessing a private GKE cluster. Using a VPN or a bastion host. This article is not about VPN solution.

There is a Terraform module that presents the solution. Please, take a look at these sources, because this article will not cover theory.


Official documentation (the link above) presents a bastion host approach that uses tinyproxy application. From my experience, it works stable but slowly. Terraform plan execution takes so much time, especially when there are multiple resources tracked in the state.

I abandoned this solution as it was too slow for me. Too slow means that I've found out other way which is 5-10 times faster.

Socks proxy

The same effect can be achieved using socks proxy. Then, we don't need tinyproxy installed on the bastion.

Socks is proxying traffic through an SSH connection. It uses pretty same command as the first solution:

gcloud beta compute ssh ${BASTION_HOST} \
    --tunnel-through-iap \
    --project=${GOOGLE_PROJECT} \
    --zone=${GOOGLE_REGION} \
    -- -4 -D${KUBE_PROXY_PORT} -N -q -f

# set proxy address in ~/.kube/config
kubectl config set clusters.${KUBE_CLUSTER_NAME}.proxy-url socks5://${KUBE_PROXY_PORT}

As I observed, it works much faster than tinyproxy! But sometimes it crashes without error. Anyway, it's better.


The last solution that I've found uses sshutle application. Please, read what it is and how it works on the author's website.

This solution requires slightly more configuration. It is caused by the fact that I'm using Google IAP auth. I had to configure ~/.ssh/config :

Host <my-host-name>
  ProxyCommand gcloud beta compute start-iap-tunnel <my-bastion-host> <my-ssh-port-number> --listen-on-stdin --project=<my-gcp-project> --zone=<my-zone> --verbosity=warning
  IdentityFile /Users/<user>/.ssh/google_compute_engine
  User <user-on-bastion>

To get <user-on-bastion> I had to log in bastion host and get my current username by running whoami.

Now, I can run:

sshuttle -r <my-host-name> <control-plane-ip>

Where <control-plane-network> is in my case. It means that every traffic for this IP from my local computer will be proxied by sshutle. Kubectl, Terraform and other tools that want to connect to Kubernetes API will be able to do this.

As I observed, this solution has pretty much the same performance as the socks proxy.

My current approach is SSH socks proxy until VPN is not configured 🙂

Let me know how it works for you.