A safe default VM has no external IP, a dedicated service account, Shielded VM features on, and admins connect through IAP with OS Login.
flowchart LR T["gcloud compute instances create web-1"] --> IMG["Image family debian-12<br/>project debian-cloud"] T --> VM["VM web-1<br/>no external IP, tag web"] VM --> SA["Service account web-sa"] VM --> SS["Startup script installs nginx"] ADM["Admin"] -- "IAP + OS Login" --> VM %% step T: One command creates the VM with all its settings. %% step IMG: The boot disk comes from the latest image in a public image family, so it is patched at creation time. %% step VM: The VM gets only an internal IP and the network tag web for firewall rules. %% step SA: It runs as web-sa with just the roles it needs, not the default Compute Engine account. %% step SS: The startup script in metadata runs at every boot, here to install and start nginx. %% step ADM: The admin connects through IAP; OS Login maps their Google identity to a Linux account.
Create
gcloud compute instances create web-1 --zone=asia-southeast1-a --machine-type=e2-medium --image-family=debian-12 --image-project=debian-cloud --subnet=snet-web --no-address --tags=web --service-account=web-sa@dl-lab-dev.iam.gserviceaccount.com --scopes=cloud-platform --shielded-secure-boot --metadata-from-file=startup-script=startup.sh
| Option | Why |
|---|---|
--image-family + --image-project |
Always the newest image of that OS (Debian, Ubuntu, Rocky, Windows…) |
--no-address |
No external IP; use Cloud NAT for outbound and IAP for admin |
--tags |
Network tags for firewall rules |
--service-account, --scopes=cloud-platform |
Identity for code; permissions come from IAM roles |
--metadata-from-file=startup-script=… |
Runs at every boot (logs in serial port and journal) |
| Labels | --labels=env=dev,team=shop for cost reports |
Connect to Linux
gcloud compute ssh web-1 --zone=… --tunnel-through-iapcreates and uploads an SSH key for you.- OS Login (metadata
enable-oslogin=TRUE, or org policycompute.requireOsLogin) ties Linux users to IAM:roles/compute.osLogin(user) orroles/compute.osAdminLogin(sudo). Removing the IAM role removes access, with no keys left behind in metadata. - The serial console helps when SSH is broken (for example a firewall mistake on the VM).
Connect to Windows
Generate a password with gcloud compute reset-windows-password win-1 --zone=…, then RDP through gcloud compute start-iap-tunnel win-1 3389 ….
Metadata server
From inside a VM, http://metadata.google.internal/computeMetadata/v1/ (header Metadata-Flavor: Google) returns project and instance data and access tokens for the attached service account. Client libraries use it automatically.
| Command | Meaning |
|---|---|
gcloud compute instances list --filter="status=RUNNING" |
Running VMs |
gcloud compute instances add-metadata web-1 --metadata=enable-oslogin=TRUE --zone=… |
Turn on OS Login |
gcloud compute instances get-serial-port-output web-1 --zone=… |
Boot and startup-script log |
gcloud compute instances stop web-1 --zone=… |
Stop (keeps disks) |
Traps: the default service account with Editor turns any compromised VM into a project-wide risk; a startup script runs at every boot, so make it idempotent; deleting a VM deletes its boot disk unless auto-delete is off.