Private Remote Server on GCP
GCP has this amazing feature called iap-tunnel that is enabled in gcloud. This allows you to create a private tunnel from your local machine to a remote machine on GCP without granting the remote machine an internet/external ip.
The tunnel also works with regular GCP credentials, so we don't use ssh keys or anything else. We login to the remote using our regular GCP credentials.
This means the remote is fully secure from a network (no external ip) and identity (no static passwords) perspective. The tunnel emulates ssh completely (unlike session manager in AWS), and is complete enough for us to even use it as a vscode remote.
This project:
- Creates a VPC Network
- Creates a NAT router on the network
- Creates a special subnetwork in a region
- Deploys an ubuntu compute instance on the subnetwork
- Enables firewall rules for the IAP service to access the ubuntu compute instance (port 22, and port 8080)
- Has a example
~/.ssh/configfile for your configuration
Installation
Modify variables.tf to change the region and stack_name, then:
tf init
tf apply --auto-approve
Modify config below and then paste into your own location, on macOS this is typically ~/.ssh/config.
Host krozario.remote.machine
HostName <PRIVATE_IP_ADDRESS>
IdentityFile ~/.ssh/google_compute_engine
UserKnownHostsFile ~/.ssh/google_compute_known_hosts
ProxyCommand gcloud compute start-iap-tunnel "<INSTANCE_NAME>" %p --listen-on-stdin --project "<PROJECT_ID>" --zone=<ZONE_NAME> --verbosity=warning
StrictHostKeyChecking no
User <USERNAME_REPLACE_ALL_@_AND_DOT_WITH_UNDERSCORE> # e.g. k@k.com ==> k_k_com
Usage
ssh
Because it works like normal ssh, you can even use remote VSCode for this, the host will appear when you try to logon to a remote machine because it references the ssh config file.
Port Binding
Sometimes you want to bind ports on the remote to your local, so you can host webserver on the remote and access it via localhost on your local:
$ gcloud compute start-iap-tunnel remote-machine 8080
--local-host-port=localhost:8080
--zone=<ZONE_NAME>
--project=<PROJECT_ID>
Because of the firewall rules set via terraform only port 8080 is open for now. You can modify this if you want to bind another port on the remote by changing the firewall rules to allow other ports for the IAP access.
Windows
A note on windows, for Windows, we bind port 3389. We also set the password using the following command:
gcloud compute reset-windows-password remote-machine-windows --project=remote-machine-b7af52b6 --zone=asia-southeast1-a
Then we create a iap tunnel and bind to our localhost:
$ gcloud compute start-iap-tunnel remote-machine-windows 3389 \
--local-host-port=localhost:3389 \
--zone=<ZONE_NAME> \
--project=<PROJECT_ID>
Finally using the windows app on MacOS (or some other RDP client), we connect to localhost:3389
Extra: Updating MOTD
On Linux boxes like Ubuntu we can update the "message of the day" so that the port binding instructions are printed directly when you login. If you run 99-get-gcp-info, you'll get the required port binding command for your local straight from the VM (without needing to check zones or project IDs), my preferred option is to copy this file to /etc/update-motd.d/ to display this message on every logon. That way I don't have to remember anything.