This check flags Compute Engine VMs where OS Login is enabled but two-factor authentication is not enforced, leaving SSH access protected by SSH keys alone. Set the enable-oslogin-2fa metadata key to TRUE at the project or instance level and back it with org policy to require it everywhere.
SSH access to your VMs is one of the highest-value targets an attacker can reach. If a single private key leaks from a laptop, a CI runner, or a misconfigured secrets store, anyone holding it can log into your instances. OS Login two-factor authentication closes that gap by requiring a second factor on top of the key. This check, compute_oslogin2fa, looks for Compute Engine VMs that have OS Login turned on but have not enforced 2FA.
What this check detects
OS Login ties SSH access on your GCP VMs to IAM identities instead of manually managed SSH key files. When OS Login is enabled, login is governed by IAM roles like roles/compute.osLogin and roles/compute.osAdminLogin, and Google manages the underlying key distribution.
OS Login 2FA is a separate, additional control. When you enable it, a user logging in over SSH must complete a second authentication factor (such as a Google Authenticator code, a security key, or a phone prompt) in addition to presenting their key. The Lensix check passes when a VM has OS Login 2FA enabled and fails when OS Login is on but 2FA is not.
Note: OS Login 2FA only applies to identities that authenticate interactively. Service accounts cannot complete a 2FA challenge, so they are exempt. This is by design, and you control service account SSH access through IAM and short-lived credentials instead.
The relevant configuration lives in metadata. Both of these keys matter:
enable-osloginset toTRUEturns on OS Login.enable-oslogin-2faset toTRUEenforces the second factor.
Metadata can be set on the project (applies to all VMs) or on an individual instance (overrides the project value).
Why it matters
SSH keys are bearer credentials. Whoever has the private key gets in, and keys do not expire on their own. In practice they end up copied into more places than anyone tracks: developer laptops, shared bastion hosts, automation scripts, and chat messages. A stolen key gives an attacker a quiet, persistent foothold.
Consider a realistic chain of events. A developer's machine is compromised through a malicious npm package. The attacker scrapes ~/.ssh, finds a private key that OS Login has authorized, and now has the same SSH access the developer had. With OS Login alone, the attacker logs straight into production. With OS Login 2FA enforced, the stolen key is not enough, because the login prompt also demands a code the attacker does not have.
The same logic applies to insider risk and to keys that leak through git history or public storage buckets. 2FA turns a single stolen secret into something that is no longer sufficient on its own.
Warning: If your VMs host customer data and you fall under SOC 2, ISO 27001, or PCI DSS, weak access controls on production hosts are a common audit finding. Requiring multi-factor authentication for administrative access is an explicit expectation in several of these frameworks.
How to fix it
You can enable OS Login 2FA at three levels. Pick the broadest one that fits your environment, since project-wide enforcement is harder to accidentally bypass than per-instance settings.
Option 1: Enable at the project level (recommended)
This applies to every VM in the project that does not explicitly override it. First confirm OS Login itself is enabled, then add the 2FA key:
gcloud compute project-info add-metadata \
--metadata enable-oslogin=TRUE,enable-oslogin-2fa=TRUE
Warning: Enabling 2FA affects active SSH workflows. Before rolling this out broadly, make sure every human who needs SSH access has registered a second factor in their Google account. Otherwise they will be locked out of their VMs on the next login.
Option 2: Enable on a single instance
Use this when you need to enforce 2FA on specific hosts without changing project-wide behavior:
gcloud compute instances add-metadata INSTANCE_NAME \
--zone ZONE \
--metadata enable-oslogin=TRUE,enable-oslogin-2fa=TRUE
An instance-level setting overrides the project value, so you can also use this to force 2FA on a sensitive VM in a project that has not enabled it globally.
Option 3: Set it in Terraform
If you manage VMs as code, bake the metadata into the resource so the configuration cannot drift back:
resource "google_compute_instance" "app" {
name = "app-server"
machine_type = "e2-medium"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
network = "default"
}
metadata = {
enable-oslogin = "TRUE"
enable-oslogin-2fa = "TRUE"
}
}
To apply it across all VMs in a project at once, set it as project metadata instead:
resource "google_compute_project_metadata" "default" {
metadata = {
enable-oslogin = "TRUE"
enable-oslogin-2fa = "TRUE"
}
}
Verify the change
Confirm the metadata is in place on the instance:
gcloud compute instances describe INSTANCE_NAME \
--zone ZONE \
--format="value(metadata.items)"
You should see both enable-oslogin and enable-oslogin-2fa set to TRUE. Then test an SSH session and confirm you are prompted for a second factor.
How to prevent it from happening again
Fixing one VM is easy. Keeping the whole fleet compliant takes enforcement that does not depend on people remembering metadata keys.
Use an organization policy constraint
GCP provides a built-in org policy that requires OS Login across an organization, folder, or project. Apply it so new VMs inherit OS Login automatically:
gcloud resource-manager org-policies enable-enforce \
compute.requireOsLogin \
--organization ORGANIZATION_ID
Note: The compute.requireOsLogin constraint enforces OS Login but does not by itself enforce 2FA. Pair it with project or organization metadata that sets enable-oslogin-2fa=TRUE so both controls are guaranteed.
Gate it in CI/CD with policy-as-code
If you provision infrastructure through Terraform, block merges that ship VMs without 2FA. A Conftest or OPA policy run against your plan catches the gap before it reaches the cloud:
deny[msg] {
resource := input.resource_changes[_]
resource.type == "google_compute_instance"
metadata := resource.change.after.metadata
metadata["enable-oslogin-2fa"] != "TRUE"
msg := sprintf("VM %s must set enable-oslogin-2fa=TRUE", [resource.name])
}
Tip: Run this policy in a pull request check so the feedback reaches engineers at review time, not after a deploy. Catching the misconfiguration in code is far cheaper than chasing it down across a running fleet later.
Monitor continuously
Org policies and CI gates cover the resources that flow through your pipelines, but VMs created by hand, by older automation, or in shadow projects can slip past them. Continuous scanning with Lensix catches those drift cases and re-flags any VM where 2FA is missing, so the gap shows up on a dashboard instead of in an incident report.
Best practices
- Prefer OS Login over manual SSH keys everywhere. Manual key management scales poorly and leaves orphaned keys behind. OS Login ties access to IAM, which you already audit.
- Enforce 2FA at the project or org level, not per instance. Broad enforcement removes the chance that a new VM is created without it.
- Use security keys where you can. Hardware security keys resist phishing in ways that TOTP codes do not, and OS Login supports them.
- Keep service account access tight. Since service accounts skip 2FA, grant them the minimum SSH access they need and rotate their credentials with short lifetimes.
- Reduce SSH exposure overall. Combine OS Login 2FA with IAP-based TCP forwarding so VMs do not need public IPs or open port 22 to the internet.
- Audit login roles regularly. Review who holds
roles/compute.osLoginandroles/compute.osAdminLoginand remove access that is no longer needed.
OS Login 2FA is a small metadata change with an outsized payoff. It converts your SSH access from a single-secret model into one where a leaked key alone is not enough to get in. Set it broadly, enforce it in policy, and keep an eye on drift, and SSH stops being the soft spot in your VM security.

