Back to Checks
azure

Virtual Machine has Just-in-Time (JIT) access enabled

vm_jit_access_enabled
Service: vmSeverity: medium
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:microsoft.compute/virtualmachines

Azure virtual machines are associated with a Just-in-Time (JIT) network access policy that opens management ports only for approved, time-bound requests from specified source IPs.

Risk

Without JIT, management ports like 22/3389 may stay reachable, enabling:

  • brute-force and password-spray attempts
  • exploitation of remote access flaws or stolen keys This threatens confidentiality (data exfiltration), integrity (unauthorized changes), and availability (service disruption).

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks vm_jit_access_enabled

Recommendation

Enable JIT network access and apply least privilege and zero trust:

  • keep admin ports closed by default
  • approve only specific IPs, minimal ports (e.g., 22, 3389), and short windows
  • favor private access (VPN, Bastion)
  • layer controls (defense in depth) and audit access requests

Remediation

CLI

az rest --method PUT --url "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Security/locations/<LOCATION>/jitNetworkAccessPolicies/default?api-version=2020-01-01" --body '{"kind":"Basic","properties":{"virtualMachines":[{"id":"/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.Compute/virtualMachines/<VM_NAME>","ports":[{"number":22,"protocol":"*","allowedSourceAddressPrefix":["*"],"maxRequestAccessDuration":"PT3H"}]}]}}'

Terraform

# Enable JIT by creating a Security Center JIT policy for the VM
resource "azurerm_security_center_jit_network_access_policy" "<example_resource_name>" {
  name                = "default"
  location            = "<LOCATION>"
  resource_group_name = "<example_resource_name>"

  virtual_machines {
    id = "<example_resource_id>" # Critical: VM ID included in the JIT policy enables JIT for this VM

    ports {
      number                           = 22
      protocol                         = "*"
      allowed_source_address_prefixes   = ["*"]
      max_request_access_duration       = "PT3H" # Critical: Minimal port config required by JIT
    }
  }
}

NativeIaC

// Bicep: Enable JIT for a VM by creating a JIT policy that references the VM
param location string = "<LOCATION>"
param vmId string = "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<example_resource_name>/providers/Microsoft.Compute/virtualMachines/<example_resource_name>"

resource jit 'Microsoft.Security/locations/jitNetworkAccessPolicies@2020-01-01' = {
  name: '${location}/default'
  properties: {
    virtualMachines: [
      {
        id: vmId // Critical: Adding the VM ID enables JIT for this VM
        ports: [
          {
            number: 22
            protocol: '*'
            allowedSourceAddressPrefix: ['*']
            maxRequestAccessDuration: 'PT3H' // Critical: Minimal required port configuration for JIT
          }
        ]
      }
    ]
  }
}

Other

1In the Azure portal, go to Microsoft Defender for Cloud
2Select Workload protections > Just-in-time VM access
3Open the Not configured tab, select the VM, and click Enable JIT on VMs
4Keep the default port (22 for Linux or 3389 for Windows) and click Save

Check Code

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


class vm_jit_access_enabled(Check):
    """
    Ensure that Microsoft Azure virtual machines are configured to use Just-in-Time (JIT) access.

    This check evaluates whether JIT access is enabled for each VM to reduce the attack surface.
    - PASS: VM has JIT access enabled.
    - FAIL: VM does not have JIT access enabled.
    """

    def execute(self):
        findings = []
        jit_enabled_vms = set()
        for subscription_id, vms in vm_client.virtual_machines.items():
            subscription_name = defender_client.subscriptions.get(
                subscription_id, subscription_id
            )
            for jit_policy in defender_client.jit_policies[subscription_id].values():
                jit_enabled_vms.update(jit_policy.vm_ids)
            for vm in vms.values():
                report = Check_Report_Azure(metadata=self.metadata(), resource=vm)
                report.subscription = subscription_id
                if vm.resource_id.lower() in {
                    vm_id.lower() for vm_id in jit_enabled_vms
                }:
                    report.status = "PASS"
                    report.status_extended = f"VM {vm.resource_name} in subscription {subscription_name} ({subscription_id}) has JIT (Just-in-Time) access enabled."
                else:
                    report.status = "FAIL"
                    report.status_extended = f"VM {vm.resource_name} in subscription {subscription_name} ({subscription_id}) does not have JIT (Just-in-Time) access enabled."
                findings.append(report)
        return findings