This check flags Compute Engine VMs running without Shielded VM Secure Boot, which leaves the boot process open to rootkits and unsigned bootloaders. Recreate the instance (or update a stopped one) with --shielded-secure-boot to enforce signed, verified boot components.
Secure Boot is one of those settings that costs nothing, adds no measurable latency, and quietly closes off an entire class of low-level attacks. Yet it ships disabled by default on most Compute Engine images and machine families, so plenty of fleets run without it for years. The VM Secure Boot Not Enabled check catches exactly that gap.
Below is what the check looks for, why an unprotected boot chain is worth caring about, and how to fix it across the console, gcloud, and Terraform.
What this check detects
The check inspects each Compute Engine instance and reports any VM where Shielded VM Secure Boot is turned off. Specifically, it looks at the instance's shieldedInstanceConfig and flags instances where enableSecureBoot is false or absent.
Shielded VM is a bundle of three boot-integrity features:
- Secure Boot — ensures only signed, trusted bootloaders and kernels run at startup.
- Virtual Trusted Platform Module (vTPM) — provides a hardware-rooted store for keys and supports measured boot.
- Integrity Monitoring — compares the boot measurements against a known-good baseline and reports drift.
This particular check is scoped to Secure Boot. The other two are valuable and often enabled together, but Secure Boot is the one doing the work of rejecting unauthorized boot components before the OS ever loads.
Note: Secure Boot relies on UEFI firmware. Older or custom images that boot in legacy BIOS mode cannot use it. If a VM was created from a non-UEFI image, you will need a UEFI-compatible image before Secure Boot can be enabled.
Why it matters
The boot sequence is the most privileged code that runs on a machine. Anything that executes before or alongside the kernel sits below the operating system's own defenses, which means it can hide from endpoint agents, antivirus, and most logging. Attackers know this, and bootkits and kernel rootkits are a well-established way to maintain persistence after an initial compromise.
Without Secure Boot, a VM will happily run a modified or unsigned bootloader. Picture this chain of events:
- An attacker gains root on a VM through an application vulnerability or a leaked SSH key.
- They install a malicious kernel module or replace the bootloader to survive reboots and image rebuilds.
- Because nothing verifies boot integrity, the tampered components load every time the instance starts.
- The compromise persists even after you patch the original entry point, and it stays invisible to host-level tooling.
Secure Boot breaks that chain. If a boot component is not signed by a trusted key, the VM refuses to boot it. That turns a stealthy, persistent compromise into a noisy failure you can actually see.
Warning: Compliance frameworks increasingly expect boot integrity controls. CIS Google Cloud Platform Foundations Benchmark recommends enabling Shielded VM on all instances, so a fleet of non-shielded VMs will show up as findings in audits and in tools mapped to those benchmarks.
How to fix it
Secure Boot can only be changed while a VM is stopped. For most workloads that means a brief restart window. New instances should set it at creation time.
Option 1: Enable on an existing VM (gcloud)
Warning: This requires stopping the instance, which causes downtime for anything running on it. Plan a maintenance window and drain traffic first. Confirm the image is UEFI-compatible, or the VM may fail to boot afterward.
# Stop the instance
gcloud compute instances stop INSTANCE_NAME \
--zone=ZONE
# Enable Secure Boot (and optionally vTPM + integrity monitoring)
gcloud compute instances update INSTANCE_NAME \
--zone=ZONE \
--shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring
# Start it back up
gcloud compute instances start INSTANCE_NAME \
--zone=ZONE
After the instance is back, confirm the setting took effect:
gcloud compute instances describe INSTANCE_NAME \
--zone=ZONE \
--format="value(shieldedInstanceConfig.enableSecureBoot)"
# Expected output: True
Option 2: Enable on a new VM (gcloud)
gcloud compute instances create INSTANCE_NAME \
--zone=ZONE \
--image-family=debian-12 \
--image-project=debian-cloud \
--shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring
Option 3: Google Cloud Console
- Go to Compute Engine > VM instances and click the instance name.
- Click Stop and wait for the instance to fully stop.
- Click Edit.
- Under Shielded VM, toggle Turn on Secure Boot (and vTPM / Integrity monitoring if not already on).
- Click Save, then Start the instance.
Option 4: Terraform
For instances managed as code, add a shielded_instance_config block:
resource "google_compute_instance" "app" {
name = "app-vm"
machine_type = "e2-medium"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
shielded_instance_config {
enable_secure_boot = true
enable_vtpm = true
enable_integrity_monitoring = true
}
network_interface {
network = "default"
}
}
Tip: Changing shielded_instance_config on an existing Terraform-managed instance may trigger a stop/start during apply. Run terraform plan first to confirm whether the change is in-place or forces replacement, and schedule accordingly.
How to prevent it from happening again
Fixing one VM is easy. Keeping the whole fleet compliant takes a guardrail. Use a combination of org policy, IaC review, and continuous scanning.
Enforce with an Organization Policy
Google Cloud has a built-in constraint that requires Shielded VM on every new instance. Apply it at the organization or folder level so nobody can launch a non-shielded VM in the first place:
gcloud resource-manager org-policies enable-enforce \
constraints/compute.requireShieldedVm \
--organization=ORGANIZATION_ID
Note: requireShieldedVm enforces that the Shielded VM config is present and Secure Boot plus vTPM are enabled. Roll it out to a test folder first, since any existing automation that creates plain VMs will start failing once it is on.
Gate it in CI/CD with policy-as-code
Catch non-compliant Terraform before it ever reaches an account. A simple OPA/Conftest rule against a plan or HCL works well:
package main
deny[msg] {
resource := input.resource.google_compute_instance[name]
not resource.shielded_instance_config.enable_secure_boot
msg := sprintf("Instance '%s' must enable Secure Boot", [name])
}
Wire that into a pull request check so the pipeline fails when someone adds an instance without Secure Boot. Combined with the org policy, you get defense at both the code layer and the platform layer.
Scan continuously
Org policy stops new violations, but it does not retroactively fix the VMs you already have. Run a recurring scan (Lensix runs this check on a schedule) so existing non-shielded instances surface and get remediated over time.
Best practices
- Enable all three Shielded VM features together. Secure Boot blocks bad boot code, vTPM anchors trust in hardware, and integrity monitoring tells you when boot measurements drift. They are most useful as a set.
- Bake it into base images and templates. Set Shielded VM config in your instance templates, MIG configs, and golden images so every workload inherits it without anyone remembering to flip a switch.
- Validate image compatibility early. Standard Google-provided images for Debian, Ubuntu, RHEL, and Windows support Shielded VM. If you build custom images, confirm they boot in UEFI mode before enforcing the constraint.
- Watch for integrity monitoring alerts. Route the late-boot and early-boot validation results to Cloud Logging and alert on failures. A failed integrity check can be your earliest signal that a boot component changed unexpectedly.
- Treat exceptions explicitly. If a legacy workload genuinely cannot use Secure Boot, document the exception, scope it to a specific project or folder, and revisit it on a schedule rather than leaving the whole fleet open.
Secure Boot is cheap insurance against expensive, hard-to-detect compromises. Turn it on by default, enforce it with org policy, and let your scanners mop up whatever predates the rule.

