Location>code7788 >text

Azure Policy] Add a policy to audit Azure Network Security Group (NSG) rules -- Only specific IP addresses can be allowed on port 3389/22.

Popularity:863 ℃/2024-08-29 21:07:43

Description of the problem

For virtual machine resources on Azure, security management is required. Only specified IP addresses can be remote to the VMs via RDP/SSH, with the following considerations:

1) Using the Azure Policy service, scan all the Network Security Group (NSG: Network Security Group) resources in the subscription

2) Determine the inbound rules, determine whether it is port 3389, 22

3) Determine if the source address is a permitted IP

4) Audit NSG rules that do not meet the conditions. Tip Non-compliant ( Non-compliant )

How do you write rules that need to fulfill the above requirements?

 

Problem solving

Centralized control of Azure resources to meet compliance needs can be accomplished using Azure Policy. To fulfill the above requirements:

Step 1: Examine the NSG resources and check the attribute names corresponding to the Inbound, port, and source values.

On the NSG Overview page, click on the "JSON View" link in the upper right corner to view the JSON content of the resource, of which the content of securityRules is:

{
    "name": "RDP",
    "id": "/subscriptions/x-x-x-x/resourceGroups/xxxx/providers//networkSecurityGroups/xxxx-xxx/securityRules/RDP",
    "etag": "W/\"xxxxxxx\"",
    "type": "/networkSecurityGroups/securityRules",
    "properties": {
        "provisioningState": "Succeeded",
        "protocol": "TCP",
        "sourcePortRange": "*",
        "destinationPortRange": "3389",
        "sourceAddressPrefix": "167.220.0.0/16",
        "destinationAddressPrefix": "*",
        "access": "Allow",
        "priority": 300,
        "direction": "Inbound",
        "sourcePortRanges": [],
        "destinationPortRanges": [],
        "sourceAddressPrefixes": [],
        "destinationAddressPrefixes": []
    }
}

Among them:

  1. The resource type is type = /networkSecurityGroups/securityRules
  2. The inbound attribute is named direction
  3. The attribute for port 3389 is named destinationPortRange
  4. And the IP address attribute is named sourceAddressPrefix

They are, in fact, what make up a Policy Rule.

 

Step 2: Write the Policy Rule

The general framework of Policy is:

{
  "mode": "All",
  "policyRule": {
    "if": {
       // Conditions under which audits are required
//1: The type of resource is /networkSecurityGroups/securityRules 
       //2: Inbound rules Inbound
//3: Port is 3389 or 22
       //4: If not in the list of allowed IP addresses, auditing is required
    },
"then": {
      "effect": "audit"
    }
  },
  "parameters": {
     //Input parameters, in this case a list of allowed IP addresses
  }
}

First condition: the type of scanned resource is a security rule for the network security group

"type": "/networkSecurityGroups/securityRules"

Convert to a Policy statement:

{
  "field": "type",
  "equals": "/networkSecurityGroups/securityRules"
}

Second condition: the direction of the judgment rule is the inbound direction

"direction": "Inbound"

Convert to a Policy statement:

     {
            "field": "/networkSecurityGroups/securityRules/direction",
            "equals": "Inbound"
     }

The third condition: determine whether the port is 3389 or 22.

"destinationPortRange": "3389" or "destinationPortRange": "22"

Convert to a Policy statement:

        {
          "anyOf": [
            {
              "field": "/networkSecurityGroups/securityRules/destinationPortRange",
              "equals": "22"
            },
            {
              "field": "/networkSecurityGroups/securityRules/destinationPortRange",
              "equals": "3389"
            }
          ]
        }

The fourth condition: determine the IP address, whether it is not in the list of allowed

"sourceAddressPrefix": "167.220.0.0/16"

Convert to a Policy statement:

{
   "field": "/networkSecurityGroups/securityRules/sourceAddressPrefix",
    "notIn": "[parameters('allowedIPs')]"
 }

 

Step 3: Prepare parameters (allowed IP addresses as input parameters)

Since there should be more than one IP address allowed, it is prepared as an Array object, with the parameter name: allowedIPs.

The structure is as follows:

    "parameters": {
      "allowedIPs": {
        "type": "Array",
        "metadata": {
          "displayName": "Allowed IPs",
          "description": "The list of allowed IPs for resources."
        },
        "defaultValue": [
          "192.168.1.1",""
        ]
      }
    }

Full Policy example:

{
    "mode": "All",
    "policyRule": {
        "if": {
            "allOf": [
                {
                    "field": "type",
                    "equals": "/networkSecurityGroups/securityRules"
                },
                {
                    "field": "/networkSecurityGroups/securityRules/direction",
                    "equals": "Inbound"
                },
                {
                    "anyOf": [
                        {
                            "field": "/networkSecurityGroups/securityRules/destinationPortRange",
                            "equals": "22"
                        },
                        {
                            "field": "/networkSecurityGroups/securityRules/destinationPortRange",
                            "equals": "3389"
                        }
                    ]
                },
                {
                    "field": "/networkSecurityGroups/securityRules/sourceAddressPrefix",
                    "notIn": "[parameters('allowedIPs')]"
                }
            ]
        },
        "then": {
            "effect": "audit"
        }
    },
    "parameters": {
        "allowedIPs": {
            "type": "Array",
            "metadata": {
                "displayName": "Allowed IPs",
                "description": "The list of allowed IPs for resources."
            },
            "defaultValue": [
                "192.168.1.1",""
            ]
        }
    }
}

Final effect:

 

 

bibliography

Using arrays in conditions: /en-us/azure/governance/policy/how-to/author-policies-for-arrays#using-arrays-in-conditions
deny-nsg-inbound-allow-all: /Azure/azure-policy/blob/master/samples/Network/deny-nsg-inbound-allow-all/
Azure Policy definitions audit effect: /en-us/azure/governance/policy/concepts/effect-audit