Deploy a Google Cloud VM with IAM, firewall policy and OS Login
Create a private Ubuntu 24.04 LTS Compute Engine VM with Shielded VM, IAP TCP forwarding, OS Login, service-account-targeted firewall rules and a least-privilege workload identity, then prove access and recovery.
Operate a Google Cloud VM without public SSH or service-account keys, with separate human and workload authorization, explainable network policy and tested immutable rebuild or data restoration.
- Google Cloud CLI 577.0.0
- Ubuntu Server 24.04 LTS
- Compute Engine Shielded VM compatible
- Google Cloud context Approved organization, folder, project, billing, Region, zone, APIs, quotas, organization policies and short-lived operator identity.
gcloud config list && gcloud auth list - Address and egress plan Non-overlapping subnet allocation plus explicit Private Google Access, NAT, proxy, VPN, Interconnect and DNS decisions.
- Human access model Operator groups, OS Login versus OS Admin Login, IAP authorization, 2FA support and break-glass access are approved.
- Workload authorization Dedicated service-account owner, exact target resource and narrow data-plane role are documented; no user-managed key is needed.
- Recovery design Immutable image and configuration plus external data backup or application-consistent snapshots can be restored in isolation.
OneLiners never runs these steps or stores secrets. Review placeholders, versions, current state, and change-control requirements before using a command.
Full guide
What you will build
- A Google Compute Engine VM using a supported Ubuntu 24.04 LTS image, Shielded VM controls, no external IPv4 address, a dedicated service account, least-privilege IAM, OS Login and optional OS Login two-factor authentication where the organization supports it.
- A custom-mode VPC, regional subnet and narrowly targeted ingress firewall rules using service accounts instead of mutable network tags where practical. Administrative SSH traverses Identity-Aware Proxy TCP forwarding rather than a public IP.
- A production operating model covering organization policy, IAM separation, firewall logging, VPC Flow Logs when justified, Shielded VM integrity, customer-managed encryption key decisions, patching, monitoring, backups or immutable rebuild, identity offboarding, incident access and measured restoration.
- The instance has no access configuration and therefore no external IP, uses the expected image and machine type, reports vTPM, Secure Boot and integrity monitoring, and is reachable through IAP only by an explicitly authorized operator.
- OS Login governs Linux account and SSH-key lifecycle from IAM, project metadata does not contain unmanaged SSH keys, the VM service account has only the required resource-scoped role and the instance uses a restricted OAuth access scope.
- An approved application source reaches only the required port, unauthorized and direct public SSH tests fail, firewall and route evidence is explainable, audit and monitoring are owned, and rebuild or restore succeeds within RTO.
Architecture
How the parts fit together
A custom VPC and regional subnet provide private addressing. A firewall rule allows IAP TCP forwarding addresses to TCP/22 only for instances represented by the dedicated VM service account, while application ingress uses a separate source and target. The VM has no external IP and uses Shielded VM Secure Boot, vTPM and integrity monitoring. OS Login maps IAM principals to guest accounts and SSH certificates or keys, centralizing lifecycle and audit; an operator needs OS Login plus IAP and suitable instance access permissions. A dedicated service account is attached to the VM with the cloud-platform OAuth scope, while IAM roles constrain actual API authorization at the smallest resource scope. Cloud Logging and Monitoring capture platform and selected guest evidence, firewall logging and VPC Flow Logs are enabled only with privacy/cost ownership, and the workload is recovered through immutable rebuild plus external data restore or tested disk snapshots.
- Confirm organization, billing project, target project, Region/zone, APIs, quota, organization policies, image support, IP plan, application exposure, IAM owners and recovery requirements.
- Create a custom VPC and regional subnet, review routes and hierarchical firewall policy, then enable OS Login in project metadata.
- Create a dedicated service account with no user-managed key, assign only the required data role at the exact resource scope and grant administrators the separate OS Login and IAP roles.
- Create firewall rules for IAP SSH and the application using narrow sources and service-account targets; enable logging only with retention and privacy review.
- Create the Shielded VM without an external IP, attach the dedicated service account and use the cloud-platform scope while letting IAM enforce least privilege.
- Verify access config absence, shielded settings, effective firewall policy, OS Login identity, positive and negative workload authorization and boot/application health.
- Operate through policy drift alerts, IAM review, patch and image refresh, flow-log analysis, key and disk review, snapshots or rebuild drills and clean identity/resource retirement.
Assumptions
- Google Cloud CLI 577.0.0, released 2026-07-21, is the reference version. Commands use stable documented interfaces and are revalidated after CLI or API changes.
- The operator uses short-lived workforce or workload authentication. Application-default credentials and service-account key JSON files are not copied to the VM or repository.
- The target organization, folder, project, billing account, Region and zone are approved, required APIs are enabled and organization policies are known.
- Ubuntu 24.04 LTS from the official `ubuntu-os-cloud` image project is supported for the selected machine family and Shielded VM configuration.
- The subnet does not overlap peerings, Cloud VPN, Interconnect, GKE, on-premises or other VPC ranges. Private Google Access and Cloud NAT are separate egress decisions.
- IAP TCP forwarding is the approved administrative path. Operators have the IAP-secured tunnel role plus OS Login role and the permissions required to view/connect to the instance.
- OS Login is compatible with the image and organization identity model. Enabling OS Login stops metadata-based SSH keys from granting access to the VM.
- A dedicated service account exists only for this workload trust boundary. It has no user-managed keys and receives no basic Owner, Editor or Viewer role.
- The `cloud-platform` access scope is used because modern authorization is controlled through IAM; a restricted scope cannot grant permission absent IAM, but broad IAM remains dangerous.
- Customer-supplied encryption keys are not used because they are deprecated. CMEK is selected only when key ownership requirements justify key availability, IAM, rotation and recovery complexity.
- The application state is externalized or protected through an approved snapshot/backup process. A snapshot is crash-consistent unless the workload performs application quiescence.
- Firewall Rules Logging and VPC Flow Logs can expose IPs, ports and communication patterns. Sampling, metadata, retention, access and cost are approved before enabling them.
Key concepts
- OS Login
- A Compute Engine feature that uses IAM identities and POSIX profiles for SSH authorization. It replaces project and instance metadata SSH keys on enabled VMs and supports centralized offboarding.
- IAP TCP forwarding
- An authenticated proxy path from a client to an internal VM TCP port. It removes the need for an external IP but requires both IAP authorization and guest access authorization.
- Target service account
- A firewall target matching instances whose network interface uses a specified service account. It is generally more identity-bound than mutable network tags, but changing the attached service account changes target membership.
- Shielded VM
- Compute Engine security features including Secure Boot, virtual TPM and integrity monitoring for compatible images. Baseline changes need investigation rather than blind acceptance.
- Service account
- A non-human Google identity used by workloads. Attached VM identity obtains short-lived tokens from the metadata server and should not use downloadable keys.
- Access scope
- A legacy OAuth scope ceiling on tokens issued to a VM. IAM still authorizes requests; cloud-platform avoids accidental scope denial while least privilege is expressed in IAM.
- Hierarchical firewall policy
- Organization- or folder-level firewall rules that can enforce policy above project VPC rules. Effective connectivity cannot be understood from project rules alone.
- CMEK
- A Cloud KMS customer-managed encryption key referenced by a disk. It adds key-policy and availability dependencies and requires the Compute Engine service agent to use the key.
Before you copy
Values used in this guide
{{projectId}}Approved Google Cloud project ID.
Example: ops-prod-123456{{region}}Approved Compute Engine Region.
Example: europe-west1{{zone}}Approved zone within the Region.
Example: europe-west1-b{{networkName}}Custom VPC name.
Example: vpc-ops-prod{{subnetName}}Regional subnet name.
Example: snet-admin-tools{{subnetCidr}}Non-overlapping private subnet prefix.
Example: 10.52.10.0/24{{vmName}}Compute Engine instance name.
Example: vm-ops-01{{machineType}}Approved machine type.
Example: e2-standard-2{{serviceAccountName}}Dedicated VM service account short name.
Example: sa-vm-ops-01{{operatorPrincipal}}Approved user or group receiving OS Login, IAP tunnel, and narrowly scoped Service Account User access needed to connect to this VM when it has an attached service account.
Example: group:platform-operators@example.com{{applicationPort}}Required application TCP port.
Example: 443{{applicationSourceCidr}}Narrow approved application source.
Example: 198.51.100.0/24{{targetResource}}Exact Cloud Storage bucket URI receiving the example workload IAM binding.
Example: gs://ops-backup-prod{{targetRole}}Narrow predefined or custom workload role.
Example: roles/storage.objectViewer{{snapshotName}}Recovery drill snapshot name.
Example: vm-ops-01-drill-20260728Security and production boundaries
- Do not attach an external IP for convenience. Use IAP, VPN or another private path and retain an audited emergency-access procedure.
- IAP access is not OS access. Require IAP tunnel, OS Login, suitable Compute visibility and Service Account User on the one attached identity; keep that workload identity least privilege and use groups/PAM rather than permanent individual grants.
- Do not grant service-account user or token-creator roles broadly. Impersonation can be equivalent to the service account's data access.
- Never create or download a service-account key for an attached VM. Metadata-server tokens are short lived; printing them still exposes bearer credentials.
- Project metadata is broad and instance metadata takes precedence. Enabling OS Login at project scope is not enforcement by itself; use the organization policy that requires OS Login when administrators must not be able to set enable-oslogin=FALSE on individual VMs.
- Firewall target service accounts and source service accounts are evaluated as identity selectors, but network traffic still needs TLS and application authorization.
- Secure Boot can reject unsigned kernel modules. Investigate compatibility before disabling it, and make any exception image-specific, time-bound and reviewed.
- CMEK can make disks unavailable if the key, version, IAM grant or project is disabled. Align key retention and recovery with snapshot and disk retention.
- Audit and flow logs contain identity, IP, method and resource metadata. Apply least privilege, retention and export controls and avoid duplicating raw logs into tickets.
- Delete project-wide default networks and broad legacy rules in a separate reviewed migration; do not combine cleanup with first workload deployment.
Stop before continuing if
- Stop if the active account or project differs from the approved project.
- Stop if the default network or a broad `0.0.0.0/0` SSH rule would be used.
- Stop if the subnet overlaps any connected network or future reserved range.
- Stop if organization or hierarchical firewall policy is unknown.
- Stop if the VM would receive an external IP or use metadata SSH keys instead of the approved OS Login model.
- Stop if the workload requires basic Owner/Editor/Viewer or project-wide broad data access.
- Stop if the service account has a user-managed key or broad impersonation grants.
- Stop if Secure Boot, vTPM or integrity monitoring cannot be enabled without a documented exception.
- Stop if a secret appears in startup scripts, metadata, labels, command arguments or logs.
- Stop if no rebuild or restore path has passed within RTO.
command
Pin the gcloud account, project, Region and zone
Use a named gcloud configuration and short-lived user or federated identity. Verify project metadata, billing, APIs, quota and organization policy before creating a resource.
Why this step matters
Google Cloud configuration can be changed by named configurations, environment variables and command flags. Explicitly setting and displaying the account, project, Region and zone prevents resources from landing in a personal project or unapproved geography. The reference version is gcloud 577.0.0 released 2026-07-21.
What to understand
Confirm the project belongs to the intended organization and billing account. Inspect inherited organization policies for external IP, service accounts, allowed images, locations and firewall controls.
Verify Compute Engine, IAP, OS Login dependencies, Logging and Monitoring APIs plus CPU and IP quota. An enabled API does not grant the operator permission.
System changes
- Changes only the local gcloud configuration; no cloud resource is created.
Syntax explained
gcloud config set project- Pins later commands to the approved project unless an explicit command flag overrides it.
Values stay on this page and are never sent or saved.
gcloud version && gcloud auth list && gcloud config set project {{projectId}} && gcloud config set compute/region {{region}} && gcloud config set compute/zone {{zone}} && gcloud config listGoogle Cloud SDK 577.0.0 ACTIVE ACCOUNT * platform-operator@example.com project = ops-prod-123456 region = europe-west1 zone = europe-west1-b
Checkpoint: Verify this layer before continuing
Continue whenAccount, organization project, Region, zone, APIs and quota exactly match the approved change.
Stop whenStop on an unexpected account/project, personal credentials, missing organization context, unsupported zone or policy conflict.
If this step fails
gcloud reports no active account or an unexpected project.
Likely causeAuthentication expired, a different named configuration is active or environment variables override local settings.
gcloud config configurations listgcloud info
ResolutionActivate a dedicated approved configuration, reauthenticate through workforce federation and repeat every preflight check.
Security notes
- Do not store ADC tokens, refresh tokens or service-account key files in the repository or support evidence.
Alternatives
- Use workload identity federation and a reviewed CI deployment service account for repeatable production deployments.
Stop conditions
- Stop on an unexpected account/project, personal credentials, missing organization context, unsupported zone or policy conflict.
command
Create a custom VPC and regional subnet
Create a custom-mode VPC with no automatic subnets, then add one reviewed non-overlapping regional subnet. Enable Private Google Access only if private instances require Google API access.
Why this step matters
Custom mode prevents automatic regional subnets and legacy convenience rules, making address ownership explicit. The subnet must fit future peering, VPN, Interconnect, container and private-service ranges. Private Google Access allows internal addresses to reach supported Google APIs but is not a general Internet egress path.
What to understand
Inspect existing routes, peerings and organization networks before allocation. Overlap can make hybrid routing ambiguous and is expensive to repair after workload deployment.
No external IP does not mean no egress. Default routes, Cloud NAT, proxies and Private Google Access have different destinations and logging; design each from workload requirements.
System changes
- Creates a global custom VPC and one regional subnet with Private Google Access.
Syntax explained
--subnet-mode=custom- Prevents Google Cloud from creating one automatic subnet per Region.
Values stay on this page and are never sent or saved.
gcloud compute networks create {{networkName}} --subnet-mode=custom --bgp-routing-mode=regional && gcloud compute networks subnets create {{subnetName}} --network={{networkName}} --region={{region}} --range={{subnetCidr}} --enable-private-ip-google-accessCreated [global/networks/vpc-ops-prod]. NAME SUBNET_MODE BGP_ROUTING_MODE vpc-ops-prod CUSTOM REGIONAL Created [regions/europe-west1/subnetworks/snet-admin-tools]. RANGE PRIVATE_GOOGLE_ACCESS 10.52.10.0/24 True
Checkpoint: Verify this layer before continuing
Continue whenThe VPC has only the approved subnet, prefix is non-overlapping and Private Google Access matches the egress design.
Stop whenStop on prefix overlap, unexpected routes/peerings, automatic subnet creation or unowned hybrid connectivity.
If this step fails
Subnet creation says IP range overlaps.
Likely causeThe prefix intersects another subnet, peering, VPN, Interconnect or reserved private-service range.
gcloud compute networks subnets list --network={{networkName}}gcloud compute routes list --filter='network:{{networkName}}'
ResolutionReturn to IP address management, choose an approved non-overlapping range and rerun before creating instances.
Security notes
- Network names, prefixes and peerings are sensitive architecture metadata; publish only sanitized examples.
Alternatives
- Use a centrally governed Shared VPC subnet when a network-host project owns routing, firewall and flow logs.
Stop conditions
- Stop on prefix overlap, unexpected routes/peerings, automatic subnet creation or unowned hybrid connectivity.
command
Enable OS Login and create the dedicated service account
Enable OS Login in project metadata after inventorying exceptions. Create a workload service account with no key, then confirm that no user-managed key exists.
Why this step matters
OS Login centralizes Linux SSH authorization in IAM and disables metadata SSH keys on enabled instances. A dedicated service account separates workload API permissions from human guest access. Creating it without downloadable keys keeps credential delivery on the metadata server with short-lived tokens.
What to understand
Project-level OS Login affects compatible instances unless overridden. Test automation and break-glass access, and consider `enable-oslogin-2fa=TRUE` only where workforce identity support and emergency procedures are validated.
Service-account display names are not security identifiers. Use the full email and immutable unique ID when reviewing bindings. Do not reuse the default Compute Engine service account.
System changes
- Updates project common metadata and creates a service-account identity; it creates no credential key.
Syntax explained
enable-oslogin=TRUE- Makes OS Login IAM authorization take precedence over project and instance metadata SSH keys.
Values stay on this page and are never sent or saved.
gcloud compute project-info add-metadata --metadata=enable-oslogin=TRUE && gcloud iam service-accounts create {{serviceAccountName}} --display-name='Operations VM workload identity' && gcloud iam service-accounts keys list --iam-account={{serviceAccountName}}@{{projectId}}.iam.gserviceaccount.comUpdated [commonInstanceMetadata]. Created service account [sa-vm-ops-01]. KEY_ID CREATED_AT EXPIRES_AT DISABLED (no user-managed keys)
Checkpoint: Verify this layer before continuing
Continue whenProject metadata enables OS Login, the dedicated service account exists and only Google-managed system credentials are present.
Stop whenStop if legacy automation depends on metadata keys, emergency access is untested or any user-managed service-account key exists.
If this step fails
Existing users lose SSH after OS Login is enabled.
Likely causeThey lack OS Login IAM roles, POSIX profile or IAP permissions, or relied on metadata keys.
gcloud compute os-login describe-profilegcloud compute project-info describe --format='yaml(commonInstanceMetadata)'
ResolutionAssign the narrow operator group roles and validate IAP plus OS Login in a pilot; do not restore unmanaged project keys broadly.
Security notes
- Never grant users permission to create service-account keys as a shortcut for VM access.
Alternatives
- Enable OS Login per instance during a staged migration before moving the reviewed setting to project metadata.
Stop conditions
- Stop if legacy automation depends on metadata keys, emergency access is untested or any user-managed service-account key exists.
command
Grant operator and workload permissions at narrow scope
Grant the operator group OS Login and IAP tunnel roles, grant that group Service Account User on this one attached VM service account as required by OS Login, then bind the VM service account to the exact Cloud Storage bucket with a narrow data role.
Why this step matters
Human connectivity requires IAP tunnel authorization, OS Login guest authorization, Compute visibility, and—because the VM has an attached service account—Service Account User on that service account. A user who can log in can potentially use the VM's metadata credentials, so the attached workload identity must itself be least privilege. The workload service account receives one data role on one bucket; it never becomes the human SSH principal.
What to understand
OS Admin Login includes sudo and should be limited to an eligible administrative group. Ordinary diagnostics may need only OS Login. Add instance-view permissions through a narrow custom or documented role.
Service Account User is granted on only the attached account, never project-wide. Treat it as access to that account's effective data permissions and keep the workload role narrow enough for every approved VM operator.
The example workload binding uses the Cloud Storage bucket-level command. For another service, replace it with that service's resource-level IAM command rather than moving the role to project scope.
System changes
- Creates human IAP/OS Login bindings, one service-account-level Service Account User binding, and one bucket-level workload data binding.
Syntax explained
roles/iap.tunnelResourceAccessor- Authorizes IAP TCP forwarding but does not itself grant Compute instance visibility or guest OS Login.
Values stay on this page and are never sent or saved.
gcloud projects add-iam-policy-binding {{projectId}} --member='{{operatorPrincipal}}' --role='roles/compute.osLogin' && gcloud projects add-iam-policy-binding {{projectId}} --member='{{operatorPrincipal}}' --role='roles/iap.tunnelResourceAccessor' && gcloud iam service-accounts add-iam-policy-binding {{serviceAccountName}}@{{projectId}}.iam.gserviceaccount.com --member='{{operatorPrincipal}}' --role='roles/iam.serviceAccountUser' && gcloud storage buckets add-iam-policy-binding {{targetResource}} --member='serviceAccount:{{serviceAccountName}}@{{projectId}}.iam.gserviceaccount.com' --role='{{targetRole}}'Updated IAM policy for project [ops-prod-123456]. bindings: - members: - group:platform-operators@example.com role: roles/compute.osLogin - members: - group:platform-operators@example.com role: roles/iap.tunnelResourceAccessor - members: - group:platform-operators@example.com role: roles/iam.serviceAccountUser resource: sa-vm-ops-01@ops-prod-123456.iam.gserviceaccount.com Workload binding: serviceAccount:sa-vm-ops-01@ops-prod-123456.iam.gserviceaccount.com roles/storage.objectViewer on gs://ops-backup-prod
Checkpoint: Verify this layer before continuing
Continue whenThe operator group has required IAP/OS Login plus Service Account User only on the attached identity; the workload identity has one bucket-level data role with no broad inheritance.
Stop whenStop if basic roles, service-account Token Creator, project-wide Service Account User, project-wide data access or permanent individual admin bindings are proposed.
If this step fails
An IAM policy update is denied.
Likely causeThe operator lacks IAM administration, an organization deny policy applies or conditional-binding syntax is invalid.
gcloud projects get-iam-policy {{projectId}} --format=json
ResolutionHave the authorized IAM owner apply the reviewed narrow bindings; do not escalate the deployment identity to Owner.
Security notes
- Use groups, PAM and time-bound conditions for humans. Broad service-account impersonation is equivalent to its effective permissions.
Alternatives
- Use instance-level OS Login/IAP IAM and IAM Conditions when access must be limited to one VM and the required permissions support that scope; Service Account User remains scoped to the attached service account.
Stop conditions
- Stop if basic roles, service-account Token Creator, project-wide Service Account User, project-wide data access or permanent individual admin bindings are proposed.
command
Create IAP SSH and application firewall rules
Allow IAP's documented TCP forwarding range to SSH and the approved application source to one port. Target the dedicated VM service account and enable firewall logging with metadata inclusion only after privacy review.
Why this step matters
IAP TCP forwarding originates from the documented 35.235.240.0/20 range, so the network needs a path to SSH while IAM controls which users can establish a tunnel. The application has a distinct source and target rule. Service-account targeting binds rule membership to workload identity more strongly than mutable tags.
What to understand
Firewall rule priority is lower number first. Review hierarchical firewall policies and all project rules because an earlier allow or deny can change the outcome.
Firewall logging can record allowed/denied five-tuples and metadata. Define sampling, retention, exclusions, access and budget before high-volume production use.
System changes
- Creates two ingress allow rules and logging configuration; the VPC implied deny rejects other ingress.
Syntax explained
--target-service-accounts- Applies the rule to NICs of instances using the named service account rather than any instance carrying a mutable tag.
Values stay on this page and are never sent or saved.
gcloud compute firewall-rules create allow-iap-ssh --network={{networkName}} --direction=INGRESS --priority=900 --action=ALLOW --rules=tcp:22 --source-ranges=35.235.240.0/20 --target-service-accounts={{serviceAccountName}}@{{projectId}}.iam.gserviceaccount.com --enable-logging && gcloud compute firewall-rules create allow-approved-app --network={{networkName}} --direction=INGRESS --priority=1000 --action=ALLOW --rules=tcp:{{applicationPort}} --source-ranges={{applicationSourceCidr}} --target-service-accounts={{serviceAccountName}}@{{projectId}}.iam.gserviceaccount.com --enable-loggingNAME DIRECTION PRIORITY ALLOW SOURCE_RANGES TARGET_SERVICE_ACCOUNTS allow-iap-ssh INGRESS 900 tcp:22 35.235.240.0/20 sa-vm-ops-01@... allow-approved-app INGRESS 1000 tcp:443 198.51.100.0/24 sa-vm-ops-01@... Logging: enabled
Checkpoint: Verify this layer before continuing
Continue whenOnly IAP can reach TCP/22 and only the approved source can reach the application port; logging and retention have owners.
Stop whenStop if source becomes 0.0.0.0/0, target is absent, hierarchy is unknown or logging lacks privacy/cost approval.
If this step fails
Rule creation is rejected for target service account.
Likely causeThe service account is in another project, permissions are missing or a firewall-policy constraint applies.
gcloud compute firewall-rules describe allow-iap-sshgcloud compute firewall-policies list
ResolutionResolve exact identity and hierarchical policy with network owners; do not replace the target with a broad all-instance rule.
Security notes
- Firewall logs expose communication metadata. Restrict log access and avoid sensitive labels or rule descriptions.
Alternatives
- Use hierarchical firewall policies for organization-wide mandatory IAP access and explicit egress control.
Stop conditions
- Stop if source becomes 0.0.0.0/0, target is absent, hierarchy is unknown or logging lacks privacy/cost approval.
command
Create the Shielded VM with no external IP
Create the VM on the private subnet using the dedicated service account, cloud-platform scope, official Ubuntu 24.04 LTS image family and all Shielded VM controls. No `--address` or external access configuration is added.
Why this step matters
The command creates a private instance whose workload identity and firewall target are the dedicated service account. Cloud-platform scope prevents legacy OAuth scope from blocking intended APIs, while IAM remains the actual least-privilege layer. Shielded VM protects the boot chain and absence of an external address removes direct Internet ingress.
What to understand
Resolve and record the exact source image ID because an image family advances over time. Production IaC should pin a tested image and refresh it through a controlled image pipeline.
Labels help ownership and cost but are visible metadata. Do not place usernames, tickets, secrets or customer identifiers in them.
No external IP may require Cloud NAT, Private Google Access, proxy or private endpoints for updates. Add only the egress path the workload needs and monitor it.
System changes
- Creates the VM, boot disk and NIC with a service-account identity and no external IP.
Syntax explained
--no-address- Creates the NIC without an external IPv4 access configuration.
Values stay on this page and are never sent or saved.
gcloud compute instances create {{vmName}} --zone={{zone}} --machine-type={{machineType}} --network={{networkName}} --subnet={{subnetName}} --no-address --image-family=ubuntu-2404-lts-amd64 --image-project=ubuntu-os-cloud --service-account={{serviceAccountName}}@{{projectId}}.iam.gserviceaccount.com --scopes=https://www.googleapis.com/auth/cloud-platform --shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --maintenance-policy=MIGRATE --labels=environment=production,service=admin-toolsNAME ZONE MACHINE_TYPE INTERNAL_IP EXTERNAL_IP STATUS vm-ops-01 europe-west1-b e2-standard-2 10.52.10.2 RUNNING Shielded VM: enableSecureBoot: true enableVtpm: true enableIntegrityMonitoring: true
Checkpoint: Verify this layer before continuing
Continue whenThe VM runs with no external IP, correct private subnet, dedicated service account, official image and all Shielded controls enabled.
Stop whenStop if external IP exists, default service account is attached, image provenance differs or a Shielded control is false.
If this step fails
The image does not support Secure Boot or instance creation fails.
Likely causeImage, architecture, machine type, zone or organization policy is incompatible with the requested configuration.
gcloud compute images describe-from-family ubuntu-2404-lts-amd64 --project=ubuntu-os-cloudgcloud compute machine-types describe {{machineType}} --zone={{zone}}
ResolutionChoose a supported official Shielded image and machine type; do not disable the control without a reviewed exception.
Security notes
- Do not use startup-script metadata for secrets. Attached identity plus Secret Manager or another approved service should provide runtime access.
Alternatives
- Use an instance template and Managed Instance Group for replaceable workloads rather than a long-lived individually modified VM.
Stop conditions
- Stop if external IP exists, default service account is attached, image provenance differs or a Shielded control is false.
verification
Verify access configuration, identity and Shielded state
Read the instance model and Shielded settings, confirm the NIC has no accessConfigs entry, inspect the service account and resolve the exact source image.
Why this step matters
Effective-state inspection catches creation flags that were ignored or later changed. An empty accessConfigs list is the authoritative indication that the NIC lacks an external IP. The attached service account determines both workload identity and firewall target membership, making an unexpected identity a dual authorization issue.
What to understand
Inspect metadata for OS Login and ensure no `ssh-keys` item reintroduces unmanaged access. Project OS Login overrides keys on supported images, but stray metadata should still be removed.
Check boot disk auto-delete behavior and encryption key. VM deletion can delete an auto-delete boot disk; application recovery must not depend on an undocumented disk default.
System changes
- No state changes; reads the Compute Engine instance representation.
Syntax explained
accessConfigs: []- Shows that the NIC has no external NAT access configuration and therefore no external IPv4 address.
Values stay on this page and are never sent or saved.
gcloud compute instances describe {{vmName}} --zone={{zone}} --format='yaml(name,status,networkInterfaces,serviceAccounts,shieldedInstanceConfig,disks,metadata.items)'name: vm-ops-01 status: RUNNING networkInterfaces: - networkIP: 10.52.10.2 accessConfigs: [] serviceAccounts: - email: sa-vm-ops-01@ops-prod-123456.iam.gserviceaccount.com scopes: - https://www.googleapis.com/auth/cloud-platform shieldedInstanceConfig: enableIntegrityMonitoring: true enableSecureBoot: true enableVtpm: true
Checkpoint: Verify this layer before continuing
Continue whenNo access configuration exists, service account is exact, OS Login applies and all Shielded flags are true.
Stop whenStop on any public address, metadata SSH key, wrong identity, untrusted image or disabled Shielded feature.
If this step fails
The instance shows an unexpected external NAT configuration.
Likely causeA later update or alternate creation tool attached an access configuration.
gcloud compute instances describe {{vmName}} --zone={{zone}} --format='json(networkInterfaces)'
ResolutionRemove the external access configuration through reviewed change control, inspect exposure logs and repeat unauthorized access tests.
Security notes
- Instance metadata and serial logs can expose topology and accidental secrets; sanitize evidence.
Alternatives
- Use Organization Policy to prevent external IP assignment and Policy Controller or CI checks for continuous enforcement.
Stop conditions
- Stop on any public address, metadata SSH key, wrong identity, untrusted image or disabled Shielded feature.
verification
Connect through IAP with OS Login and test offboarding
Connect with gcloud's IAP tunnel, verify the OS Login-derived account and sudo boundary, then remove a temporary test principal and confirm access is revoked. Do not add a metadata key.
Why this step matters
The connection proves IAP authorization, firewall source, Compute visibility, OS Login mapping, SSH daemon and private routing together. The guest identity confirms centralized account mapping. A deliberate sudo check validates whether the chosen OS Login role provides ordinary or administrative access.
What to understand
Use `roles/compute.osLogin` for non-sudo access and `roles/compute.osAdminLogin` only for eligible administrators. Combine with PAM/time-bound access where available.
Offboarding needs removal from every inherited group/binding and termination of active sessions according to incident policy. New connection denial is necessary but may not kill an existing shell.
System changes
- Creates a temporary authenticated SSH session through IAP; no guest file or metadata key is intentionally changed.
Syntax explained
--tunnel-through-iap- Forces gcloud SSH to proxy TCP/22 through Identity-Aware Proxy instead of requiring an external IP.
Values stay on this page and are never sent or saved.
gcloud compute ssh {{vmName}} --zone={{zone}} --tunnel-through-iap --command='id && hostnamectl --static && sudo -n true; printf "sudo_rc=%s\n" "$?"'uid=2048123456_platform_operator gid=2048123456_platform_operator groups=... vm-ops-01 sudo: a password is required sudo_rc=1 IAP tunnel established External IP used: none
Checkpoint: Verify this layer before continuing
Continue whenApproved operator connects without a public IP or metadata key, receives the sudo boundary implied by its exact OS Login role, and a removed test principal cannot reconnect.
Stop whenStop if direct public SSH works, unauthorized user connects, metadata keys appear or ordinary operators receive unexpected sudo.
If this step fails
IAP connects but SSH returns Permission denied (publickey).
Likely causeOS Login role/POSIX profile is missing, guest policy is incompatible or 2FA requirements are unmet.
gcloud compute os-login describe-profilegcloud projects get-iam-policy {{projectId}} --format=json
ResolutionCorrect group membership and the narrow OS Login role, refresh the login profile and keep metadata keys disabled.
Security notes
- SSH usernames and group memberships are personal data. Limit logs and do not copy private keys or full user profiles into tickets.
Alternatives
- Use serial console only as a separately approved break-glass path with organization policy, audit and immediate revocation.
Stop conditions
- Stop if direct public SSH works, unauthorized user connects, metadata keys appear or ordinary operators receive unexpected sudo.
verification
Test workload IAM and network positive and negative paths
From the VM, use Application Default Credentials or the Google client library without displaying a token. Perform one harmless approved read and one unrelated denied read, then test application reachability from approved and unauthorized sources.
Why this step matters
A successful authorized operation proves metadata-server identity, access scope, IAM role, service perimeter, DNS and network path. A denied unrelated operation proves bounded scope. Network positive and negative tests prove the firewall target and source rules rather than merely their configuration.
What to understand
Do not call a token-printing command merely to prove identity; a token is a bearer credential even when terminal output is redirected imperfectly. Prefer the application SDK or a harmless service read and inspect only identity, expiry metadata and the service result.
Choose read-only fixtures with no customer data. When the target service supports policy troubleshooting, use it to explain denials rather than broadening permissions.
Test TCP/TLS/application semantics from an approved client and a controlled unauthorized source. A refused or timed-out connection should match firewall logs and expected listener state.
System changes
- No cloud data is modified; requests create audit records and firewall log entries.
Syntax explained
gcloud storage ls- Uses the VM's attached workload identity through the metadata server when no user credential or downloaded key is configured on the host.
Values stay on this page and are never sent or saved.
gcloud storage ls {{targetResource}} --limit=5gs://ops-backup-prod/manifests/manifest-2026-07-28.json gs://ops-backup-prod/manifests/manifest-2026-07-27.json Unrelated resource negative test: ERROR: (gcloud.storage.ls) HTTPError 403: sa-vm-ops-01@ops-prod-123456.iam.gserviceaccount.com does not have storage.objects.list access. Network: approved source PASS; unauthorized source DENIED
Checkpoint: Verify this layer before continuing
Continue whenApproved data read succeeds, unrelated read is denied, application source succeeds, unauthorized source fails and no credential value is logged.
Stop whenStop if unrelated data is accessible, a user key is required, token leaks or an unauthorized source reaches the service.
If this step fails
Approved API read fails with 403.
Likely causeIAM scope, role, propagation, service account, access scope, VPC Service Controls or resource policy is wrong.
gcloud projects get-iam-policy {{projectId}} --format=jsongcloud compute instances describe {{vmName}} --zone={{zone}} --format='yaml(serviceAccounts)'
ResolutionObtain a fresh token after bounded propagation, trace the exact denied permission and change only the resource-scoped role.
Security notes
- Never enable metadata concealment workarounds by proxying the metadata token to other hosts; protect SSRF paths in the application.
Alternatives
- Use Workload Identity Federation outside Compute Engine instead of exporting this VM service account credential.
Stop conditions
- Stop if unrelated data is accessible, a user key is required, token leaks or an unauthorized source reaches the service.
verification
Validate operations, patching, logs and recovery
Review Shielded integrity events, VM health, Ops Agent and application alerts. Create an approved crash-consistent or application-consistent snapshot, restore to an isolated disk or replacement VM and validate the application within RTO.
Why this step matters
Boot integrity, patch posture, guest monitoring and application recovery are ongoing controls, not creation flags. Shielded integrity changes require correlation with approved kernel/image updates. Serial output helps diagnose boot but may expose metadata. A snapshot or immutable rebuild must be tested with application semantics and external dependencies.
What to understand
Use OS Config patch management or an approved image-rebuild cadence with maintenance windows, reboot policy and post-change canaries. Monitor image support and rebuild rather than accumulating manual package drift.
For stateful workloads, quiesce the application or use its native backup before snapshots. Restore into an isolated network, validate checksums/schema/application behavior and never attach an untrusted disk to production first.
Alert on external IP creation, firewall changes, service-account key creation, broad IAM grants, Shielded integrity failures, logging gaps, VM health and application SLOs.
System changes
- Read commands do not change state; the operational drill may create a snapshot and isolated temporary recovery resources.
Syntax explained
get-shielded-identity- Retrieves Shielded VM identity material for attestation workflows; it is not a substitute for reviewing integrity events and guest health.
Values stay on this page and are never sent or saved.
gcloud compute instances get-shielded-identity {{vmName}} --zone={{zone}} && gcloud compute instances get-serial-port-output {{vmName}} --zone={{zone}} --port=1 --start=0 | tail -n 20Shielded instance identity retrieved. Secure Boot: enabled vTPM: enabled Integrity monitoring: enabled Guest startup: complete Ops Agent: healthy Critical alerts: 0 Latest isolated rebuild/restore: PASS Measured RTO: 00:21:54
Checkpoint: Verify this layer before continuing
Continue whenBoot and agent health are clean, patch/image review is current, alerts have owners and isolated rebuild/restore passes within RTO.
Stop whenStop on unexplained integrity change, unsupported image, critical patch gap, monitoring blind spot or failed recovery.
If this step fails
A restored snapshot boots but the application fails consistency checks.
Likely causeThe snapshot captured an unquiesced state or omitted dependent disks, databases, secrets, DNS or IAM bindings.
gcloud compute snapshots describe {{snapshotName}} --format=jsongcloud compute instances get-serial-port-output {{vmName}} --zone={{zone}} --port=1
ResolutionKeep the restore isolated, use application-native recovery, restore all dependencies and do not promote until integrity and semantic checks pass.
Security notes
- Serial output and recovery disks can contain secrets and personal data. Restrict access, redact exports and delete drill resources under retention policy.
Alternatives
- Prefer immutable Managed Instance Group replacement plus external managed data services when the application architecture permits.
Stop conditions
- Stop on unexplained integrity change, unsupported image, critical patch gap, monitoring blind spot or failed recovery.
verification
Capture release evidence and schedule access review
Record sanitized instance, IAM, firewall, route, OS Login, Shielded, logging, patch, alert and recovery evidence. Review access every 90 days and architecture/image support at least every 180 days.
Why this step matters
The release record establishes a known-good baseline and ownership. IAM inheritance, group membership, firewall policy, images, agents, routes and service retirements evolve. Scheduled review and automated drift detection keep the private VM from silently becoming public, over-privileged or unrecoverable.
What to understand
Review organization, folder, project and resource IAM together, including service-account impersonation and user-managed keys. Verify removed users cannot start new IAP/OS Login sessions.
Recheck external addresses, firewall and hierarchical policy, Cloud NAT/egress, flow-log sampling, image support, Shielded settings, disk encryption, snapshots, application SLO and recovery evidence.
System changes
- No resource state changes; creates governance evidence and recurring review work.
Syntax explained
--format=json- Produces structured evidence suitable for sanitization and policy assertions without depending on console layout.
Values stay on this page and are never sent or saved.
gcloud compute instances describe {{vmName}} --zone={{zone}} --format='json(name,status,networkInterfaces,serviceAccounts,shieldedInstanceConfig)' && gcloud compute firewall-rules list --filter='network:{{networkName}}' --format=jsonRelease checks External IP absent: PASS IAP + OS Login: PASS Shielded VM: PASS Firewall positive/negative: PASS Service account least privilege: PASS User-managed keys: 0 Patch and monitoring: PASS Recovery drill: PASS Next IAM review: 2026-10-26
Checkpoint: Verify this layer before continuing
Continue whenAll release gates pass, every exception has owner and expiry, and IAM/network/recovery reviews are scheduled.
Stop whenStop release if evidence is missing, a broad inherited grant exists, recovery is stale or exceptions lack expiry.
If this step fails
IAM review reveals the default Compute Engine service account has Editor.
Likely causeLegacy automatic grants or inherited basic roles remain in the project.
gcloud projects get-iam-policy {{projectId}} --format=jsongcloud iam service-accounts list
ResolutionRemove the basic binding through approved change, assign workload-specific identities and rerun allowed/denied tests.
Security notes
- Sanitize project numbers, principal IDs, private IPs, group membership and log excerpts before sharing evidence.
Alternatives
- Automate controls with Organization Policy, IAM recommender review, Security Command Center and CI policy checks after manual acceptance.
Stop conditions
- Stop release if evidence is missing, a broad inherited grant exists, recovery is stale or exceptions lack expiry.
Finish line
Verification checklist
gcloud compute instances describe {{vmName}} --zone={{zone}} --format='yaml(networkInterfaces,serviceAccounts,shieldedInstanceConfig)'No accessConfigs/external IP exists, dedicated service account is attached and Secure Boot, vTPM and integrity monitoring are enabled.gcloud compute ssh {{vmName}} --zone={{zone}} --tunnel-through-iap --command='id'Approved operator connects through IAP as the expected OS Login account, direct public SSH fails and removed test access cannot reconnect.gcloud compute firewall-rules list --filter='network:{{networkName}}' --format='table(name,direction,priority,sourceRanges,allowed,targetServiceAccounts)'IAP is the only SSH source, application ingress is narrow, target identity is exact and unauthorized-source tests are denied.gcloud projects get-iam-policy {{projectId}} --format=jsonThe VM service account has only the approved resource data role, has no user-managed keys and passes allowed plus denied operation tests.gcloud compute instances get-shielded-identity {{vmName}} --zone={{zone}}Integrity, patch/image, monitoring and application checks pass and the latest isolated rebuild or restore meets RTO.Recovery guidance
Common problems and safe checks
gcloud targets the wrong project or account.
Likely causeA named configuration, environment variable or cached account overrides expected context.
gcloud config listgcloud auth list
ResolutionActivate or create an approved named configuration, set the exact project and repeat every preview/check.
Instance creation reports insufficient quota or unavailable resources.
Likely causeRegional CPU quota, zonal capacity, machine-family policy or image/feature compatibility blocks creation.
gcloud compute regions describe {{region}}gcloud compute machine-types describe {{machineType}} --zone {{zone}}
ResolutionRequest quota or select an approved compatible zone/type; do not silently change data residency or drop security controls.
IAP SSH times out.
Likely causeFirewall does not permit 35.235.240.0/20 to TCP/22, IAP role is missing, target identity does not match, or sshd/route is unhealthy.
gcloud compute firewall-rules list --filter='network:{{networkName}}' --format='table(name,direction,priority,sourceRanges,allowed,targetServiceAccounts)'
ResolutionTrace IAP authorization, firewall target, route and guest service; do not add an external IP as the first fix.
OS Login says permission denied.
Likely causeOS Login metadata, OS Login role, instance access permission, POSIX profile or 2FA requirement is incomplete.
gcloud compute project-info describe --format='yaml(commonInstanceMetadata.items)'gcloud compute os-login describe-profile
ResolutionCorrect the exact OS Login/IAP role and identity profile, refresh credentials and avoid adding metadata SSH keys.
A former operator can still connect.
Likely causeAn inherited IAM group, instance-level binding, cached key/session or metadata-based access remains.
gcloud projects get-iam-policy {{projectId}} --format=jsongcloud compute instances describe {{vmName}} --zone {{zone}} --format='yaml(metadata)'
ResolutionRemove inherited membership or binding, invalidate the documented access path, inspect audit logs and verify metadata keys are not active.
The application port is unreachable from the approved source.
Likely causeFirewall priority, target identity, hierarchical rule, route, host firewall or listener binding denies traffic.
gcloud compute firewall-rules list --filter='network:{{networkName}}' --format=jsongcloud compute routes list --filter='network:{{networkName}}'
ResolutionIdentify the exact layer, correct the narrow rule/listener and repeat positive plus negative tests.
An unauthorized source reaches the VM.
Likely causeA broad higher-priority rule, legacy default rule, proxy/load balancer path or hierarchical policy permits it.
gcloud compute firewall-rules list --format='table(name,network,direction,priority,sourceRanges,allowed,targetTags,targetServiceAccounts)'
ResolutionDisable the broad path through reviewed policy, inspect firewall/audit logs and rerun unauthorized-source tests.
The VM service account receives PERMISSION_DENIED.
Likely causeThe target role or scope is wrong, IAM has not propagated, access scope is restrictive, or a service perimeter/resource policy blocks access.
gcloud projects get-iam-policy {{projectId}} --flatten='bindings[].members' --filter='bindings.members:serviceAccount:' --format=table
ResolutionRefresh the token after bounded propagation and correct only the narrow role/scope; do not grant Editor.
The service account accesses unrelated resources.
Likely causeProject/folder/organization inheritance, basic roles, broad custom roles or impersonation grants exceed the design.
gcloud projects get-iam-policy {{projectId}} --format=json
ResolutionRemove broad binding, split the identity and add allowed/denied integration tests before resuming.
Shielded VM integrity reports a changed baseline.
Likely causeA legitimate kernel/boot update, image change or unauthorized boot-chain modification changed measured state.
gcloud compute instances describe {{vmName}} --zone {{zone}} --format='yaml(shieldedInstanceConfig,shieldedInstanceIntegrityPolicy)'
ResolutionCorrelate with approved image and patch events; isolate and rebuild from trusted artifacts when change cannot be explained.
Secure Boot blocks an expected kernel module.
Likely causeThe module is unsigned or incompatible with the trusted image boot policy.
gcloud compute instances get-serial-port-output {{vmName}} --zone {{zone}} --port=1
ResolutionUse a signed supported module or rebuild the image; disable Secure Boot only through a narrow, time-bound exception.
CMEK-protected disk cannot attach or start.
Likely causeThe key/version is disabled, IAM grant is missing, location mismatches or the key project is inaccessible.
gcloud kms keys versions list --key=<key> --keyring=<ring> --location=<location>gcloud compute disks describe <disk> --zone {{zone}} --format=json
ResolutionRestore key availability and the Compute Engine service-agent grant under key-owner approval; do not create an unmanaged replacement key.
A snapshot restores but the application is inconsistent.
Likely causeThe snapshot was crash-consistent while application buffers, transactions or dependent services were not quiesced.
gcloud compute snapshots describe {{snapshotName}} --format=json
ResolutionUse application-native backup/quiescence, restore all required components into isolation and validate application semantics before production use.
Recovery
Rollback
Remove the instance from traffic, preserve sanitized evidence, revoke or narrow IAM, restore the last reviewed firewall and configuration, and prefer immutable replacement plus isolated data restore. Do not delete the project or encryption key as a rollback.
- Remove the VM from application backends or DNS without opening an alternative public path.
- Preserve audit logs, firewall logs, instance image and Shielded state, serial output, effective IAM, service-account key inventory and recovery evidence.
- Remove the workload IAM binding and human IAP/OS Login binding when compromise or over-privilege is suspected; inspect inherited groups and active sessions.
- Apply the last reviewed firewall/IAM/IaC state and repeat positive and negative access tests.
- For boot or guest drift, create an isolated replacement from the last trusted image and configuration, then restore application data and validate it.
- Do not delete the project, KMS key, snapshots or original disks until owners, retention, dependencies and recovery evidence are complete.
- Before returning traffic, verify no external IP, IAP/OS Login, Shielded controls, narrow workload IAM, firewall, patches, monitoring and application SLO.
Evidence