Skip to main content
emnode
Compliance High severity MCSB NS-1

Microsoft Defender for Cloud · Azure Virtual Machines

Machines should have ports closed that might expose attack vectors

Written and reviewed by Emnode · Last reviewed

What does the recommendation "Machines should have ports closed that might expose attack vectors" check?

Flags any Microsoft.Compute/virtualMachines instance where Defender for Cloud has identified inbound ports that present a known attack vector, based on the network exposure assessment behind this recommendation. The match is driven by the Defender assessment status, not a live external scan, so it reflects effective reachability through the network security group and Azure Firewall rules rather than which application happens to be listening. It does not cover the security of the service behind the port (a patched, well-configured SSH daemon still flags if the port is broadly reachable), and it is separate from the just-in-time 'Management ports should be closed' recommendation, which targets only RDP and SSH. This policy is currently in Preview and evaluates with effect AuditIfNotExists.

Why does "Machines should have ports closed that might expose attack vectors" matter?

An open inbound port is the first thing an attacker enumerates: brute-force against management ports, exploitation of an exposed database or admin panel, and lateral movement all start with a reachable port. Because the assessment weighs ports that genuinely expose an attack vector, a flag here usually means a real, internet-facing or over-broadly-permitted entry point rather than a theoretical one. Left open, a single compromised VM becomes a foothold into the rest of the subscription, and the business consequence is the familiar one: data theft, ransomware staging, or a regulator asking why a production host accepted connections from any source.

How do I fix "Machines should have ports closed that might expose attack vectors"?

  1. Review the flagged ports in the Defender for Cloud recommendation and confirm which are genuinely required; close the rest by tightening the network security group. Add an explicit deny rule with: az network nsg rule create --resource-group <rg> --nsg-name <nsg> --name deny-attack-vector-port --priority 4000 --direction Inbound --access Deny --protocol '*' --source-address-prefixes '*' --destination-port-ranges <port>.
  2. For ports that must stay reachable, restrict the source instead of allowing Any: scope the rule to known address prefixes or front the service with Azure Firewall, and enable just-in-time access for RDP and SSH so management ports open only on request.
  3. Prevent regressions by assigning the built-in policy at audit scope so new VMs are evaluated automatically. Look up the definition by its exact display name rather than hardcoding a GUID: pid=$(az policy definition list --query "[?displayName=='[Preview]: Machines should have ports closed that might expose attack vectors'].name" -o tsv); az policy assignment create --name vm-ports-closed --policy "$pid" --scope <scope>.

Remediation script · bash

# 1. Close the highest-impact exposure first: delete any rule that
#    allows a management port from the whole internet.
for rule in $(az network nsg rule list -g prod-rg --nsg-name prod-nsg \
    --query "[?access=='Allow' && (sourceAddressPrefix=='*' || sourceAddressPrefix=='Internet') && (destinationPortRange=='3389' || destinationPortRange=='22')].name" -o tsv); do
  az network nsg rule delete -g prod-rg --nsg-name prod-nsg -n "$rule"
  echo "$rule: open management-port rule removed"
done

# 2. Add an explicit deny on the management ports as a backstop.
az network nsg rule create -g prod-rg --nsg-name prod-nsg \
  --name deny-mgmt-ports --priority 4000 --access Deny --direction Inbound \
  --protocol Tcp --source-address-prefixes Internet \
  --destination-port-ranges 22 3389

# 3. Gate the ports you still need behind just-in-time access.
#    JIT is configured via PowerShell or the portal; request access with the CLI:
az security jit-policy list -o table   # confirm the JIT policy is in place

# 4. Ratchet it shut: audit any VM left without an NSG (Defender built-in policy).
az policy assignment create \
  --name audit-internet-facing-nsg \
  --policy f6de0be7-9a8a-4b8a-b349-43cf02d22f7c \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Full walkthrough (console steps, edge cases and verification) in the lesson Restrict virtual machine network exposure.

Is "Machines should have ports closed that might expose attack vectors" a false positive?

A purpose-built bastion or jump host that deliberately accepts inbound management traffic, but only from a locked-down source such as a corporate IP range or Azure Bastion, can still flag because the assessment sees the port as open. Where the source is genuinely constrained and the host exists to be that controlled entry point, this is a defensible exception: document the source restriction and exempt the resource rather than removing the rule that the architecture depends on.