Reading Time: 3 minutes

So, recently I was working on a project where I had to deploy a new environment in Azure. This included deploying a Virtual Network (VNet) that was not going to be connected to the rest of the network and must be isolated. Virtual Machines (VMs) deployed here should also be accessible via Remote Desktop Protocol and Secure Shell (SSH). Thankfully Microsoft has a solution for this with Azure Bastion. To integrate Azure Bastion with your VNet, you need to have a dedicated subnet called AzureBastionSubnet (no variations on the name are supported) with at least a /26 address space. Another of the requirements is to have a Network Security Group (NSG) with the correct rules which essentially acts as a layer 4 firewall as documented here – Working with VMs and NSGs in Azure Bastion | Microsoft Learn. Whilst this documentation is good, it doesn’t give you a code-based way to deploy the required rules.

I’ve created both Bicep and ARM templates that will create the NSG, deploy the required rules. My implementation of the rules go even further than the documented rules where anything not specified in rules further up in the priority list is blocked by default with explicit deny rules.

Feel free to use and share. I’ve also put the code in my GitHub here

Bicep Template

param networkSecurityGroupName string
param resourceLocation string

resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2022-11-01' = {
  name: networkSecurityGroupName
  location: resourceLocation
  properties: {
    flushConnection: false
    securityRules: [
      {
        name: 'AllowHttpsInbound'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: '*'
          destinationPortRange: '443'
          direction: 'Inbound'
          priority: 100
          protocol: 'TCP'
          sourceAddressPrefix: 'Internet'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowGatewayManagerInbound'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: '*'
          destinationPortRange: '443'
          direction: 'Inbound'
          priority: 110
          protocol: 'TCP'
          sourceAddressPrefix: 'GatewayManager'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowBastionHostCommunication'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: 'VirtualNetwork'
          destinationPortRanges: [
            '5701'
            '8080'
          ]
          direction: 'Inbound'
          priority: 120
          protocol: '*'
          sourceAddressPrefix: 'VirtualNetwork'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowAzureLoadBalancerInbound'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: '*'
          destinationPortRange: '443'
          direction: 'Inbound'
          priority: 4095
          protocol: 'TCP'
          sourceAddressPrefix: 'AzureLoadBalancer'
          sourcePortRange: '*'
        }
      }
      {
        name: 'DenyAllInbound'
        properties: {
          access: 'Deny'
          destinationAddressPrefix: '*'
          destinationPortRange: '*'
          direction: 'Inbound'
          priority: 4096
          protocol: '*'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowSshRDPOutbound'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: 'VirtualNetwork'
          destinationPortRanges: [
            '22'
            '3389'
          ]
          direction: 'Outbound'
          priority: 100
          protocol: '*'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowAzureCloudOutbound'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: 'AzureCloud'
          destinationPortRange: '443'
          direction: 'Outbound'
          priority: 110
          protocol: 'TCP'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowBastionCommunication'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: 'VirtualNetwork'
          destinationPortRanges: [
            '5701'
            '8080'
          ]
          direction: 'Outbound'
          priority: 120
          protocol: '*'
          sourceAddressPrefix: 'VirtualNetwork'
          sourcePortRange: '*'
        }
      }
      {
        name: 'AllowHttpOutbound'
        properties: {
          access: 'Allow'
          destinationAddressPrefix: 'Internet'
          destinationPortRange: '80'
          direction: 'Outbound'
          priority: 130
          protocol: 'TCP'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
        }
      }
      {
        name: 'DenyAllOutbound'
        properties: {
          access: 'Deny'
          destinationAddressPrefix: '*'
          destinationPortRange: '*'
          direction: 'Outbound'
          priority: 140
          protocol: '*'
          sourceAddressPrefix: '*'
          sourcePortRange: '*'
        }
      }
    ]
  }
}

ARM Template

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.17.1.54307",
      "templateHash": "4751223750055747166"
    }
  },
  "parameters": {
    "networkSecurityGroupName": {
      "type": "string"
    },
    "resourceLocation": {
      "type": "string"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2022-11-01",
      "name": "[parameters('networkSecurityGroupName')]",
      "location": "[parameters('resourceLocation')]",
      "properties": {
        "flushConnection": false,
        "securityRules": [
          {
            "name": "AllowHttpsInbound",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "443",
              "direction": "Inbound",
              "priority": 100,
              "protocol": "TCP",
              "sourceAddressPrefix": "Internet",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowGatewayManagerInbound",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "443",
              "direction": "Inbound",
              "priority": 110,
              "protocol": "TCP",
              "sourceAddressPrefix": "GatewayManager",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowBastionHostCommunication",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "VirtualNetwork",
              "destinationPortRanges": [
                "5701",
                "8080"
              ],
              "direction": "Inbound",
              "priority": 120,
              "protocol": "*",
              "sourceAddressPrefix": "VirtualNetwork",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowAzureLoadBalancerInbound",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "443",
              "direction": "Inbound",
              "priority": 4095,
              "protocol": "TCP",
              "sourceAddressPrefix": "AzureLoadBalancer",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "DenyAllInbound",
            "properties": {
              "access": "Deny",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "*",
              "direction": "Inbound",
              "priority": 4096,
              "protocol": "*",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowSshRDPOutbound",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "VirtualNetwork",
              "destinationPortRanges": [
                "22",
                "3389"
              ],
              "direction": "Outbound",
              "priority": 100,
              "protocol": "*",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowAzureCloudOutbound",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "AzureCloud",
              "destinationPortRange": "443",
              "direction": "Outbound",
              "priority": 110,
              "protocol": "TCP",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowBastionCommunication",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "VirtualNetwork",
              "destinationPortRanges": [
                "5701",
                "8080"
              ],
              "direction": "Outbound",
              "priority": 120,
              "protocol": "*",
              "sourceAddressPrefix": "VirtualNetwork",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "AllowHttpOutbound",
            "properties": {
              "access": "Allow",
              "destinationAddressPrefix": "Internet",
              "destinationPortRange": "80",
              "direction": "Outbound",
              "priority": 130,
              "protocol": "TCP",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*"
            }
          },
          {
            "name": "DenyAllOutbound",
            "properties": {
              "access": "Deny",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "*",
              "direction": "Outbound",
              "priority": 140,
              "protocol": "*",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*"
            }
          }
        ]
      }
    }
  ]
}

 

Categories: