Back to Checks
azure

Linux Virtual Machine has password authentication disabled (SSH key authentication enforced)

vm_linux_enforce_ssh_authentication
Service: vmSeverity: high
OfficialBuilt-inVerified
Categories:identity-access
Resource Type:microsoft.compute/virtualmachines

Azure Linux virtual machines are assessed for SSH configuration where disablePasswordAuthentication is set to true, allowing only public key authentication and disallowing interactive passwords.

Risk

With password-based SSH, attackers can run brute-force or password-spray campaigns. A successful login grants remote shell, enabling command execution, data exfiltration, and lateral movement, degrading confidentiality and integrity.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks vm_linux_enforce_ssh_authentication

Recommendation

Enforce key-only SSH by setting disablePasswordAuthentication to true and disallowing OS password logins. Use strong, passphrase-protected keys with rotation; restrict SSH via NSGs and private access or Azure Bastion; enable JIT; and apply least privilege.

Remediation

Terraform

# Minimal Terraform to enforce SSH key authentication on a Linux VM
resource "azurerm_linux_virtual_machine" "<example_resource_name>" {
  name                = "<example_resource_name>"
  resource_group_name = "<example_resource_name>"
  location            = "<example_location>"
  size                = "Standard_B1s"
  network_interface_ids = ["<example_resource_id>"]
  admin_username        = "azureuser"

  disable_password_authentication = true  # CRITICAL: Disables password-based SSH; enforces SSH key authentication

  admin_ssh_key {                         # Required when password auth is disabled
    username   = "azureuser"
    public_key = "<example_public_key>"
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-focal"
    sku       = "20_04-lts"
    version   = "latest"
  }
}

NativeIaC

// Bicep snippet to enforce SSH key authentication on a Linux VM
resource linuxVm 'Microsoft.Compute/virtualMachines@2024-03-01' = {
  name: '<example_resource_name>'
  location: '<example_location>'
  properties: {
    osProfile: {
      linuxConfiguration: {
        disablePasswordAuthentication: true // CRITICAL: Disables password-based SSH; enforces SSH key authentication
      }
    }
  }
}

Other

1In Azure Portal, go to your Linux VM > Settings > Export template
2Click Edit template
3Find properties.osProfile.linuxConfiguration and set disablePasswordAuthentication to true
4Ensure an SSH public key is provided (adminPassword must be absent)
5Click Save, then Review + create to deploy the update

Check Code

from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.vm.vm_client import vm_client


class vm_linux_enforce_ssh_authentication(Check):
    """
    Ensure that Azure Linux-based virtual machines are configured to use SSH keys (password authentication is disabled).

    This check evaluates whether disablePasswordAuthentication is set to True for Linux VMs to ensure only SSH key authentication is allowed.
    - PASS: VM has password authentication disabled (SSH key authentication enforced).
    - FAIL: VM has password authentication enabled (password-based SSH allowed).
    """

    def execute(self) -> list[Check_Report_Azure]:
        findings = []
        for subscription_id, vms in vm_client.virtual_machines.items():
            subscription_name = vm_client.subscriptions.get(
                subscription_id, subscription_id
            )
            for vm in vms.values():
                if vm.linux_configuration:
                    report = Check_Report_Azure(metadata=self.metadata(), resource=vm)
                    report.subscription = subscription_id

                    if vm.linux_configuration.disable_password_authentication:
                        report.status = "PASS"
                        report.status_extended = f"VM {vm.resource_name} in subscription {subscription_name} ({subscription_id}) has password authentication disabled (SSH key authentication enforced)."
                    else:
                        report.status = "FAIL"
                        report.status_extended = f"VM {vm.resource_name} in subscription {subscription_name} ({subscription_id}) has password authentication enabled (password-based SSH allowed)."
                    findings.append(report)
        return findings