Back to blog
Best PracticesCloud SecurityCompute & ContainersGCPIdentity & Access

VM OS Login Disabled: Securing Compute Engine SSH Access with IAM

Learn why disabling OS Login on Compute Engine VMs is risky, how to enable it with IAM-controlled SSH, and how to enforce it with org policies and CI/CD.

TL;DR

This check flags Compute Engine VMs that have OS Login disabled, which means SSH access falls back to manually managed metadata keys instead of centralized IAM control. Enable OS Login by setting the enable-oslogin metadata key to TRUE so SSH access is governed by IAM, audited in Cloud Logging, and revoked the moment an account is offboarded.

SSH key management is one of those problems that quietly rots over time. Someone adds a public key to a VM's metadata to debug an issue, the incident gets resolved, and the key stays there for the next three years. Multiply that across a fleet of instances and a few dozen engineers, and you end up with no real idea of who can log into what. OS Login fixes this by tying SSH access to Google Cloud IAM, and this check exists to make sure you are actually using it.


What this check detects

The compute_oslogin check inspects each Compute Engine instance and looks at the enable-oslogin metadata key. When that key is missing or set to FALSE at the instance level, the check fails.

With OS Login disabled, SSH access to the VM is controlled by SSH public keys stored in instance or project metadata. Google Cloud takes those keys, provisions matching Linux user accounts on the VM, and allows anyone holding the corresponding private key to connect. There is no link to IAM, no central audit trail of who has access, and no automatic cleanup when someone leaves the team.

Note: OS Login replaces the legacy metadata key workflow with an IAM-driven one. When enabled, Google manages Linux user accounts and SSH key pairs based on each user's Google identity and their IAM roles, rather than raw public keys pasted into metadata.


Why it matters

The core risk is that metadata-based SSH access decouples server login from your identity provider. That has a few concrete consequences.

Orphaned access after offboarding

When an engineer leaves, you revoke their IAM permissions and disable their Google account. But if their SSH public key is still sitting in a VM's metadata, that key continues to work. Anyone who has the private key, including the former employee, can still SSH in. With OS Login enabled, removing their IAM access removes their server access at the same time.

No centralized audit trail

Metadata SSH keys do not produce useful login records tied to a real identity. OS Login writes structured login events to Cloud Audit Logs, so you can answer questions like "who logged into this production database VM last Tuesday" without scraping auth.log across every host.

Weak control over privilege

With metadata keys, every key holder gets the same shell access, and sudo is typically all-or-nothing on the box. OS Login lets you grant roles/compute.osLogin for standard access and roles/compute.osAdminLogin for sudo access, so root privileges become an explicit IAM grant instead of a local file setting.

Warning: A common real-world failure mode is a service account or shared key copied into project-wide metadata. Because project metadata applies to every instance that does not block it, a single leaked key can grant an attacker shell access to your entire fleet at once.

Two-factor and security keys

OS Login supports requiring two-factor authentication and hardware security keys for SSH. Metadata-based access has no equivalent, so a stolen private key is all an attacker needs.


How to fix it

You can enable OS Login at the project level so it covers everything, or at the instance level for a single VM. Project level is almost always the right call.

Option 1: Enable OS Login project-wide (recommended)

Set the metadata key once on the project, and every instance inherits it unless it explicitly opts out.

gcloud compute project-info add-metadata \
  --metadata enable-oslogin=TRUE

Danger: Flipping this on project-wide immediately changes how SSH access is resolved across every VM. Any user relying on a metadata-based key who does not have roles/compute.osLogin will lose SSH access. Grant the required IAM roles before you enable it in production, or you may lock yourself out.

Option 2: Enable OS Login on a single instance

gcloud compute instances add-metadata INSTANCE_NAME \
  --zone ZONE \
  --metadata enable-oslogin=TRUE

Grant the IAM roles users need

