Quickstart: Secure your virtual hub using Azure Firewall Manager - Bicep
In this quickstart, you use Bicep to secure your virtual hub using Azure Firewall Manager. The deployed firewall has an application rule that allows connections to www.microsoft.com
. Two Windows Server 2019 virtual machines are deployed to test the firewall. One jump server is used to connect to the workload server. From the workload server, you can only connect to www.microsoft.com
.
Bicep is a domain-specific language (DSL) that uses declarative syntax to deploy Azure resources. It provides concise syntax, reliable type safety, and support for code reuse. Bicep offers the best authoring experience for your infrastructure-as-code solutions in Azure.
For more information about Azure Firewall Manager, see What is Azure Firewall Manager?.
Prerequisites
- An Azure account with an active subscription. Create an account for free.
Review the Bicep file
This Bicep file creates a secured virtual hub using Azure Firewall Manager, along with the necessary resources to support the scenario.
The Bicep file used in this quickstart is from Azure Quickstart Templates.
@description('Admin username for the servers')
param adminUsername string
@description('Password for the admin account on the servers')
@secure()
param adminPassword string
@description('Location for all resources.')
param location string = resourceGroup().location
@description('Size of the virtual machine.')
param vmSize string = 'Standard_D2_v3'
resource virtualWan 'Microsoft.Network/virtualWans@2021-08-01' = {
name: 'VWan-01'
location: location
properties: {
disableVpnEncryption: false
allowBranchToBranchTraffic: true
type: 'Standard'
}
}
resource virtualHub 'Microsoft.Network/virtualHubs@2021-08-01' = {
name: 'Hub-01'
location: location
properties: {
addressPrefix: '10.1.0.0/16'
virtualWan: {
id: virtualWan.id
}
}
}
resource hubVNetconnection 'Microsoft.Network/virtualHubs/hubVirtualNetworkConnections@2021-08-01' = {
parent: virtualHub
name: 'hub-spoke'
dependsOn: [
firewall
]
properties: {
remoteVirtualNetwork: {
id: virtualNetwork.id
}
allowHubToRemoteVnetTransit: true
allowRemoteVnetToUseHubVnetGateways: false
enableInternetSecurity: true
routingConfiguration: {
associatedRouteTable: {
id: hubRouteTable.id
}
propagatedRouteTables: {
labels: [
'VNet'
]
ids: [
{
id: hubRouteTable.id
}
]
}
}
}
}
resource policy 'Microsoft.Network/firewallPolicies@2021-08-01' = {
name: 'Policy-01'
location: location
properties: {
threatIntelMode: 'Alert'
}
}
resource ruleCollectionGroup 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2021-08-01' = {
parent: policy
name: 'DefaultApplicationRuleCollectionGroup'
properties: {
priority: 300
ruleCollections: [
{
ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
name: 'RC-01'
priority: 100
action: {
type: 'Allow'
}
rules: [
{
ruleType: 'ApplicationRule'
name: 'Allow-msft'
sourceAddresses: [
'*'
]
protocols: [
{
port: 80
protocolType: 'Http'
}
{
port: 443
protocolType: 'Https'
}
]
targetFqdns: [
'*.microsoft.com'
]
}
]
}
]
}
}
resource firewall 'Microsoft.Network/azureFirewalls@2021-08-01' = {
name: 'AzfwTest'
location: location
properties: {
sku: {
name: 'AZFW_Hub'
tier: 'Standard'
}
hubIPAddresses: {
publicIPs: {
count: 1
}
}
virtualHub: {
id: virtualHub.id
}
firewallPolicy: {
id: policy.id
}
}
}
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2021-08-01' = {
name: 'Spoke-01'
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
enableDdosProtection: false
enableVmProtection: false
}
}
resource subnet_Workload_SN 'Microsoft.Network/virtualNetworks/subnets@2021-08-01' = {
parent: virtualNetwork
name: 'Workload-SN'
properties: {
addressPrefix: '10.0.1.0/24'
privateEndpointNetworkPolicies: 'Enabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
}
resource subnet_Jump_SN 'Microsoft.Network/virtualNetworks/subnets@2021-08-01' = {
parent: virtualNetwork
name: 'Jump-SN'
dependsOn: [
subnet_Workload_SN
]
properties: {
addressPrefix: '10.0.2.0/24'
routeTable: {
id: routeTable.id
}
privateEndpointNetworkPolicies: 'Enabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
}
resource Jump_Srv 'Microsoft.Compute/virtualMachines@2022-03-01' = {
name: 'Jump-Srv'
location: location
properties: {
hardwareProfile: {
vmSize: vmSize
}
storageProfile: {
imageReference: {
publisher: 'MicrosoftWindowsServer'
offer: 'WindowsServer'
sku: '2019-Datacenter'
version: 'latest'
}
osDisk: {
osType: 'Windows'
createOption: 'FromImage'
caching: 'ReadWrite'
managedDisk: {
storageAccountType: 'StandardSSD_LRS'
}
diskSizeGB: 127
}
}
osProfile: {
computerName: 'Jump-Srv'
adminUsername: adminUsername
adminPassword: adminPassword
windowsConfiguration: {
provisionVMAgent: true
enableAutomaticUpdates: true
}
allowExtensionOperations: true
}
networkProfile: {
networkInterfaces: [
{
id: netInterface_jump_srv.id
}
]
}
}
}
resource Workload_Srv 'Microsoft.Compute/virtualMachines@2022-03-01' = {
name: 'Workload-Srv'
location: location
properties: {
hardwareProfile: {
vmSize: vmSize
}
storageProfile: {
imageReference: {
publisher: 'MicrosoftWindowsServer'
offer: 'WindowsServer'
sku: '2019-Datacenter'
version: 'latest'
}
osDisk: {
osType: 'Windows'
createOption: 'FromImage'
caching: 'ReadWrite'
managedDisk: {
storageAccountType: 'StandardSSD_LRS'
}
diskSizeGB: 127
}
}
osProfile: {
computerName: 'Workload-Srv'
adminUsername: adminUsername
adminPassword: adminPassword
windowsConfiguration: {
provisionVMAgent: true
enableAutomaticUpdates: true
}
allowExtensionOperations: true
}
networkProfile: {
networkInterfaces: [
{
id: netInterface_workload_srv.id
}
]
}
}
}
resource netInterface_workload_srv 'Microsoft.Network/networkInterfaces@2021-08-01' = {
name: 'netInterface-workload-srv'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnet_Workload_SN.id
}
primary: true
privateIPAddressVersion: 'IPv4'
}
}
]
enableAcceleratedNetworking: false
enableIPForwarding: false
networkSecurityGroup: {
id: nsg_workload_srv.id
}
}
}
resource netInterface_jump_srv 'Microsoft.Network/networkInterfaces@2021-08-01' = {
name: 'netInterface-jump-srv'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: publicIP_jump_srv.id
}
subnet: {
id: subnet_Jump_SN.id
}
primary: true
privateIPAddressVersion: 'IPv4'
}
}
]
enableAcceleratedNetworking: false
enableIPForwarding: false
networkSecurityGroup: {
id: nsg_jump_srv.id
}
}
}
resource nsg_jump_srv 'Microsoft.Network/networkSecurityGroups@2021-08-01' = {
name: 'nsg-jump-srv'
location: location
properties: {
securityRules: [
{
name: 'RDP'
properties: {
protocol: 'Tcp'
sourcePortRange: '*'
destinationPortRange: '3389'
sourceAddressPrefix: '*'
destinationAddressPrefix: '*'
access: 'Allow'
priority: 300
direction: 'Inbound'
}
}
]
}
}
resource nsg_workload_srv 'Microsoft.Network/networkSecurityGroups@2021-08-01' = {
name: 'nsg-workload-srv'
location: location
properties: {}
}
resource publicIP_jump_srv 'Microsoft.Network/publicIPAddresses@2021-08-01' = {
name: 'publicIP-jump-srv'
location: location
sku: {
name: 'Standard'
}
properties: {
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Static'
idleTimeoutInMinutes: 4
}
}
resource routeTable 'Microsoft.Network/routeTables@2021-08-01' = {
name: 'RT-01'
location: location
properties: {
disableBgpRoutePropagation: false
routes: [
{
name: 'jump-to-inet'
properties: {
addressPrefix: '0.0.0.0/0'
nextHopType: 'Internet'
}
}
]
}
}
resource hubRouteTable 'Microsoft.Network/virtualHubs/hubRouteTables@2021-08-01' = {
parent: virtualHub
name: 'RT_VNet'
properties: {
routes: [
{
name: 'Workload-SNToFirewall'
destinationType: 'CIDR'
destinations: [
'10.0.1.0/24'
]
nextHopType: 'ResourceId'
nextHop: firewall.id
}
{
name: 'InternetToFirewall'
destinationType: 'CIDR'
destinations: [
'0.0.0.0/0'
]
nextHopType: 'ResourceId'
nextHop: firewall.id
}
]
labels: [
'VNet'
]
}
}
Multiple Azure resources are defined in the Bicep file:
- Microsoft.Network/virtualWans
- Microsoft.Network/virtualHubs
- Microsoft.Network/firewallPolicies
- Microsoft.Network/azureFirewalls
- Microsoft.Network/virtualNetworks
- Microsoft.Compute/virtualMachines
- Microsoft.Storage/storageAccounts
- Microsoft.Network/networkInterfaces
- Microsoft.Network/networkSecurityGroups
- Microsoft.Network/publicIPAddresses
- Microsoft.Network/routeTables
Deploy the Bicep file
Save the Bicep file as
main.bicep
to your local computer.Deploy the Bicep file using either Azure CLI or Azure PowerShell.
az group create --name exampleRG --location eastus az deployment group create --resource-group exampleRG --template-file main.bicep --parameters adminUsername=<admin-user>
Note
Replace <admin-user> with the administrator login username for the servers. You'll be prompted to enter adminPassword.
When the deployment finishes, you should see a message indicating the deployment succeeded.
Validate the deployment
Use Azure CLI or Azure PowerShell to review the deployed resources.
az resource list --resource-group exampleRG
Now, test the firewall rules to confirm that it works as expected.
From the Azure portal, review the network settings for the Workload-Srv virtual machine and note the private IP address.
Connect a remote desktop to Jump-Srv virtual machine, and sign in. From there, open a remote desktop connection to the Workload-Srv private IP address.
Open Internet Explorer and browse to
www.microsoft.com
.Select OK > Close on the Internet Explorer security alerts.
You should see the Microsoft home page.
Browse to
www.google.com
.You should be blocked by the firewall.
Now you've verified that the firewall rules are working, you can browse to the one allowed FQDN, but not to any others.
Clean up resources
When you no longer need the resources that you created with the firewall, use Azure portal, Azure CLI, or Azure PowerShell to delete the resource group. This removes the firewall and all the related resources.
az group delete --name exampleRG