Back to Checks
Network security group does not allow inbound SSH (TCP port 22) from the Internet
network_ssh_internet_access_restricted
Service: networkSeverity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:microsoft.network/networksecuritygroups
Azure NSG inbound rules that allow SSH on TCP 22 from 0.0.0.0/0, Internet, or * are identified, including rules where port ranges include 22 and protocol is TCP or *.
Indicates NSGs exposing SSH to the Internet.
Risk
Public SSH access weakens confidentiality and integrity. Open 22 invites brute force and key theft, enabling remote shell control, persistence, and lateral movement. Attackers can pivot into VNets, exfiltrate data, deploy crypto-miners, and impact availability.
Run this check with Prowler
Run in Prowler CloudRun
prowler azure --checks network_ssh_internet_access_restrictedRecommendation
Apply least privilege on SSH:
- Remove public rules to
TCP 22from0.0.0.0/0 - Allowlist specific admin IPs or management subnets
- Prefer Azure Bastion, JIT access, or VPN/ExpressRoute for admin
- Use key-based auth, disable passwords, and remove unnecessary public IPs
Adopt defense in depth with logging and periodic reviews.
Remediation
CLI
az network nsg rule delete --resource-group <RESOURCE_GROUP> --nsg-name <NSG_NAME> --name <RULE_NAME>Terraform
# Restrict SSH to a specific source so port 22 is not open to the Internet
resource "azurerm_network_security_rule" "<example_resource_name>" {
name = "<example_rule_name>"
resource_group_name = "<example_resource_name>"
network_security_group_name = "<example_resource_name>"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "<ALLOWED_CIDR>" # CRITICAL: restrict SSH source; not Internet/*/0.0.0.0/0
destination_address_prefix = "*"
}NativeIaC
// NSG allowing SSH only from a specific source (not the Internet)
resource <example_resource_name> 'Microsoft.Network/networkSecurityGroups@2023-09-01' = {
name: '<example_resource_name>'
location: '<location>'
properties: {
securityRules: [
{
name: '<example_rule_name>'
properties: {
priority: 100
direction: 'Inbound'
access: 'Allow'
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '22'
sourceAddressPrefix: '<ALLOWED_CIDR>' // CRITICAL: restrict SSH source; not Internet/*/0.0.0.0/0
destinationAddressPrefix: '*'
}
}
]
}
}Other
1In Azure Portal, go to Network security groups and open <NSG_NAME>
2Select Inbound security rules
3Find any rule that allows TCP 22 from Internet/Any/0.0.0.0/0
4Delete the rule, or Edit it and set Source to IP Addresses with only your allowed CIDR(s)
5Save
Check Code
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.network.network_client import network_client
class network_ssh_internet_access_restricted(Check):
def execute(self) -> Check_Report_Azure:
findings = []
for subscription, security_groups in network_client.security_groups.items():
subscription_name = network_client.subscriptions.get(
subscription, subscription
)
for security_group in security_groups:
report = Check_Report_Azure(
metadata=self.metadata(), resource=security_group
)
report.subscription = subscription
report.status = "PASS"
report.status_extended = f"Security Group {security_group.name} from subscription {subscription_name} ({subscription}) has SSH internet access restricted."
rule_fail_condition = any(
(
rule.destination_port_range == "22"
or (
(
rule.destination_port_range
and "-" in rule.destination_port_range
)
and int(rule.destination_port_range.split("-")[0]) <= 22
and int(rule.destination_port_range.split("-")[1]) >= 22
)
)
and rule.protocol in ["TCP", "Tcp", "*"]
and rule.source_address_prefix in ["Internet", "*", "0.0.0.0/0"]
and rule.access == "Allow"
and rule.direction == "Inbound"
for rule in security_group.security_rules
)
if rule_fail_condition:
report.status = "FAIL"
report.status_extended = f"Security Group {security_group.name} from subscription {subscription_name} ({subscription}) has SSH internet access allowed."
findings.append(report)
return findingsReferences
- https://www.trendmicro.com/cloudoneconformity/knowledge-base/azure/Network/unrestricted-ssh-access.html
- https://learn.microsoft.com/en-us/azure/security/fundamentals/network-best-practices#disable-rdpssh-access-to-azure-virtual-machines
- https://learn.microsoft.com/en-us/security/benchmark/azure/security-controls-v3-network-security#ns-1-establish-network-segmentation-boundaries