NSG Bicep/ARM-mal for Azure Bastion

| 4 min lesing

Nylig jobbet jeg med et prosjekt der jeg måtte distribuere et nytt miljø i Azure. Dette omfattet et Virtual Network (VNet) som ikke skulle kobles til resten av nettverket og måtte være isolert. Virtual Machines (VMs) som ble distribuert her, måtte også være tilgjengelige via Remote Desktop Protocol og Secure Shell (SSH). Heldigvis har Microsoft en løsning for dette i Azure Bastion. For å integrere Azure Bastion med VNet-et må du ha et dedikert subnett kalt AzureBastionSubnet (ingen varianter av navnet støttes), med minst et /26-adresserom. Et annet krav er å ha en Network Security Group (NSG) med riktige regler, som i praksis fungerer som en brannmur på lag 4, slik det er dokumentert her: Working with VMs and NSGs in Azure Bastion | Microsoft Learn. Dokumentasjonen er god, men den gir ingen kodebasert måte å distribuere de nødvendige reglene på.

Jeg har laget både Bicep- og ARM-maler som oppretter NSG-en og distribuerer de nødvendige reglene. Implementeringen min går enda lenger enn de dokumenterte reglene: Alt som ikke er spesifisert i regler høyere opp i prioritetslisten, blokkeres som standard med eksplisitte deny-regler.

Bruk og del dem gjerne. Jeg har også lagt koden på GitHub her.

Bicep-mal

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-mal

{
  "$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": "*"
            }
          }
        ]
      }
    }
  ]
}