Before or right after enabling OS Login, give your engineers the appropriate role. For standard, non-sudo access:

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='user:[email protected]' \
  --role='roles/compute.osLogin'

For administrators who need sudo on the VM:

gcloud projects add-iam-policy-binding PROJECT_ID \
  --member='user:[email protected]' \
  --role='roles/compute.osAdminLogin'

Users also need roles/iam.serviceAccountUser on the VM's attached service account, plus permission to reach the instance (for example through Identity-Aware Proxy if you are tunneling SSH).

Connect after enabling

Once OS Login is on, the normal SSH workflow keeps working and Google handles the key provisioning behind the scenes:

gcloud compute ssh INSTANCE_NAME --zone ZONE

Terraform example

If you manage infrastructure as code, set the metadata directly on the instance or use a project metadata resource.

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"
  }
}

To enforce it across the whole project in Terraform:

resource "google_compute_project_metadata_item" "oslogin" {
  key   = "enable-oslogin"
  value = "TRUE"
}

Tip: If you want hardware-backed SSH, add enable-oslogin-2fa=TRUE or enable-oslogin-sk=TRUE to the same metadata block. The security key option (-sk) forces users to authenticate with a registered hardware key, which kills the "stolen private key" attack outright.


How to prevent it from happening again

Fixing a VM by hand is fine for a one-off, but the metadata will drift right back without a guardrail. Push enforcement to the left.

Use an Organization Policy constraint

Google Cloud ships a managed constraint that requires OS Login on every new VM in scope. Apply it at the organization or folder level so new projects inherit it.

gcloud resource-manager org-policies enable-enforce \
  compute.requireOsLogin \
  --organization ORGANIZATION_ID

With this in place, attempts to create instances with OS Login disabled are rejected, and you do not have to chase down individual VMs.

Note: The compute.requireOsLogin constraint sets the project-level metadata for you and blocks instances from overriding it. It is the single most effective control for this check because it removes the option to disable OS Login rather than just detecting it afterward.

Gate it in CI/CD with policy-as-code

If your VMs are provisioned through Terraform, scan plans before they apply. A simple Conftest or OPA policy can reject any instance missing the metadata key.

package main

deny[msg] {
  resource := input.resource.google_compute_instance[name]
  not resource.metadata["enable-oslogin"] == "TRUE"
  msg := sprintf("Instance %q must set enable-oslogin = TRUE", [name])
}

Wire that into your pipeline so a non-compliant plan fails the build before anything reaches production.

Continuous monitoring

Org policies and CI gates cover the create path, but manual changes, imported resources, and exceptions still happen. Lensix runs the compute_oslogin check continuously so a VM that drifts out of compliance gets surfaced quickly instead of lingering until an audit finds it.


Best practices

  • Default to project-wide OS Login. Enabling it once at the project level, or better yet through an org policy, is far less error-prone than per-instance metadata.
  • Map IAM roles to real access needs. Use roles/compute.osLogin for routine access and reserve roles/compute.osAdminLogin for the small set of people who genuinely need sudo.
  • Combine OS Login with IAP for SSH. Identity-Aware Proxy lets you remove public IPs and open firewall rules entirely, so SSH traffic is brokered through Google's identity layer instead of the open internet.
  • Require 2FA or security keys for production. The marginal effort is small and it neutralizes credential theft as an attack path.
  • Purge legacy metadata keys. After migrating to OS Login, remove leftover ssh-keys entries from project and instance metadata so no stale access lingers.
  • Tie access reviews to offboarding. Because OS Login binds login to IAM, your existing joiner-mover-leaver process now covers server access for free. Make sure your offboarding checklist actually revokes the IAM roles.

OS Login is one of the rare security controls that makes daily operations easier rather than harder. Engineers keep using gcloud compute ssh exactly as before, while you gain a clean audit trail, centralized revocation, and the ability to enforce strong authentication. Turn it on, enforce it with an org policy, and watch the orphaned SSH keys disappear.