Intro to Google Cloud VMware Engine – Bastion Host Access with IAP – VMware Cloud Community
resource "google_project_iam_member" "bastion_sa_bindings" { for_each = toset(var.service_account_roles) project = var.project role = each.key member = "serviceAccount:${google_service_account.bastion_host.email}" }
google_project_iam_member.bastion_sa_bindings
completes the IAM-related configuration by granting roles defined in the service_account_roles
variable to the service account. This service account is assigned to the bastion host, which defines what the bastion host can do. The default roles assigned are listed below, but they can be modified in variables.tf
.
- Log Writer (
roles/logging.logWriter
) - Monitoring Metric Writer (
roles/monitoring.metricWriter
) - Monitoring Viewer (
roles/monitoring.viewer
) - Compute OS Login (
roles/compute.osLogin
)
resource "time_sleep" "wait_60_seconds" { create_duration = "60s" depends_on = [google_compute_instance.bastion_host] } data "external" "gcloud_set_bastion_password" { program = ["bash", "-c", "gcloud compute reset-windows-password ${var.name} --user=${var.username} --format=json --quiet"] depends_on = [time_sleep.wait_60_seconds] }
These final two blocks are what I refer to as “cool Terraform tricks.” The point of these blocks is to set the password on the bastion host. There are a few ways to do this, but unfortunately, there is no way to set a Windows instance password with a native Terraform resource. Instead, an external
data source is used to run the appropriate gcloud
command, with JSON formatted results returned (this is a requirement of the external
data source.) The password cannot be set until the bastion host is fully booted, so external.gcloud_set_bastion_pasword
depends on time_sleep.wait_60_seconds
, which is a simple 60-second timer that gives the bastion host time to boot up before the gcloud
command is run.
There is a chance that 60 seconds may not be long enough for the bastion host to boot. If you receive an error stating that the instance is not ready for use, you have two options:
- Run
terraform destroy
to remove the bastion host. Editmain.tf
and increase thecreate_duration
to a higher value, then runterraform apply
again. - Run the
gcloud compute reset-windows-password
command manually
Ideally, the password reset functionality would be built into the Google Cloud Terraform provider, and I wouldn’t be surprised to see it added in the future. If you’re reading this post in 2022 or beyond, it’s probably worth a quick investigation to see if this has happened.
output.tf Contents
output "bastion_username" { value = data.external.gcloud_set_bastion_password.result.username } output "bastion_password" { value = data.external.gcloud_set_bastion_password.result.password }
These two outputs are the results of running the gcloud command. Once Terraform has completed running, it will display the username and password set on the bastion host. A password is sensitive data, so if you want to prevent it from being displayed, add sensitive = true
to the bastion_password
output block. Output values are stored in the Terraform state file, so you should take precautions to protect the state file from unauthorized access. Additional information on Terraform outputs is available here.
terraform.tfvars Contents
terraform.tfvars
is the file that defines all the variables that are referenced in main.tf
. All you need to do is supply the desired values for your environment, and you are good to go. Note that the variables below are all examples, so simply copying and pasting may not lead to the desired result.
members = ["user:you@domain.com"] project = "your-gcp-project" region = "us-west2" zone = "us-west2-a" service_account_name = "bastion-sa" name = "bastion-vm" username = "bastionuser" labels = { owner = "Cloud Team", created_with = "terraform" } image = "gce-uefi-images/windows-2019" machine_type = "n1-standard-1" network_name = "gcve-usw2" subnet_name = "gcve-usw2-mgmt" tag = "bastion"
Additional information on the variables used is available in README.md. You can also find information on these variables, including their default values should one exist, in variables.tf
.
Initializing and Running Terraform
Terraform will use Application Default Credentials to authenticate to Google Cloud. Assuming you have the gcloud
cli tool installed, you can set these by running gcloud auth application-default
. Additional information on authentication can be found in the Getting Started with the Google Provider Terraform documentation. To run the Terraform code, follow the steps below.
Following these steps will create resources in your Google Cloud project, and you will be billed for them.
- Run
terraform init
and ensure no errors are displayed - Run
terraform plan
and review the changes that Terraform will perform - Run
terraform apply
to apply the proposed configuration changes
Should you wish to remove everything created by Terraform, run terraform destroy
and answer yes
when prompted. This will only remove the VPC network and related configuration created by Terraform. Your Google Cloud VMware Engine environment will have to be deleted using these instructions, if desired.
Now, you should have a fresh Windows 2019 Server running in Google Cloud to serve as a bastion host. Use this command to create a tunnel to the bastion host:
gcloud compute start-iap-tunnel [bastion-host-name] 3389 --zone [zone]
You will see a message that says Listening on port [random number]
. This random high port is proxied to your bastion host port 3389. Fire up your favorite RDP client and connect to localhost:[random number]
. Login with the credentials that were output from running Terraform. Once you’re able to connect to the bastion host, install the vSphere-compatible browser of your choice, along with any other management tools you may need.
If you’re a Windows user, there is an IAP-enabled RDP client available here.
Open the Google Cloud VMware Engine portal, browse to Resources
, and click on your SDDC, then vSphere Management Network
. This will display the hostnames for your vCenter, NSX and HCX instances. Copy the hostname for vCenter and paste it into a browser in your bastion host to verify you can access your SDDC.
Cloud DNS forwarding config to enable resolution of Google Cloud VMware Engine resources
Access to Google Cloud VMware Engine from your VPC is made possible by private service access and a DNS forwarding configuration in Cloud DNS. The DNS forwarding configuration enables name resolution from your VPC for resources in Google Cloud VMware Engine. It is automatically created in Cloud DNS when private service access is configured between your VPC and Google Cloud VMware Engine. This is a relatively new feature and a nice improvement. Previously, name resolution for Google Cloud VMware Engine required manually changing resolvers on your bastion host or configuring a standalone DNS server.
A quick recap of everything we’ve accomplished if you’ve been following this blog series from the beginning:
- Deployed an SDDC in Google Cloud VMware Engine
- Created a new VPC and configured private service access to your SDDC
- Deployed a bastion host in your VPC, accessible via IAP
Clearly, we are just getting started! My next post will look at configuring Cloud Interconnect and standing up an HCX service mesh. With that in place, we can begin migrating some workloads into our SDDC.