* feat: azFw Basic SKU - Bicep

* feat: Fw Basic - ARM implementation

* DOCS: fix heading
This commit is contained in:
Thodoris Theodorou 2024-04-02 19:09:30 +03:00 коммит произвёл GitHub
Родитель 0acc6318dc
Коммит 7eb5e67d68
21 изменённых файлов: 4586 добавлений и 1605 удалений

Просмотреть файл

@ -13,7 +13,6 @@ This repository provides both enterprise architecture guidelines and a reference
- [Step 2. Configure and test the deployment in your own environment](#step-2-configure-and-test-the-deployment-in-your-own-environment)
- [Deploy with Azure Portal (Bicep/ARM)](#deploy-with-azure-portal-biceparm)
- [Locally deploy with Bicep](#locally-deploy-with-bicep)
- [Locally deploy with Terraform](#locally-deploy-with-terraform)
- [Step 3. Configure GitHub Actions](#step-3-configure-github-actions)
- [App Patterns](#app-patterns)
- [Got a feedback](#got-a-feedback)
@ -89,7 +88,7 @@ Before deploying the Bicep IaC artifacts, you need to review and customize the v
The expandable table below summarizes the available parameters and the possible values that can be set.
<details>
<summary><h4>Bicep Configuration Parameters Table</h4></summary>
<summary>Bicep Configuration Parameters Table</summary>
| Name | Description | Example |
|------|-------------|---------|
@ -101,7 +100,8 @@ The expandable table below summarizes the available parameters and the possible
|firewallInternalIp|If you select to create a new Hub, the UDR for locking the egress traffic will be created as well, no matter what value you set to that variable. However, if you select to connect to an existing hub, then you need to provide the internal IP of the azure firewal so that the deployment can create the UDR for locking down egress traffic. If not given, no UDR will be created||
|vnetHubAddressSpace|If you deploy a new hub, you need to set the appropriate CIDR of the newly created Hub virtual network|10.242.0.0/20|
|subnetHubFirewallAddressSpace|CIDR of the subnet that will host the azure Firewall|10.242.0.0/26|
|subnetHubBastionAddressSpace|CIDR of the subnet that will host the Bastion Service|10.242.0.64/26|
|subnetHubFirewallManagementAddressSpace|CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic|10.242.0.64/26|
|subnetHubBastionAddressSpace|CIDR of the subnet that will host the Bastion Service|10.242.0.128/26|
|vnetSpokeAddressSpace|CIDR of the spoke vnet that will hold the app services plan and the rest supporting services (and their private endpoints)|10.240.0.0/20|
|subnetSpokeAppSvcAddressSpace|CIDR of the subnet that will hold the app services plan. ATTENTION: If you deploy ASEv3 this CIDR should be x.x.x.x/24 |10.240.0.0/26 (*USE 10.240.0.0/24 if deployAseV3=true*)|
|subnetSpokeDevOpsAddressSpace|CIDR of the subnet that will hold devOps agents etc|10.240.10.128/26|
@ -119,7 +119,7 @@ The expandable table below summarizes the available parameters and the possible
</details>
<details>
<summary><h4> Locally deploy with Terraform</h4></summary>
<summary> Locally deploy with Terraform </summary>
1. Ensure you are logged in to Azure CLI and have selected the correct subscription.
1. Navigate to the Terraform deployment directory (same directory as the `main.tf` file).
- [scenarios/secure-baseline-multitenant/terraform/hub](scenarios/secure-baseline-multitenant/terraform/hub/)

Просмотреть файл

@ -27,7 +27,8 @@ The table below summarizes the available parameters and the possible values that
|firewallInternalIp|If you select to create a new Hub, the UDR for locking the egress traffic will be created as well, no matter what value you set to that variable. However, if you select to connect to an existing hub, then you need to provide the internal IP of the azure firewall so that the deployment can create the UDR for locking down egress traffic. If not given, no UDR will be created||
|vnetHubAddressSpace|If you deploy a new hub, you need to set the appropriate CIDR of the newly created Hub virtual network|10.242.0.0/20|
|subnetHubFirewallAddressSpace|CIDR of the subnet that will host the azure Firewall|10.242.0.0/26|
|subnetHubBastionAddressSpace|CIDR of the subnet that will host the Bastion Service|10.242.0.64/26|
|subnetHubFirewallManagementAddressSpace|CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic|10.242.0.64/26|
|subnetHubBastionAddressSpace|CIDR of the subnet that will host the Bastion Service|10.242.0.128/26|
|vnetSpokeAddressSpace|CIDR of the spoke vnet that will hold the app services plan and the rest supporting services (and their private endpoints)|10.240.0.0/20|
|subnetSpokeAppSvcAddressSpace|CIDR of the subnet that will hold the app services plan|10.240.0.0/26|
|subnetSpokeDevOpsAddressSpace|CIDR of the subnet that will hold devOps agents etc|10.240.10.128/26|

Просмотреть файл

@ -32,4 +32,10 @@ for webapp_id in $webapp_ids; do
done
# test
# test
# https://portal.azure.com/#view/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/URL_TEMPLATE/uiFormDefinitionUri/CUSTOM_UI_DEF_JSON
# <!-- URL_TEMPLATE: The URL Encoded version of the URI to the remote Azure ARM deployment template -->
# <!-- CUSTOM_UI_DEF_JSON: The URL Encoded version of the URI to the custom UI Definition json file -->
# <!-- The actual link for our sample deployment -->

Просмотреть файл

@ -378,12 +378,33 @@
"infoMessages": [],
"visible": "[equals(steps('networking').sectionHubSelector.deployHub, 'deployNew')]"
},
{
"name": "subnetHubFirewallManagementAddressSpace",
"type": "Microsoft.Common.TextBox",
"label": "Azure Firewall Management Subnet Address Prefix (azFW Basic)",
"subLabel": "",
"defaultValue": "10.242.0.64/26",
"toolTip": "CIDR to use for the Azure Firewall Management subnet (Azure Firewall Basic). Optional if you want to use an existing hub vnet (vnetHubResourceId)",
"constraints": {
"required": true,
"regex": "",
"validationMessage": "",
"validations": [
{
"regex": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(?:\/(2[0-6]))$",
"message": "Invalid CIDR range. The address prefix must be in the range [20,26]."
}
]
},
"infoMessages": [],
"visible": "[equals(steps('networking').sectionHubSelector.deployHub, 'deployNew')]"
},
{
"name": "subnetHubBastionAddressSpace",
"type": "Microsoft.Common.TextBox",
"label": "Hub Subnet CIDR for Bastion Service",
"subLabel": "",
"defaultValue": "10.242.0.64/26",
"defaultValue": "10.242.0.128/26",
"toolTip": "CIDR of the subnet hosting the Bastion Service - optional if you want to use an existing hub vnet (vnetHubResourceId)",
"constraints": {
"required": false,
@ -1168,6 +1189,7 @@
"environmentName": "[steps('basics').environmentName]",
"vnetHubAddressSpace": "[steps('networking').vnetHubAddressSpace]",
"subnetHubFirewallAddressSpace": "[steps('networking').subnetHubFirewallAddressSpace]",
"subnetHubFirewallManagementAddressSpace": "[steps('networking').subnetHubFirewallManagementAddressSpace]",
"subnetHubBastionAddressSpace": "[steps('networking').subnetHubBastionAddressSpace]",
"vnetSpokeAddressSpace": "[steps('networking').vnetSpokeAddressSpace]",
"subnetSpokeAppSvcAddressSpace": "[if( equals ( steps('basics').appSvcPlanSection.deployAseV3, true), steps('networking').subnetSpokeAppSvcAddressSpaceAse , steps('networking').subnetSpokeAppSvcAddressSpace )]",

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -57,11 +57,15 @@
},
// CIDR of the subnet that will host the azure Firewall
"subnetHubFirewallAddressSpace": {
"value": "10.242.0.0/26"
"value": "10.242.0.0/26" // "10.242.0.0/26"
},
// CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic
"subnetHubFirewallManagementAddressSpace": {
"value": "10.242.0.64/26" //
},
// CIDR of the subnet that will host the Bastion Service
"subnetHubBastionAddressSpace": {
"value": "10.242.0.64/26"
"value": "10.242.0.128/26" // "10.242.0.64/26"
},
//CIDR of the spoke vnet that will hold the app services plan and the rest supporting services (and their private endpoints)
"vnetSpokeAddressSpace": {

Просмотреть файл

@ -26,7 +26,8 @@ The table below summarizes the available parameters and the possible values that
|firewallInternalIp|If you select to create a new Hub, the UDR for locking the egress traffic will be created as well, no matter what value you set to that variable. However, if you select to connect to an existing hub, then you need to provide the internal IP of the azure firewall so that the deployment can create the UDR for locking down egress traffic. If not given, no UDR will be created||
|vnetHubAddressSpace|If you deploy a new hub, you need to set the appropriate CIDR of the newly created Hub virtual network|10.242.0.0/20|
|subnetHubFirewallAddressSpace|CIDR of the subnet that will host the azure Firewall|10.242.0.0/26|
|subnetHubBastionAddressSpace|CIDR of the subnet that will host the Bastion Service|10.242.0.64/26|
|subnetHubFirewallManagementAddressSpace|CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic|10.242.0.64/26|
|subnetHubBastionAddressSpace|CIDR of the subnet that will host the Bastion Service|10.242.0.128/26|
|vnetSpokeAddressSpace|CIDR of the spoke vnet that will hold the app services plan and the rest supporting services (and their private endpoints)|10.240.0.0/20|
|subnetSpokeAppSvcAddressSpace|CIDR of the subnet that will hold the app services plan. ATTENTION: If you deploy ASEv3 this CIDR should be x.x.x.x/24 |10.240.0.0/26 (*USE 10.240.0.0/24 if deployAseV3=true*)|
|subnetSpokeDevOpsAddressSpace|CIDR of the subnet that will hold devOps agents etc|10.240.10.128/26|
@ -54,7 +55,7 @@ az deployment sub create \
--template-file main.bicep \
--location $location \
--name $deploymentName \
--parameters ./main.parameters.jsonc
--parameters ./main.parameters.local.jsonc
```
### Powershell (windows based OS)

Просмотреть файл

@ -15,6 +15,9 @@ param vnetHubAddressSpace string
@description('CIDR of the subnet hosting the azure Firewall')
param subnetHubFirewallAddressSpace string
@description('CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic.')
param subnetHubFirewallManagementAddressSpace string
@description('CIDR of the subnet hosting the Bastion Service')
param subnetHubBastionAddressSpace string
@ -25,24 +28,13 @@ param vnetSpokeAddressSpace string
param subnetSpokeDevOpsAddressSpace string
//look https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-deployment#example-1
// TODO: Check if this is required or if we go with module (inline) implementation
// var privateDnsZoneNames = {
// appConfiguration: 'privatelink.azconfig.io'
// webApps: 'privaprivatelink.azurewebsites.net'
// sqlDb: 'privatelink${environment().suffixes.sqlServerHostname}'
// redis: 'privatelink.redis.cache.windows.net'
// keyvault: 'privatelink.vaultcore.azure.net'
// }
var resourceNames = {
bastionService: naming.bastionHost.name
laws: take ('${naming.logAnalyticsWorkspace.name}-hub', 63)
azFw: naming.firewall.name
vnetHub: take('${naming.virtualNetwork.name}-hub', 80)
subnetFirewall: 'AzureFirewallSubnet'
subnetFirewallManagement: 'AzureFirewallManagementSubnet'
subnetBastion: 'AzureBastionSubnet'
}
@ -57,6 +49,12 @@ var subnets = [
// }
}
}
{
name: resourceNames.subnetFirewallManagement
properties: {
addressPrefix: subnetHubFirewallManagementAddressSpace
}
}
{
name: resourceNames.subnetBastion
properties: {
@ -99,362 +97,22 @@ module laws '../../shared/bicep/log-analytics-ws.bicep' = {
}
}
var applicationRules = [
{
name: 'Azure-Monitor-FQDNs'
properties: {
action: {
type: 'allow'
}
priority: 201
rules: [
{
fqdnTags: [ ]
targetFqdns: [
'dc.applicationinsights.azure.com'
'dc.applicationinsights.microsoft.com'
'dc.services.visualstudio.com'
'*.in.applicationinsights.azure.com'
'live.applicationinsights.azure.com'
'rt.applicationinsights.microsoft.com'
'rt.services.visualstudio.com'
'*.livediagnostics.monitor.azure.com'
'*.monitoring.azure.com'
'agent.azureserviceprofiler.net'
'*.agent.azureserviceprofiler.net'
'*.monitor.azure.com'
]
name: 'allow-azure-monitor'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetHubAddressSpace
vnetSpokeAddressSpace
]
}
{
name: 'allow-entra-join'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
targetFqdns: [
'enterpriseregistration.windows.net'
'pas.windows.net'
#disable-next-line no-hardcoded-env-urls
'login.microsoftonline.com'
#disable-next-line no-hardcoded-env-urls
'device.login.microsoftonline.com'
'autologon.microsoftazuread-sso.com'
'manage-beta.microsoft.com'
'manage.microsoft.com'
'aadcdn.msauth.net'
'aadcdn.msftauth.net'
'aadcdn.msftauthimages.net'
'*.sts.microsoft.com'
'*.manage-beta.microsoft.com'
'*.manage.microsoft.com'
]
}
]
}
}
{
name: 'Devops-VM-Dependencies-FQDNs'
properties: {
action: {
type: 'allow'
}
priority: 202
rules: [
{
fqdnTags: [ ]
targetFqdns: [
'enterpriseregistration.windows.net'
'pas.windows.net'
#disable-next-line no-hardcoded-env-urls
'login.microsoftonline.com'
#disable-next-line no-hardcoded-env-urls
'device.login.microsoftonline.com'
'autologon.microsoftazuread-sso.com'
'manage-beta.microsoft.com'
'manage.microsoft.com'
'aadcdn.msauth.net'
'aadcdn.msftauth.net'
'aadcdn.msftauthimages.net'
'*.sts.microsoft.com'
'*.manage-beta.microsoft.com'
'*.manage.microsoft.com'
]
name: 'allow-entra-join'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
}
{
name: 'allow-vm-dependencies-and-tools'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
targetFqdns: [
'aka.ms'
'go.microsoft.com'
'download.microsoft.com'
'edge.microsoft.com'
'fs.microsoft.com'
'wdcp.microsoft.com'
'wdcpalt.microsoft.com'
'msedge.api.cdp.microsoft.com'
'winatp-gw-cane.microsoft.com'
'*.google.com'
'*.live.com'
'*.bing.com'
'*.msappproxy.net'
'*.delivery.mp.microsoft.com'
'*.data.microsoft.com'
'*.blob.storage.azure.net'
#disable-next-line no-hardcoded-env-urls
'*.blob.core.windows.net'
'*.dl.delivery.mp.microsoft.com'
'*.prod.do.dsp.mp.microsoft.com'
'*.update.microsoft.com'
'*.windowsupdate.com'
'*.apps.qualys.com'
'*.bootstrapcdn.com'
'*.jsdelivr.net'
'*.jquery.com'
'*.msecnd.net'
]
}
]
}
}
{
name: 'Core-Dependencies-FQDNs'
properties: {
action: {
type: 'allow'
}
priority: 200
rules: [
{
fqdnTags: [ ]
targetFqdns: [
#disable-next-line no-hardcoded-env-urls
'management.azure.com'
#disable-next-line no-hardcoded-env-urls
'management.core.windows.net'
#disable-next-line no-hardcoded-env-urls
'login.microsoftonline.com'
'login.windows.net'
'login.live.com'
#disable-next-line no-hardcoded-env-urls
'graph.windows.net'
]
name: 'allow-core-apis'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetSpokeAddressSpace
vnetHubAddressSpace
]
}
{
name: 'allow-developer-services'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetSpokeAddressSpace
vnetHubAddressSpace
]
targetFqdns: [
'github.com'
'*.github.com'
'*.nuget.org'
#disable-next-line no-hardcoded-env-urls
'*.blob.core.windows.net'
'raw.githubusercontent.com'
'dev.azure.com'
'portal.azure.com'
'*.portal.azure.com'
'*.portal.azure.net'
'appservice.azureedge.net'
'*.azurewebsites.net'
#disable-next-line no-hardcoded-env-urls
'edge.management.azure.com'
]
}
{
name: 'allow-certificate-dependencies'
protocols: [
{
port: '80'
protocolType: 'HTTP'
}
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetSpokeAddressSpace
vnetHubAddressSpace
]
targetFqdns: [
'*.delivery.mp.microsoft.com'
'ctldl.windowsupdate.com'
'ocsp.msocsp.com'
'oneocsp.microsoft.com'
'crl.microsoft.com'
'www.microsoft.com'
'*.digicert.com'
'*.symantec.com'
'*.symcb.com'
'*.d-trust.net'
]
}
]
}
}
]
var networkRules = [
{
name: 'Windows-VM-Connectivity-Requirements'
properties: {
action: {
type: 'allow'
}
priority: 202
rules: [
{
destinationAddresses: [
'20.118.99.224'
'40.83.235.53'
'23.102.135.246'
'51.4.143.248'
'23.97.0.13'
'52.126.105.2'
]
destinationPorts: [
'*'
]
name: 'allow-kms-activation'
protocols: [
'Any'
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
}
{
destinationAddresses: [
'*'
]
destinationPorts: [
'123'
'12000'
]
name: 'allow-ntp'
protocols: [
'Any'
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
}
]
}
}
]
module azFw '../../shared/bicep/network/firewall.bicep' = {
name: 'azFW-Deployment'
@description('The Azure Firewall deployment. This would normally be already provisioned by your platform team.')
module azfw './modules/firewall-basic.module.bicep' = {
name: take('afw-${deployment().name}', 64)
params: {
location: location
name: resourceNames.azFw
vnetId: vnetHub.outputs.vnetId
diagnosticWorkspaceId: laws.outputs.logAnalyticsWsId
tags: tags
applicationRuleCollections: applicationRules
networkRuleCollections: networkRules
afwVNetName: vnetHub.outputs.vnetName
logAnalyticsWorkspaceId: laws.outputs.logAnalyticsWsId
firewallName: resourceNames.azFw
vnetSpokeAddressSpace: vnetSpokeAddressSpace
subnetSpokeDevOpsAddressSpace: subnetSpokeDevOpsAddressSpace
vnetHubAddressSpace: vnetHubAddressSpace
}
}
// module privateDnsZoneAppConfig '../../shared/bicep/private-dns-zone.bicep' = {
// name: 'privateDnsZoneAppConfigDeployment'
// params: {
// name: privateDnsZoneNames.appConfiguration
// virtualNetworkLinks: virtualNetworkLinks
// tags: tags
// }
// }
// module privateDnsKeyvault '../../shared/bicep/private-dns-zone.bicep' = {
// name: 'privateDnsKeyvaultDeployment'
// params: {
// name: privateDnsZoneNames.keyvault
// virtualNetworkLinks: virtualNetworkLinks
// tags: tags
// }
// }
// module privateDnsRedis '../../shared/bicep/private-dns-zone.bicep' = {
// name: 'privateDnsRedisDeployment'
// params: {
// name: privateDnsZoneNames.redis
// virtualNetworkLinks: virtualNetworkLinks
// tags: tags
// }
// }
// module privateDnsZoneSql '../../shared/bicep/private-dns-zone.bicep' = {
// name: 'privateDnsZoneSqlDeployment'
// params: {
// name: privateDnsZoneNames.sqlDb
// virtualNetworkLinks: virtualNetworkLinks
// tags: tags
// }
// }
// module privateDnsWebApps '../../shared/bicep/private-dns-zone.bicep' = {
// name: 'privateDnsWebAppsDeployment'
// params: {
// name: privateDnsZoneNames.webApps
// virtualNetworkLinks: virtualNetworkLinks
// tags: tags
// }
// }
@description('Resource name of the hub vnet')
output vnetHubName string = vnetHub.outputs.vnetName
@ -463,4 +121,4 @@ output vnetHubName string = vnetHub.outputs.vnetName
output vnetHubId string = vnetHub.outputs.vnetId
@description('The private IP of the Azure firewall.')
output firewallPrivateIp string = azFw.outputs.azFwPrivateIp
output firewallPrivateIp string = azfw.outputs.afwPrivateIp

Просмотреть файл

@ -24,8 +24,11 @@ param vnetHubAddressSpace string = '10.242.0.0/20'
@description('CIDR of the subnet hosting the azure Firewall - optional if you want to use an existing hub vnet (vnetHubResourceId)')
param subnetHubFirewallAddressSpace string = '10.242.0.0/26'
@description('CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic.')
param subnetHubFirewallManagementAddressSpace string = '10.242.0.64/26'
@description('CIDR of the subnet hosting the Bastion Service - optional if you want to use an existing hub vnet (vnetHubResourceId)')
param subnetHubBastionAddressSpace string = '10.242.0.64/26'
param subnetHubBastionAddressSpace string = '10.242.0.128/26'
@description('CIDR of the SPOKE vnet i.e. 192.168.0.0/24')
param vnetSpokeAddressSpace string = '10.240.0.0/20'
@ -189,6 +192,7 @@ module hub 'deploy.hub.bicep' = if ( empty(vnetHubResourceId) ) {
tags: tags
subnetHubBastionAddressSpace: subnetHubBastionAddressSpace
subnetHubFirewallAddressSpace: subnetHubFirewallAddressSpace
subnetHubFirewallManagementAddressSpace: subnetHubFirewallManagementAddressSpace
vnetSpokeAddressSpace: vnetSpokeAddressSpace
subnetSpokeDevOpsAddressSpace: subnetSpokeDevOpsAddressSpace
}

Просмотреть файл

@ -44,8 +44,11 @@
"subnetHubFirewallAddressSpace": {
"value": "10.242.0.0/26"
},
"subnetHubFirewallManagementAddressSpace": {
"value": "10.242.0.64/26"
},
"subnetHubBastionAddressSpace": {
"value": "10.242.0.64/26"
"value": "10.242.0.128/26"
},
"vnetSpokeAddressSpace": {
"value": "10.240.0.0/20"

Просмотреть файл

@ -57,11 +57,15 @@
},
// CIDR of the subnet that will host the azure Firewall
"subnetHubFirewallAddressSpace": {
"value": "10.242.0.0/26"
"value": "10.242.0.0/26" // "10.242.0.0/26"
},
// CIDR to use for the AzureFirewallManagementSubnet, which is required by AzFW Basic
"subnetHubFirewallManagementAddressSpace": {
"value": "10.242.0.64/26" //
},
// CIDR of the subnet that will host the Bastion Service
"subnetHubBastionAddressSpace": {
"value": "10.242.0.64/26"
"value": "10.242.0.128/26" // "10.242.0.64/26"
},
//CIDR of the spoke vnet that will hold the app services plan and the rest supporting services (and their private endpoints)
"vnetSpokeAddressSpace": {

Просмотреть файл

@ -0,0 +1,373 @@
targetScope = 'resourceGroup'
// ------------------
// PARAMETERS
// ------------------
@description('The location where the resources will be created.')
param location string
@description('The name of the azure firewall to create.')
param firewallName string
@description('The Name of the virtual network in which afw is created.')
param afwVNetName string
@description('The log analytics workspace id to which the azure firewall will send logs.')
param logAnalyticsWorkspaceId string
@description('Optional. The tags to be assigned to the created resources.')
param tags object = {}
@description('CIDR of the subnet that will hold devOps agents etc ')
param subnetSpokeDevOpsAddressSpace string
@description('CIDR of the HUB vnet i.e. 192.168.0.0/24')
param vnetHubAddressSpace string
@description('CIDR of the SPOKE vnet i.e. 192.168.0.0/24')
param vnetSpokeAddressSpace string
// ------------------
// RESOURCES
// ------------------
resource hubVnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = {
name: afwVNetName
}
@description('The azure firewall deployment.')
module afw '../../../shared/bicep/network/azureFirewalls/main.bicep' = {
name: 'afw-deployment'
params: {
tags: tags
location: location
name: firewallName
azureSkuTier: 'Basic'
vNetId: hubVnet.id
additionalPublicIpConfigurations: []
applicationRuleCollections: applicationRules
networkRuleCollections: networkRules
natRuleCollections: []
threatIntelMode: 'Deny'
diagnosticSettings: [
{
name: 'customSetting'
workspaceResourceId: logAnalyticsWorkspaceId
}
]
}
}
// ------------------
// OUTPUTS
// ------------------
output afwPrivateIp string = afw.outputs.privateIp
output afwId string = afw.outputs.resourceId
@description('Application Rules for the Firewall')
var applicationRules = [
{
name: 'Azure-Monitor-FQDNs'
properties: {
action: {
type: 'allow'
}
priority: 201
rules: [
{
fqdnTags: [ ]
targetFqdns: [
'dc.applicationinsights.azure.com'
'dc.applicationinsights.microsoft.com'
'dc.services.visualstudio.com'
'*.in.applicationinsights.azure.com'
'live.applicationinsights.azure.com'
'rt.applicationinsights.microsoft.com'
'rt.services.visualstudio.com'
'*.livediagnostics.monitor.azure.com'
'*.monitoring.azure.com'
'agent.azureserviceprofiler.net'
'*.agent.azureserviceprofiler.net'
'*.monitor.azure.com'
]
name: 'allow-azure-monitor'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetHubAddressSpace
vnetSpokeAddressSpace
]
}
{
name: 'allow-azure-ad-join'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
targetFqdns: [
'enterpriseregistration.windows.net'
'pas.windows.net'
#disable-next-line no-hardcoded-env-urls
'login.microsoftonline.com'
#disable-next-line no-hardcoded-env-urls
'device.login.microsoftonline.com'
'autologon.microsoftazuread-sso.com'
'manage-beta.microsoft.com'
'manage.microsoft.com'
'aadcdn.msauth.net'
'aadcdn.msftauth.net'
'aadcdn.msftauthimages.net'
'*.sts.microsoft.com'
'*.manage-beta.microsoft.com'
'*.manage.microsoft.com'
]
}
]
}
}
{
name: 'Devops-VM-Dependencies-FQDNs'
properties: {
action: {
type: 'allow'
}
priority: 202
rules: [
{
fqdnTags: [ ]
targetFqdns: [
'enterpriseregistration.windows.net'
'pas.windows.net'
#disable-next-line no-hardcoded-env-urls
'login.microsoftonline.com'
#disable-next-line no-hardcoded-env-urls
'device.login.microsoftonline.com'
'autologon.microsoftazuread-sso.com'
'manage-beta.microsoft.com'
'manage.microsoft.com'
'aadcdn.msauth.net'
'aadcdn.msftauth.net'
'aadcdn.msftauthimages.net'
'*.sts.microsoft.com'
'*.manage-beta.microsoft.com'
'*.manage.microsoft.com'
]
name: 'allow-azure-ad-join'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
}
{
name: 'allow-vm-dependencies-and-tools'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
targetFqdns: [
'aka.ms'
'go.microsoft.com'
'download.microsoft.com'
'edge.microsoft.com'
'fs.microsoft.com'
'wdcp.microsoft.com'
'wdcpalt.microsoft.com'
'msedge.api.cdp.microsoft.com'
'winatp-gw-cane.microsoft.com'
'*.google.com'
'*.live.com'
'*.bing.com'
'*.msappproxy.net'
'*.delivery.mp.microsoft.com'
'*.data.microsoft.com'
'*.blob.storage.azure.net'
#disable-next-line no-hardcoded-env-urls
'*.blob.core.windows.net'
'*.dl.delivery.mp.microsoft.com'
'*.prod.do.dsp.mp.microsoft.com'
'*.update.microsoft.com'
'*.windowsupdate.com'
'*.apps.qualys.com'
'*.bootstrapcdn.com'
'*.jsdelivr.net'
'*.jquery.com'
'*.msecnd.net'
]
}
]
}
}
{
name: 'Core-Dependencies-FQDNs'
properties: {
action: {
type: 'allow'
}
priority: 200
rules: [
{
fqdnTags: [ ]
targetFqdns: [
#disable-next-line no-hardcoded-env-urls
'management.azure.com'
#disable-next-line no-hardcoded-env-urls
'management.core.windows.net'
#disable-next-line no-hardcoded-env-urls
'login.microsoftonline.com'
'login.windows.net'
'login.live.com'
#disable-next-line no-hardcoded-env-urls
'graph.windows.net'
]
name: 'allow-core-apis'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetSpokeAddressSpace
vnetHubAddressSpace
]
}
{
name: 'allow-developer-services'
protocols: [
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetSpokeAddressSpace
vnetHubAddressSpace
]
targetFqdns: [
'github.com'
'*.github.com'
'*.nuget.org'
#disable-next-line no-hardcoded-env-urls
'*.blob.core.windows.net'
'raw.githubusercontent.com'
'dev.azure.com'
'portal.azure.com'
'*.portal.azure.com'
'*.portal.azure.net'
'appservice.azureedge.net'
'*.azurewebsites.net'
#disable-next-line no-hardcoded-env-urls
'edge.management.azure.com'
]
}
{
name: 'allow-certificate-dependencies'
protocols: [
{
port: '80'
protocolType: 'HTTP'
}
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
vnetSpokeAddressSpace
vnetHubAddressSpace
]
targetFqdns: [
'*.delivery.mp.microsoft.com'
'ctldl.windowsupdate.com'
'ocsp.msocsp.com'
'oneocsp.microsoft.com'
'crl.microsoft.com'
'www.microsoft.com'
'*.digicert.com'
'*.symantec.com'
'*.symcb.com'
'*.d-trust.net'
]
}
]
}
}
]
@description('Network Rules for the Firewall')
var networkRules = [
{
name: 'Windows-VM-Connectivity-Requirements'
properties: {
action: {
type: 'allow'
}
priority: 202
rules: [
{
destinationAddresses: [
'20.118.99.224'
'40.83.235.53'
'23.102.135.246'
'51.4.143.248'
'23.97.0.13'
'52.126.105.2'
]
destinationPorts: [
'*'
]
name: 'allow-kms-activation'
protocols: [
'Any'
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
}
{
destinationAddresses: [
'*'
]
destinationPorts: [
'123'
'12000'
]
name: 'allow-ntp'
protocols: [
'Any'
]
sourceAddresses: [
subnetSpokeDevOpsAddressSpace
]
}
]
}
}
]

Просмотреть файл

@ -0,0 +1,97 @@
@sys.description('Required. The IDs of the principals to assign the role to.')
param principalIds array
@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.')
param roleDefinitionIdOrName string
@sys.description('Required. The resource ID of the resource to apply the role assignment to.')
param resourceId string
@sys.description('Optional. The principal type of the assigned principal ID.')
@allowed([
'ServicePrincipal'
'Group'
'User'
'ForeignGroup'
'Device'
''
])
param principalType string = ''
@sys.description('Optional. The description of the role assignment.')
param description string = ''
@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".')
param condition string = ''
@sys.description('Optional. Version of the condition.')
@allowed([
'2.0'
])
param conditionVersion string = '2.0'
@sys.description('Optional. Id of the delegated managed identity resource.')
param delegatedManagedIdentityResourceId string = ''
var builtInRoleNames = {
'Avere Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a')
'Avere Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9')
'Azure Center for SAP solutions administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7b0c7e81-271f-4c71-90bf-e30bdfdbc2f7')
'Azure Center for SAP solutions reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '05352d14-a920-4328-a0de-4cbe7430e26b')
'Azure Center for SAP solutions service role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aabbc5dd-1af0-458b-a942-81af88f9c138')
'Azure Kubernetes Service Policy Add-on Deployment': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18ed5180-3e48-46fd-8541-4ea054d57064')
'Backup Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')
'Backup Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00c29273-979b-4161-815c-10b084fb9324')
Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
'Cosmos DB Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')
'Desktop Virtualization Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')
'DevTest Labs User': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')
'DNS Resolver Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')
'DNS Zone Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')
'DocumentDB Account Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')
'Domain Services Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')
'Domain Services Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')
'LocalNGFirewallAdministrator role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8835c7d-b5cb-47fa-b6f0-65ea10ce07a2')
'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')
'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')
'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')
'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')
'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')
'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')
'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')
'Network Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')
Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')
'Private DNS Zone Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')
Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')
'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')
'Site Recovery Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6670b86e-a3f7-4917-ac9b-5d6ab1be4567')
'Site Recovery Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '494ae006-db33-4328-bf46-533a6560a3ca')
'SQL Managed Instance Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4939a1f6-9ae0-4e48-a1e0-f2cbe897382d')
'SQL Security Manager': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '056cd41c-7e88-42e1-933e-88ba6a50c9c3')
'Storage Account Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')
'Traffic Manager Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4b10055-b0c7-44c2-b00f-c7b5b3550cf7')
'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')
'Virtual Machine Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')
'Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')
'Virtual Machine User Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')
'Windows Admin Center Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a6333a3e-0164-44c3-b281-7a577aff287f')
}
resource azureFirewall 'Microsoft.Network/azureFirewalls@2021-08-01' existing = {
name: last(split(resourceId, '/'))!
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: {
name: guid(azureFirewall.id, principalId, roleDefinitionIdOrName)
properties: {
description: description
roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName
principalId: principalId
principalType: !empty(principalType) ? any(principalType) : null
condition: !empty(condition) ? condition : null
conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null
delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null
}
scope: azureFirewall
}]

Просмотреть файл

@ -0,0 +1,969 @@
# Azure Firewalls `[Microsoft.Network/azureFirewalls]`
This module deploys a firewall.
## Navigation
- [Resource types](#Resource-types)
- [Parameters](#Parameters)
- [Outputs](#Outputs)
- [Considerations](#Considerations)
- [Cross-referenced modules](#Cross-referenced-modules)
- [Deployment examples](#Deployment-examples)
## Resource types
| Resource Type | API Version |
| :-- | :-- |
| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) |
| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) |
| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) |
| `Microsoft.Network/azureFirewalls` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/azureFirewalls) |
| `Microsoft.Network/publicIPAddresses` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/publicIPAddresses) |
## Parameters
**Required parameters**
| Parameter Name | Type | Description |
| :-- | :-- | :-- |
| `name` | string | Name of the Azure Firewall. |
**Conditional parameters**
| Parameter Name | Type | Default Value | Description |
| :-- | :-- | :-- | :-- |
| `hubIPAddresses` | object | `{object}` | IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied. |
| `virtualHubId` | string | `''` | The virtualHub resource ID to which the firewall belongs. Required if `vNetId` is empty. |
| `vNetId` | string | `''` | Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty. |
**Optional parameters**
| Parameter Name | Type | Default Value | Allowed Values | Description |
| :-- | :-- | :-- | :-- | :-- |
| `additionalPublicIpConfigurations` | array | `[]` | | This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration. |
| `applicationRuleCollections` | array | `[]` | | Collection of application rule collections used by Azure Firewall. |
| `azureSkuTier` | string | `'Standard'` | `[Premium, Standard]` | Tier of an Azure Firewall. |
| `diagnosticEventHubAuthorizationRuleId` | string | `''` | | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. |
| `diagnosticEventHubName` | string | `''` | | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. |
| `diagnosticLogCategoriesToEnable` | array | `[allLogs]` | `[allLogs, AzureFirewallApplicationRule, AzureFirewallDnsProxy, AzureFirewallNetworkRule]` | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. |
| `diagnosticMetricsToEnable` | array | `[AllMetrics]` | `[AllMetrics]` | The name of metrics that will be streamed. |
| `diagnosticSettingsName` | string | `''` | | The name of the diagnostic setting, if deployed. If left empty, it defaults to "<resourceName>-diagnosticSettings". |
| `diagnosticStorageAccountId` | string | `''` | | Diagnostic Storage Account resource identifier. |
| `diagnosticWorkspaceId` | string | `''` | | Log Analytics workspace resource identifier. |
| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). |
| `firewallPolicyId` | string | `''` | | Resource ID of the Firewall Policy that should be attached. |
| `isCreateDefaultPublicIP` | bool | `True` | | Specifies if a Public IP should be created by default if one is not provided. |
| `location` | string | `[resourceGroup().location]` | | Location for all resources. |
| `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. |
| `natRuleCollections` | array | `[]` | | Collection of NAT rule collections used by Azure Firewall. |
| `networkRuleCollections` | array | `[]` | | Collection of network rule collections used by Azure Firewall. |
| `publicIPAddressObject` | object | `{object}` | | Specifies the properties of the Public IP to create and be used by Azure Firewall. If it's not provided and publicIPAddressId is empty, a '-pip' suffix will be appended to the Firewall's name. |
| `publicIPResourceID` | string | `''` | | The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet. |
| `roleAssignments` | array | `[]` | | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. |
| `tags` | object | `{object}` | | Tags of the Azure Firewall resource. |
| `threatIntelMode` | string | `'Deny'` | `[Alert, Deny, Off]` | The operation mode for Threat Intel. |
| `zones` | array | `[1, 2, 3]` | | Zone numbers e.g. 1,2,3. |
### Parameter Usage: `additionalPublicIpConfigurations`
Create additional public ip configurations from existing public ips
<details>
<summary>Parameter JSON format</summary>
```json
"additionalPublicIpConfigurations": {
"value": [
{
"name": "ipConfig01",
"publicIPAddressResourceId": "/subscriptions/<<subscriptionId>>/resourceGroups/validation-rg/providers/Microsoft.Network/publicIPAddresses/adp-<<namePrefix>>-az-pip-x-fw-01"
},
{
"name": "ipConfig02",
"publicIPAddressResourceId": "/subscriptions/<<subscriptionId>>/resourceGroups/validation-rg/providers/Microsoft.Network/publicIPAddresses/adp-<<namePrefix>>-az-pip-x-fw-02"
}
]
}
```
</details>
<details>
<summary>Bicep format</summary>
```bicep
additionalPublicIpConfigurations: [
{
name: 'ipConfig01'
publicIPAddressResourceId: '/subscriptions/<<subscriptionId>>/resourceGroups/validation-rg/providers/Microsoft.Network/publicIPAddresses/adp-<<namePrefix>>-az-pip-x-fw-01'
}
{
name: 'ipConfig02'
publicIPAddressResourceId: '/subscriptions/<<subscriptionId>>/resourceGroups/validation-rg/providers/Microsoft.Network/publicIPAddresses/adp-<<namePrefix>>-az-pip-x-fw-02'
}
]
```
</details>
### Parameter Usage: `publicIPAddressObject`
The Public IP Address object to create as part of the module. This will be created if `isCreateDefaultPublicIP` is true (which it is by default). If not provided, the name and other configurations will be set by default.
<details>
<summary>Parameter JSON format</summary>
```json
"publicIPAddressObject": {
"value": {
"name": "adp-<<namePrefix>>-az-pip-custom-x-fw",
"publicIPPrefixResourceId": "",
"publicIPAllocationMethod": "Static",
"skuName": "Standard",
"skuTier": "Regional",
"roleAssignments": [
{
"roleDefinitionIdOrName": "Reader",
"principalIds": [
"<principalId>"
]
}
],
"diagnosticMetricsToEnable": [
"AllMetrics"
],
"diagnosticLogCategoriesToEnable": [
"DDoSProtectionNotifications",
"DDoSMitigationFlowLogs",
"DDoSMitigationReports"
]
}
}
```
</details>
<details>
<summary>Bicep format</summary>
```bicep
publicIPAddressObject: {
name: 'mypip'
publicIPPrefixResourceId: '/subscriptions/<<subscriptionId>>/resourceGroups/validation-rg/providers/Microsoft.Network/publicIPPrefixes/myprefix'
publicIPAllocationMethod: 'Dynamic'
skuName: 'Basic'
skuTier: 'Regional'
roleAssignments: [
{
roleDefinitionIdOrName: 'Reader'
principalIds: [
'<principalId>'
]
}
]
diagnosticMetricsToEnable: [
'AllMetrics'
]
diagnosticLogCategoriesToEnable: [
'DDoSProtectionNotifications'
'DDoSMitigationFlowLogs'
'DDoSMitigationReports'
]
}
```
</details>
### Parameter Usage: `roleAssignments`
Create a role assignment for the given resource. If you want to assign a service principal / managed identity that is created in the same deployment, make sure to also specify the `'principalType'` parameter and set it to `'ServicePrincipal'`. This will ensure the role assignment waits for the principal's propagation in Azure.
<details>
<summary>Parameter JSON format</summary>
```json
"roleAssignments": {
"value": [
{
"roleDefinitionIdOrName": "Reader",
"description": "Reader Role Assignment",
"principalIds": [
"12345678-1234-1234-1234-123456789012", // object 1
"78945612-1234-1234-1234-123456789012" // object 2
]
},
{
"roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11",
"principalIds": [
"12345678-1234-1234-1234-123456789012" // object 1
],
"principalType": "ServicePrincipal"
}
]
}
```
</details>
<details>
<summary>Bicep format</summary>
```bicep
roleAssignments: [
{
roleDefinitionIdOrName: 'Reader'
description: 'Reader Role Assignment'
principalIds: [
'12345678-1234-1234-1234-123456789012' // object 1
'78945612-1234-1234-1234-123456789012' // object 2
]
}
{
roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'
principalIds: [
'12345678-1234-1234-1234-123456789012' // object 1
]
principalType: 'ServicePrincipal'
}
]
```
</details>
<p>
### Parameter Usage: `tags`
Tag names and tag values can be provided as needed. A tag can be left without a value.
<details>
<summary>Parameter JSON format</summary>
```json
"tags": {
"value": {
"Environment": "Non-Prod",
"Contact": "test.user@testcompany.com",
"PurchaseOrder": "1234",
"CostCenter": "7890",
"ServiceName": "DeploymentValidation",
"Role": "DeploymentValidation"
}
}
```
</details>
<details>
<summary>Bicep format</summary>
```bicep
tags: {
Environment: 'Non-Prod'
Contact: 'test.user@testcompany.com'
PurchaseOrder: '1234'
CostCenter: '7890'
ServiceName: 'DeploymentValidation'
Role: 'DeploymentValidation'
}
```
</details>
<p>
## Outputs
| Output Name | Type | Description |
| :-- | :-- | :-- |
| `applicationRuleCollections` | array | List of Application Rule Collections. |
| `ipConfAzureFirewallSubnet` | object | The Public IP configuration object for the Azure Firewall Subnet. |
| `location` | string | The location the resource was deployed into. |
| `name` | string | The name of the Azure Firewall. |
| `natRuleCollections` | array | Collection of NAT rule collections used by Azure Firewall. |
| `networkRuleCollections` | array | List of Network Rule Collections. |
| `privateIp` | string | The private IP of the Azure firewall. |
| `resourceGroupName` | string | The resource group the Azure firewall was deployed into. |
| `resourceId` | string | The resource ID of the Azure Firewall. |
## Considerations
The `applicationRuleCollections` parameter accepts a JSON Array of AzureFirewallApplicationRule objects.
The `networkRuleCollections` parameter accepts a JSON Array of AzureFirewallNetworkRuleCollection objects.
## Cross-referenced modules
This section gives you an overview of all local-referenced module files (i.e., other CARML modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs).
| Reference | Type |
| :-- | :-- |
| `Network/publicIPAddresses` | Local reference |
## Deployment examples
The following module usage examples are retrieved from the content of the files hosted in the module's `.test` folder.
>**Note**: The name of each example is based on the name of the file from which it is taken.
>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order.
<h3>Example 1: Addpip</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module azureFirewalls './Network/azureFirewalls/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-nafaddpip'
params: {
// Required parameters
name: '<<namePrefix>>nafaddpip001'
// Non-required parameters
additionalPublicIpConfigurations: [
{
name: 'ipConfig01'
publicIPAddressResourceId: '<publicIPAddressResourceId>'
}
]
enableDefaultTelemetry: '<enableDefaultTelemetry>'
tags: {
Environment: 'Non-Prod'
Role: 'DeploymentValidation'
}
vNetId: '<vNetId>'
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>nafaddpip001"
},
// Non-required parameters
"additionalPublicIpConfigurations": {
"value": [
{
"name": "ipConfig01",
"publicIPAddressResourceId": "<publicIPAddressResourceId>"
}
]
},
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"tags": {
"value": {
"Environment": "Non-Prod",
"Role": "DeploymentValidation"
}
},
"vNetId": {
"value": "<vNetId>"
}
}
}
```
</details>
<p>
<h3>Example 2: Common</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module azureFirewalls './Network/azureFirewalls/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-nafcom'
params: {
// Required parameters
name: '<<namePrefix>>nafcom001'
// Non-required parameters
applicationRuleCollections: [
{
name: 'allow-app-rules'
properties: {
action: {
type: 'allow'
}
priority: 100
rules: [
{
fqdnTags: [
'AppServiceEnvironment'
'WindowsUpdate'
]
name: 'allow-ase-tags'
protocols: [
{
port: '80'
protocolType: 'HTTP'
}
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
'*'
]
}
{
name: 'allow-ase-management'
protocols: [
{
port: '80'
protocolType: 'HTTP'
}
{
port: '443'
protocolType: 'HTTPS'
}
]
sourceAddresses: [
'*'
]
targetFqdns: [
'bing.com'
]
}
]
}
}
]
diagnosticEventHubAuthorizationRuleId: '<diagnosticEventHubAuthorizationRuleId>'
diagnosticEventHubName: '<diagnosticEventHubName>'
diagnosticStorageAccountId: '<diagnosticStorageAccountId>'
diagnosticWorkspaceId: '<diagnosticWorkspaceId>'
enableDefaultTelemetry: '<enableDefaultTelemetry>'
lock: 'CanNotDelete'
networkRuleCollections: [
{
name: 'allow-network-rules'
properties: {
action: {
type: 'allow'
}
priority: 100
rules: [
{
destinationAddresses: [
'*'
]
destinationPorts: [
'12000'
'123'
]
name: 'allow-ntp'
protocols: [
'Any'
]
sourceAddresses: [
'*'
]
}
]
}
}
]
publicIPResourceID: '<publicIPResourceID>'
roleAssignments: [
{
principalIds: [
'<managedIdentityPrincipalId>'
]
principalType: 'ServicePrincipal'
roleDefinitionIdOrName: 'Reader'
}
]
tags: {
Environment: 'Non-Prod'
Role: 'DeploymentValidation'
}
vNetId: '<vNetId>'
zones: [
'1'
'2'
'3'
]
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>nafcom001"
},
// Non-required parameters
"applicationRuleCollections": {
"value": [
{
"name": "allow-app-rules",
"properties": {
"action": {
"type": "allow"
},
"priority": 100,
"rules": [
{
"fqdnTags": [
"AppServiceEnvironment",
"WindowsUpdate"
],
"name": "allow-ase-tags",
"protocols": [
{
"port": "80",
"protocolType": "HTTP"
},
{
"port": "443",
"protocolType": "HTTPS"
}
],
"sourceAddresses": [
"*"
]
},
{
"name": "allow-ase-management",
"protocols": [
{
"port": "80",
"protocolType": "HTTP"
},
{
"port": "443",
"protocolType": "HTTPS"
}
],
"sourceAddresses": [
"*"
],
"targetFqdns": [
"bing.com"
]
}
]
}
}
]
},
"diagnosticEventHubAuthorizationRuleId": {
"value": "<diagnosticEventHubAuthorizationRuleId>"
},
"diagnosticEventHubName": {
"value": "<diagnosticEventHubName>"
},
"diagnosticStorageAccountId": {
"value": "<diagnosticStorageAccountId>"
},
"diagnosticWorkspaceId": {
"value": "<diagnosticWorkspaceId>"
},
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"lock": {
"value": "CanNotDelete"
},
"networkRuleCollections": {
"value": [
{
"name": "allow-network-rules",
"properties": {
"action": {
"type": "allow"
},
"priority": 100,
"rules": [
{
"destinationAddresses": [
"*"
],
"destinationPorts": [
"12000",
"123"
],
"name": "allow-ntp",
"protocols": [
"Any"
],
"sourceAddresses": [
"*"
]
}
]
}
}
]
},
"publicIPResourceID": {
"value": "<publicIPResourceID>"
},
"roleAssignments": {
"value": [
{
"principalIds": [
"<managedIdentityPrincipalId>"
],
"principalType": "ServicePrincipal",
"roleDefinitionIdOrName": "Reader"
}
]
},
"tags": {
"value": {
"Environment": "Non-Prod",
"Role": "DeploymentValidation"
}
},
"vNetId": {
"value": "<vNetId>"
},
"zones": {
"value": [
"1",
"2",
"3"
]
}
}
}
```
</details>
<p>
<h3>Example 3: Custompip</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module azureFirewalls './Network/azureFirewalls/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-nafcstpip'
params: {
// Required parameters
name: '<<namePrefix>>nafcstpip001'
// Non-required parameters
enableDefaultTelemetry: '<enableDefaultTelemetry>'
publicIPAddressObject: {
diagnosticLogCategoriesToEnable: [
'DDoSMitigationFlowLogs'
'DDoSMitigationReports'
'DDoSProtectionNotifications'
]
diagnosticMetricsToEnable: [
'AllMetrics'
]
name: 'new-<<namePrefix>>-pip-nafcstpip'
publicIPAllocationMethod: 'Static'
publicIPPrefixResourceId: ''
roleAssignments: [
{
principalIds: [
'<managedIdentityPrincipalId>'
]
principalType: 'ServicePrincipal'
roleDefinitionIdOrName: 'Reader'
}
]
skuName: 'Standard'
skuTier: 'Regional'
}
tags: {
Environment: 'Non-Prod'
Role: 'DeploymentValidation'
}
vNetId: '<vNetId>'
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>nafcstpip001"
},
// Non-required parameters
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"publicIPAddressObject": {
"value": {
"diagnosticLogCategoriesToEnable": [
"DDoSMitigationFlowLogs",
"DDoSMitigationReports",
"DDoSProtectionNotifications"
],
"diagnosticMetricsToEnable": [
"AllMetrics"
],
"name": "new-<<namePrefix>>-pip-nafcstpip",
"publicIPAllocationMethod": "Static",
"publicIPPrefixResourceId": "",
"roleAssignments": [
{
"principalIds": [
"<managedIdentityPrincipalId>"
],
"principalType": "ServicePrincipal",
"roleDefinitionIdOrName": "Reader"
}
],
"skuName": "Standard",
"skuTier": "Regional"
}
},
"tags": {
"value": {
"Environment": "Non-Prod",
"Role": "DeploymentValidation"
}
},
"vNetId": {
"value": "<vNetId>"
}
}
}
```
</details>
<p>
<h3>Example 4: Hubcommon</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module azureFirewalls './Network/azureFirewalls/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-nafhubcom'
params: {
// Required parameters
name: '<<namePrefix>>nafhubcom001'
// Non-required parameters
enableDefaultTelemetry: '<enableDefaultTelemetry>'
firewallPolicyId: '<firewallPolicyId>'
hubIPAddresses: {
publicIPs: {
count: 1
}
}
tags: {
Environment: 'Non-Prod'
Role: 'DeploymentValidation'
}
virtualHubId: '<virtualHubId>'
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>nafhubcom001"
},
// Non-required parameters
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"firewallPolicyId": {
"value": "<firewallPolicyId>"
},
"hubIPAddresses": {
"value": {
"publicIPs": {
"count": 1
}
}
},
"tags": {
"value": {
"Environment": "Non-Prod",
"Role": "DeploymentValidation"
}
},
"virtualHubId": {
"value": "<virtualHubId>"
}
}
}
```
</details>
<p>
<h3>Example 5: Hubmin</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module azureFirewalls './Network/azureFirewalls/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-nafhubmin'
params: {
// Required parameters
name: '<<namePrefix>>nafhubmin001'
// Non-required parameters
enableDefaultTelemetry: '<enableDefaultTelemetry>'
hubIPAddresses: {
publicIPs: {
count: 1
}
}
virtualHubId: '<virtualHubId>'
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>nafhubmin001"
},
// Non-required parameters
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"hubIPAddresses": {
"value": {
"publicIPs": {
"count": 1
}
}
},
"virtualHubId": {
"value": "<virtualHubId>"
}
}
}
```
</details>
<p>
<h3>Example 6: Min</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module azureFirewalls './Network/azureFirewalls/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-nafmin'
params: {
// Required parameters
name: '<<namePrefix>>nafmin001'
// Non-required parameters
enableDefaultTelemetry: '<enableDefaultTelemetry>'
vNetId: '<vNetId>'
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>nafmin001"
},
// Non-required parameters
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"vNetId": {
"value": "<vNetId>"
}
}
}
```
</details>
<p>

Просмотреть файл

@ -0,0 +1,388 @@
metadata name = 'Azure Firewalls'
metadata description = 'This module deploys an Azure Firewall.'
metadata owner = 'Azure/module-maintainers'
@description('Required. Name of the Azure Firewall.')
param name string
@description('Optional. Tier of an Azure Firewall.')
@allowed([
'Basic'
'Standard'
'Premium'
])
param azureSkuTier string = 'Standard'
@description('Conditional. Shared services Virtual Network resource ID. The virtual network ID containing AzureFirewallSubnet. If a Public IP is not provided, then the Public IP that is created as part of this module will be applied with the subnet provided in this variable. Required if `virtualHubId` is empty.')
param vNetId string = ''
@description('Optional. The Public IP resource ID to associate to the AzureFirewallSubnet. If empty, then the Public IP that is created as part of this module will be applied to the AzureFirewallSubnet.')
param publicIPResourceID string = ''
@description('Optional. This is to add any additional Public IP configurations on top of the Public IP with subnet IP configuration.')
param additionalPublicIpConfigurations array = []
@description('Optional. Specifies the properties of the Public IP to create and be used by the Firewall, if no existing public IP was provided.')
param publicIPAddressObject object = {
name: '${name}-pip'
}
@description('Optional. The Management Public IP resource ID to associate to the AzureFirewallManagementSubnet. If empty, then the Management Public IP that is created as part of this module will be applied to the AzureFirewallManagementSubnet.')
param managementIPResourceID string = ''
@description('Optional. Specifies the properties of the Management Public IP to create and be used by Azure Firewall. If it\'s not provided and managementIPResourceID is empty, a \'-mip\' suffix will be appended to the Firewall\'s name.')
param managementIPAddressObject object = {}
@description('Optional. Collection of application rule collections used by Azure Firewall.')
param applicationRuleCollections array = []
@description('Optional. Collection of network rule collections used by Azure Firewall.')
param networkRuleCollections array = []
@description('Optional. Collection of NAT rule collections used by Azure Firewall.')
param natRuleCollections array = []
@description('Optional. Resource ID of the Firewall Policy that should be attached.')
param firewallPolicyId string = ''
@description('Conditional. IP addresses associated with AzureFirewall. Required if `virtualHubId` is supplied.')
param hubIPAddresses object = {}
@description('Conditional. The virtualHub resource ID to which the firewall belongs. Required if `vNetId` is empty.')
param virtualHubId string = ''
@allowed([
'Alert'
'Deny'
'Off'
])
@description('Optional. The operation mode for Threat Intel.')
param threatIntelMode string = 'Deny'
@description('Optional. Zone numbers e.g. 1,2,3.')
param zones array = [
'1'
'2'
'3'
]
@description('Optional. The diagnostic settings of the service.')
param diagnosticSettings diagnosticSettingType
@description('Optional. Location for all resources.')
param location string = resourceGroup().location
@description('Optional. The lock settings of the service.')
param lock lockType
@description('Optional. Array of role assignments to create.')
param roleAssignments roleAssignmentType
@description('Optional. Tags of the Azure Firewall resource.')
param tags object?
@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).')
param enableDefaultTelemetry bool = true
var azureSkuName = empty(vNetId) ? 'AZFW_Hub' : 'AZFW_VNet'
var requiresManagementIp = azureSkuTier == 'Basic' ? true : false
var isCreateDefaultManagementIP = empty(managementIPResourceID) && requiresManagementIp
// ----------------------------------------------------------------------------
// Prep ipConfigurations object AzureFirewallSubnet for different uses cases:
// 1. Use existing Public IP
// 2. Use new Public IP created in this module
// 3. Do not use a Public IP if publicIPAddressObject is empty
var additionalPublicIpConfigurationsVar = [for ipConfiguration in additionalPublicIpConfigurations: {
name: ipConfiguration.name
properties: {
publicIPAddress: contains(ipConfiguration, 'publicIPAddressResourceId') ? {
id: ipConfiguration.publicIPAddressResourceId
} : null
}
}]
var ipConfigurations = concat([
{
name: !empty(publicIPResourceID) ? last(split(publicIPResourceID, '/')) : publicIPAddress.outputs.name
properties: union({
subnet: {
id: '${vNetId}/subnets/AzureFirewallSubnet' // The subnet name must be AzureFirewallSubnet
}
}, (!empty(publicIPResourceID) || !empty(publicIPAddressObject)) ? {
//Use existing Public IP, new Public IP created in this module, or none if neither
publicIPAddress: {
id: !empty(publicIPResourceID) ? publicIPResourceID : publicIPAddress.outputs.resourceId
}
} : {})
}
], additionalPublicIpConfigurationsVar)
// ----------------------------------------------------------------------------
// Prep managementIPConfiguration object for different uses cases:
// 1. Use existing Management Public IP
// 2. Use new Management Public IP created in this module
// var managementIPConfiguration = {
// name: !empty(managementIPResourceID) ? last(split(managementIPResourceID, '/')) : managementIPAddress.outputs.name
// properties: union({
// subnet: {
// id: '${vNetId}/subnets/AzureFirewallManagementSubnet' // The subnet name must be AzureFirewallManagementSubnet for a 'Basic' SKU tier firewall
// }
// }, (!empty(managementIPResourceID) || !empty(managementIPAddressObject)) ? {
// // Use existing Management Public IP, new Management Public IP created in this module, or none if neither
// publicIPAddress: {
// id: !empty(managementIPResourceID) ? managementIPResourceID : managementIPAddress.outputs.resourceId
// }
// } : {})
// }
var managementIPConfiguration = {
name: managementIPAddress.outputs.name
properties: {
subnet: {
id: '${vNetId}/subnets/AzureFirewallManagementSubnet' // The subnet name must be AzureFirewallManagementSubnet for a 'Basic' SKU tier firewall
}
publicIPAddress: {
id: managementIPAddress.outputs.resourceId
}
}
}
// ----------------------------------------------------------------------------
var builtInRoleNames = {
Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')
Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')
'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')
}
#disable-next-line no-deployments-resources
resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) {
name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}'
properties: {
mode: 'Incremental'
template: {
'$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
contentVersion: '1.0.0.0'
resources: []
}
}
}
module publicIPAddress '../publicIPAddresses/main.bicep' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') {
name: '${uniqueString(deployment().name, location)}-Firewall-PIP'
params: {
name: publicIPAddressObject.name
publicIPPrefixResourceId: contains(publicIPAddressObject, 'publicIPPrefixResourceId') ? (!(empty(publicIPAddressObject.publicIPPrefixResourceId)) ? publicIPAddressObject.publicIPPrefixResourceId : '') : ''
publicIPAllocationMethod: contains(publicIPAddressObject, 'publicIPAllocationMethod') ? (!(empty(publicIPAddressObject.publicIPAllocationMethod)) ? publicIPAddressObject.publicIPAllocationMethod : 'Static') : 'Static'
skuName: contains(publicIPAddressObject, 'skuName') ? (!(empty(publicIPAddressObject.skuName)) ? publicIPAddressObject.skuName : 'Standard') : 'Standard'
skuTier: contains(publicIPAddressObject, 'skuTier') ? (!(empty(publicIPAddressObject.skuTier)) ? publicIPAddressObject.skuTier : 'Regional') : 'Regional'
roleAssignments: contains(publicIPAddressObject, 'roleAssignments') ? (!empty(publicIPAddressObject.roleAssignments) ? publicIPAddressObject.roleAssignments : []) : []
location: location
tags: publicIPAddressObject.?tags ?? tags
zones: zones
}
}
// create a Management Public IP address if one is not provided and the flag is true
module managementIPAddress '../publicIPAddresses/main.bicep' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') {
name: '${uniqueString(deployment().name, location)}-Firewall-MIP'
params: {
name: contains(managementIPAddressObject, 'name') ? (!(empty(managementIPAddressObject.name)) ? managementIPAddressObject.name : '${name}-mip') : '${name}-mip'
publicIPPrefixResourceId: contains(managementIPAddressObject, 'managementIPPrefixResourceId') ? (!(empty(managementIPAddressObject.publicIPPrefixResourceId)) ? managementIPAddressObject.publicIPPrefixResourceId : '') : ''
publicIPAllocationMethod: contains(managementIPAddressObject, 'managementIPAllocationMethod') ? (!(empty(managementIPAddressObject.publicIPAllocationMethod)) ? managementIPAddressObject.publicIPAllocationMethod : 'Static') : 'Static'
skuName: contains(managementIPAddressObject, 'skuName') ? (!(empty(managementIPAddressObject.skuName)) ? managementIPAddressObject.skuName : 'Standard') : 'Standard'
skuTier: contains(managementIPAddressObject, 'skuTier') ? (!(empty(managementIPAddressObject.skuTier)) ? managementIPAddressObject.skuTier : 'Regional') : 'Regional'
roleAssignments: contains(managementIPAddressObject, 'roleAssignments') ? (!empty(managementIPAddressObject.roleAssignments) ? managementIPAddressObject.roleAssignments : []) : []
location: location
tags: managementIPAddressObject.?tags ?? tags
zones: zones
}
}
resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = {
name: name
location: location
zones: length(zones) == 0 ? null : zones
tags: tags
properties: azureSkuName == 'AZFW_VNet' ? {
threatIntelMode: threatIntelMode
firewallPolicy: !empty(firewallPolicyId) ? {
id: firewallPolicyId
} : null
ipConfigurations: ipConfigurations
managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null
sku: {
name: azureSkuName
tier: azureSkuTier
}
applicationRuleCollections: applicationRuleCollections
natRuleCollections: natRuleCollections
networkRuleCollections: networkRuleCollections
} : {
firewallPolicy: !empty(firewallPolicyId) ? {
id: firewallPolicyId
} : null
sku: {
name: azureSkuName
tier: azureSkuTier
}
hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null
virtualHub: !empty(virtualHubId) ? {
id: virtualHubId
} : null
}
}
resource azureFirewall_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') {
name: lock.?name ?? 'lock-${name}'
properties: {
level: lock.?kind ?? ''
notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.'
}
scope: azureFirewall
}
resource azureFirewall_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [for (diagnosticSetting, index) in (diagnosticSettings ?? []): {
name: diagnosticSetting.?name ?? '${name}-diagnosticSettings'
properties: {
storageAccountId: diagnosticSetting.?storageAccountResourceId
workspaceId: diagnosticSetting.?workspaceResourceId
eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId
eventHubName: diagnosticSetting.?eventHubName
metrics: diagnosticSetting.?metricCategories ?? [
{
category: 'AllMetrics'
timeGrain: null
enabled: true
}
]
logs: diagnosticSetting.?logCategoriesAndGroups ?? [
{
categoryGroup: 'AllLogs'
enabled: true
}
]
marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId
logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType
}
scope: azureFirewall
}]
resource azureFirewall_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): {
name: guid(azureFirewall.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName)
properties: {
roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)
principalId: roleAssignment.principalId
description: roleAssignment.?description
principalType: roleAssignment.?principalType
condition: roleAssignment.?condition
conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set
delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId
}
scope: azureFirewall
}]
@description('The resource ID of the Azure Firewall.')
output resourceId string = azureFirewall.id
@description('The name of the Azure Firewall.')
output name string = azureFirewall.name
@description('The resource group the Azure firewall was deployed into.')
output resourceGroupName string = resourceGroup().name
@description('The private IP of the Azure firewall.')
output privateIp string = contains(azureFirewall.properties, 'ipConfigurations') ? azureFirewall.properties.ipConfigurations[0].properties.privateIPAddress : ''
@description('The Public IP configuration object for the Azure Firewall Subnet.')
output ipConfAzureFirewallSubnet object = contains(azureFirewall.properties, 'ipConfigurations') ? azureFirewall.properties.ipConfigurations[0] : {}
@description('List of Application Rule Collections.')
output applicationRuleCollections array = applicationRuleCollections
@description('List of Network Rule Collections.')
output networkRuleCollections array = networkRuleCollections
@description('Collection of NAT rule collections used by Azure Firewall.')
output natRuleCollections array = natRuleCollections
@description('The location the resource was deployed into.')
output location string = azureFirewall.location
// =============== //
// Definitions //
// =============== //
type lockType = {
@description('Optional. Specify the name of lock.')
name: string?
@description('Optional. Specify the type of lock.')
kind: ('CanNotDelete' | 'ReadOnly' | 'None')?
}?
type roleAssignmentType = {
@description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.')
roleDefinitionIdOrName: string
@description('Required. The principal ID of the principal (user/group/identity) to assign the role to.')
principalId: string
@description('Optional. The principal type of the assigned principal ID.')
principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')?
@description('Optional. The description of the role assignment.')
description: string?
@description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container"')
condition: string?
@description('Optional. Version of the condition.')
conditionVersion: '2.0'?
@description('Optional. The Resource Id of the delegated managed identity resource.')
delegatedManagedIdentityResourceId: string?
}[]?
type diagnosticSettingType = {
@description('Optional. The name of diagnostic setting.')
name: string?
@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.')
logCategoriesAndGroups: {
@description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.')
category: string?
@description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to \'AllLogs\' to collect all logs.')
categoryGroup: string?
}[]?
@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.')
metricCategories: {
@description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to \'AllMetrics\' to collect all metrics.')
category: string
}[]?
@description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.')
logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')?
@description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.')
workspaceResourceId: string?
@description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.')
storageAccountResourceId: string?
@description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.')
eventHubAuthorizationRuleResourceId: string?
@description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.')
eventHubName: string?
@description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.')
marketplacePartnerResourceId: string?
}[]?

Просмотреть файл

@ -23,15 +23,16 @@ var snetBastion = {
id: '${vnetId}/subnets/AzureBastionSubnet'
}
module publicIp 'publicIp.bicep' = {
name: 'pipBastionHostDeployment'
params: {
location: location
name: 'pip-${bastionNameSantized}'
skuTier: 'Regional'
skuName: 'Standard'
publicIPAllocationMethod: 'Static'
resource publicIp 'Microsoft.Network/publicIPAddresses@2021-02-01' = {
name: 'pip-${bastionNameSantized}'
location: location
tags: tags
sku: {
name: 'Standard'
tier: 'Regional'
}
properties: {
publicIPAllocationMethod: 'Static'
}
}
@ -50,7 +51,7 @@ resource bastionHost 'Microsoft.Network/bastionHosts@2022-07-01' = {
properties: {
subnet: snetBastion
publicIPAddress: {
id: publicIp.outputs.pipResourceId
id: publicIp.id
}
}
}
@ -59,4 +60,4 @@ resource bastionHost 'Microsoft.Network/bastionHosts@2022-07-01' = {
}
@description('The standard public IP assigned to the Bastion Service')
output bastionPublicIp string = publicIp.outputs.ipAddress
output bastionPublicIp string = publicIp.properties.ipAddress

Просмотреть файл

@ -1,186 +0,0 @@
@description('Required. Name of the Azure Firewall.')
param name string
@description('Optional. Location for all resources.')
param location string = resourceGroup().location
@description('Optional. Tags of the Azure Firewall resource.')
param tags object = {}
@description('Optional. Tier of an Azure Firewall.')
@allowed([
'Standard'
'Premium'
])
param azureSkuTier string = 'Standard'
@description('The virtual network ID containing AzureFirewallSubnet. If a public ip is not provided, then the public ip that is created as part of this module will be applied with the subnet provided in this variable.')
param vnetId string = ''
@description('Optional. Collection of application rule collections used by Azure Firewall.')
param applicationRuleCollections array = []
@description('Optional. Collection of network rule collections used by Azure Firewall.')
param networkRuleCollections array = []
@description('Optional. Collection of NAT rule collections used by Azure Firewall.')
param natRuleCollections array = []
@description('Optional. Resource ID of the Firewall Policy that should be attached.')
param firewallPolicyId string = ''
@allowed([
'Alert'
'Deny'
'Off'
])
@description('Optional. The operation mode for Threat Intel.')
param threatIntelMode string = 'Deny'
@description('Optional. Zone numbers e.g. 1,2,3.')
param zones array = []
// param zones array = [
// '1'
// '2'
// '3'
// ]
@description('Optional. Diagnostic Storage Account resource identifier.')
param diagnosticStorageAccountId string = ''
@description('Optional. Log Analytics workspace resource identifier.')
param diagnosticWorkspaceId string = ''
@description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.')
param diagnosticEventHubAuthorizationRuleId string = ''
@description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category.')
param diagnosticEventHubName string = ''
@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource.')
@allowed([
'allLogs'
'AzureFirewallApplicationRule'
'AzureFirewallNetworkRule'
'AzureFirewallDnsProxy'
])
param diagnosticLogCategoriesToEnable array = [
'allLogs'
]
@description('Optional. The name of metrics that will be streamed.')
@allowed([
'AllMetrics'
])
param diagnosticMetricsToEnable array = [
'AllMetrics'
]
@description('Optional. The name of the diagnostic setting, if deployed.')
param diagnosticSettingsName string = '${name}-diagnosticSettings'
var azFwNameMaxLength = 56
var azFwNameSantized = length(name) > azFwNameMaxLength ? substring(name, 0, azFwNameMaxLength) : name
// The default is AZFW_VNet. If you want to attach azure firewall to vhub, you should set sku to AZFW_Hub. accepted values: AZFW_Hub, AZFW_VNet
var azureSkuName = 'AZFW_VNet'
// ----------------------------------------------------------------------------
var diagnosticsLogsSpecified = [for category in filter(diagnosticLogCategoriesToEnable, item => item != 'allLogs'): {
category: category
enabled: true
}]
var diagnosticsLogs = contains(diagnosticLogCategoriesToEnable, 'allLogs') ? [
{
categoryGroup: 'allLogs'
enabled: true
}
] : diagnosticsLogsSpecified
var diagnosticsMetrics = [for metric in diagnosticMetricsToEnable: {
category: metric
timeGrain: null
enabled: true
}]
var ipConfigurations = [{
name: 'azFwIpConf1'
properties: {
subnet: {
id: '${vnetId}/subnets/AzureFirewallSubnet'
}
publicIPAddress: {
id: publicIp.outputs.pipResourceId
}
}
}]
module publicIp 'publicIp.bicep' = {
name: 'pipAzFwDeployment'
params: {
location: location
name: 'pip-${azFwNameSantized}'
skuTier: 'Regional'
skuName: 'Standard'
publicIPAllocationMethod: 'Static'
}
}
resource azureFirewall_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(diagnosticStorageAccountId) || !empty(diagnosticWorkspaceId) || !empty(diagnosticEventHubAuthorizationRuleId) || !empty(diagnosticEventHubName)) {
name: diagnosticSettingsName
properties: {
storageAccountId: !empty(diagnosticStorageAccountId) ? diagnosticStorageAccountId : null
workspaceId: !empty(diagnosticWorkspaceId) ? diagnosticWorkspaceId : null
eventHubAuthorizationRuleId: !empty(diagnosticEventHubAuthorizationRuleId) ? diagnosticEventHubAuthorizationRuleId : null
eventHubName: !empty(diagnosticEventHubName) ? diagnosticEventHubName : null
metrics: diagnosticsMetrics
logs: diagnosticsLogs
}
scope: azureFirewall
}
resource azureFirewall 'Microsoft.Network/azureFirewalls@2022-07-01' = {
name: azFwNameSantized
location: location
zones: length(zones) == 0 ? null : zones
tags: tags
properties: {
threatIntelMode: threatIntelMode
firewallPolicy: !empty(firewallPolicyId) ? {
id: firewallPolicyId
} : null
ipConfigurations: ipConfigurations
sku: {
name: azureSkuName
tier: azureSkuTier
}
applicationRuleCollections: applicationRuleCollections
natRuleCollections: natRuleCollections
networkRuleCollections: networkRuleCollections
}
}
@description('The resource ID of the Azure Firewall.')
output azureFirewallId string = azureFirewall.id
@description('The name of the Azure Firewall.')
output azureFirewallName string = azureFirewall.name
@description('The private IP of the Azure firewall.')
output azFwPrivateIp string = contains(azureFirewall.properties, 'ipConfigurations') ? azureFirewall.properties.ipConfigurations[0].properties.privateIPAddress : ''
@description('The public IP configuration object for the Azure Firewall Subnet.')
output ipConfAzureFirewallSubnet object = contains(azureFirewall.properties, 'ipConfigurations') ? azureFirewall.properties.ipConfigurations[0] : {}
@description('List of Application Rule Collections.')
output azFwApplicationRuleCollections array = applicationRuleCollections
@description('List of Network Rule Collections.')
output azFwANetworkRuleCollections array = networkRuleCollections
@description('Collection of NAT rule collections used by Azure Firewall.')
output azFwANatRuleCollections array = natRuleCollections

Просмотреть файл

@ -0,0 +1,97 @@
@sys.description('Required. The IDs of the principals to assign the role to.')
param principalIds array
@sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.')
param roleDefinitionIdOrName string
@sys.description('Required. The resource ID of the resource to apply the role assignment to.')
param resourceId string
@sys.description('Optional. The principal type of the assigned principal ID.')
@allowed([
'ServicePrincipal'
'Group'
'User'
'ForeignGroup'
'Device'
''
])
param principalType string = ''
@sys.description('Optional. The description of the role assignment.')
param description string = ''
@sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".')
param condition string = ''
@sys.description('Optional. Version of the condition.')
@allowed([
'2.0'
])
param conditionVersion string = '2.0'
@sys.description('Optional. Id of the delegated managed identity resource.')
param delegatedManagedIdentityResourceId string = ''
var builtInRoleNames = {
'Avere Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4f8fab4f-1852-4a58-a46a-8eaf358af14a')
'Avere Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c025889f-8102-4ebf-b32c-fc0c6f0c6bd9')
'Azure Center for SAP solutions administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7b0c7e81-271f-4c71-90bf-e30bdfdbc2f7')
'Azure Center for SAP solutions reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '05352d14-a920-4328-a0de-4cbe7430e26b')
'Azure Center for SAP solutions service role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'aabbc5dd-1af0-458b-a942-81af88f9c138')
'Azure Kubernetes Service Policy Add-on Deployment': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18ed5180-3e48-46fd-8541-4ea054d57064')
'Backup Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e467623-bb1f-42f4-a55d-6e525e11384b')
'Backup Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00c29273-979b-4161-815c-10b084fb9324')
Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
'Cosmos DB Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')
'Desktop Virtualization Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')
'DevTest Labs User': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')
'DNS Resolver Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')
'DNS Zone Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')
'DocumentDB Account Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')
'Domain Services Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')
'Domain Services Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')
'LocalNGFirewallAdministrator role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a8835c7d-b5cb-47fa-b6f0-65ea10ce07a2')
'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')
'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')
'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e')
'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae')
'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44')
'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')
'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')
'Network Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')
Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')
'Private DNS Zone Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')
Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608')
'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')
'Site Recovery Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6670b86e-a3f7-4917-ac9b-5d6ab1be4567')
'Site Recovery Operator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '494ae006-db33-4328-bf46-533a6560a3ca')
'SQL Managed Instance Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4939a1f6-9ae0-4e48-a1e0-f2cbe897382d')
'SQL Security Manager': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '056cd41c-7e88-42e1-933e-88ba6a50c9c3')
'Storage Account Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')
'Traffic Manager Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4b10055-b0c7-44c2-b00f-c7b5b3550cf7')
'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')
'Virtual Machine Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')
'Virtual Machine Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')
'Virtual Machine User Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')
'Windows Admin Center Administrator Login': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a6333a3e-0164-44c3-b281-7a577aff287f')
}
resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2022-07-01' existing = {
name: last(split(resourceId, '/'))!
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: {
name: guid(publicIpAddress.id, principalId, roleDefinitionIdOrName)
properties: {
description: description
roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName
principalId: principalId
principalType: !empty(principalType) ? any(principalType) : null
condition: !empty(condition) ? condition : null
conditionVersion: !empty(conditionVersion) && !empty(condition) ? conditionVersion : null
delegatedManagedIdentityResourceId: !empty(delegatedManagedIdentityResourceId) ? delegatedManagedIdentityResourceId : null
}
scope: publicIpAddress
}]

Просмотреть файл

@ -0,0 +1,338 @@
# Public IP Addresses `[Microsoft.Network/publicIPAddresses]`
## Navigation
- [Public IP Addresses `[Microsoft.Network/publicIPAddresses]`](#public-ip-addresses-microsoftnetworkpublicipaddresses)
- [Navigation](#navigation)
- [Resource types](#resource-types)
- [Parameters](#parameters)
- [Parameter Usage: `tags`](#parameter-usage-tags)
- [Parameter Usage: `roleAssignments`](#parameter-usage-roleassignments)
- [Outputs](#outputs)
- [Cross-referenced modules](#cross-referenced-modules)
- [Deployment examples](#deployment-examples)
## Resource types
| Resource Type | API Version |
| :-- | :-- |
| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) |
| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) |
| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) |
| `Microsoft.Network/publicIPAddresses` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-07-01/publicIPAddresses) |
## Parameters
**Required parameters**
| Parameter Name | Type | Description |
| :-- | :-- | :-- |
| `name` | string | The name of the Public IP Address. |
**Optional parameters**
| Parameter Name | Type | Default Value | Allowed Values | Description |
| :-- | :-- | :-- | :-- | :-- |
| `diagnosticEventHubAuthorizationRuleId` | string | `''` | | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. |
| `diagnosticEventHubName` | string | `''` | | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. |
| `diagnosticLogCategoriesToEnable` | array | `[allLogs]` | `[allLogs, DDoSMitigationFlowLogs, DDoSMitigationReports, DDoSProtectionNotifications]` | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. |
| `diagnosticMetricsToEnable` | array | `[AllMetrics]` | `[AllMetrics]` | The name of metrics that will be streamed. |
| `diagnosticSettingsName` | string | `''` | | The name of the diagnostic setting, if deployed. If left empty, it defaults to "<resourceName>-diagnosticSettings". |
| `diagnosticStorageAccountId` | string | `''` | | Resource ID of the diagnostic storage account. |
| `diagnosticWorkspaceId` | string | `''` | | Resource ID of the diagnostic log analytics workspace. |
| `domainNameLabel` | string | `''` | | The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system. |
| `enableDefaultTelemetry` | bool | `True` | | Enable telemetry via a Globally Unique Identifier (GUID). |
| `fqdn` | string | `''` | | The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone. |
| `location` | string | `[resourceGroup().location]` | | Location for all resources. |
| `lock` | string | `''` | `['', CanNotDelete, ReadOnly]` | Specify the type of lock. |
| `publicIPAddressVersion` | string | `'IPv4'` | `[IPv4, IPv6]` | IP address version. |
| `publicIPAllocationMethod` | string | `'Dynamic'` | `[Dynamic, Static]` | The public IP address allocation method. |
| `publicIPPrefixResourceId` | string | `''` | | Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix. |
| `reverseFqdn` | string | `''` | | The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN. |
| `roleAssignments` | array | `[]` | | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. |
| `skuName` | string | `'Basic'` | `[Basic, Standard]` | Name of a public IP address SKU. |
| `skuTier` | string | `'Regional'` | `[Global, Regional]` | Tier of a public IP address SKU. |
| `tags` | object | `{object}` | | Tags of the resource. |
| `zones` | array | `[]` | | A list of availability zones denoting the IP allocated for the resource needs to come from. |
### Parameter Usage: `tags`
Tag names and tag values can be provided as needed. A tag can be left without a value.
<details>
<summary>Parameter JSON format</summary>
```json
"tags": {
"value": {
"Environment": "Non-Prod",
"Contact": "test.user@testcompany.com",
"PurchaseOrder": "1234",
"CostCenter": "7890",
"ServiceName": "DeploymentValidation",
"Role": "DeploymentValidation"
}
}
```
</details>
<details>
<summary>Bicep format</summary>
```bicep
tags: {
Environment: 'Non-Prod'
Contact: 'test.user@testcompany.com'
PurchaseOrder: '1234'
CostCenter: '7890'
ServiceName: 'DeploymentValidation'
Role: 'DeploymentValidation'
}
```
</details>
<p>
### Parameter Usage: `roleAssignments`
Create a role assignment for the given resource. If you want to assign a service principal / managed identity that is created in the same deployment, make sure to also specify the `'principalType'` parameter and set it to `'ServicePrincipal'`. This will ensure the role assignment waits for the principal's propagation in Azure.
<details>
<summary>Parameter JSON format</summary>
```json
"roleAssignments": {
"value": [
{
"roleDefinitionIdOrName": "Reader",
"description": "Reader Role Assignment",
"principalIds": [
"12345678-1234-1234-1234-123456789012", // object 1
"78945612-1234-1234-1234-123456789012" // object 2
]
},
{
"roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11",
"principalIds": [
"12345678-1234-1234-1234-123456789012" // object 1
],
"principalType": "ServicePrincipal"
}
]
}
```
</details>
<details>
<summary>Bicep format</summary>
```bicep
roleAssignments: [
{
roleDefinitionIdOrName: 'Reader'
description: 'Reader Role Assignment'
principalIds: [
'12345678-1234-1234-1234-123456789012' // object 1
'78945612-1234-1234-1234-123456789012' // object 2
]
}
{
roleDefinitionIdOrName: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'
principalIds: [
'12345678-1234-1234-1234-123456789012' // object 1
]
principalType: 'ServicePrincipal'
}
]
```
</details>
<p>
## Outputs
| Output Name | Type | Description |
| :-- | :-- | :-- |
| `ipAddress` | string | The public IP address of the public IP address resource. |
| `location` | string | The location the resource was deployed into. |
| `name` | string | The name of the public IP address. |
| `resourceGroupName` | string | The resource group the public IP address was deployed into. |
| `resourceId` | string | The resource ID of the public IP address. |
## Cross-referenced modules
_None_
## Deployment examples
The following module usage examples are retrieved from the content of the files hosted in the module's `.test` folder.
>**Note**: The name of each example is based on the name of the file from which it is taken.
>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order.
<h3>Example 1: Common</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module publicIPAddresses './Network/publicIPAddresses/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-npiacom'
params: {
// Required parameters
name: '<<namePrefix>>npiacom001'
// Non-required parameters
diagnosticEventHubAuthorizationRuleId: '<diagnosticEventHubAuthorizationRuleId>'
diagnosticEventHubName: '<diagnosticEventHubName>'
diagnosticStorageAccountId: '<diagnosticStorageAccountId>'
diagnosticWorkspaceId: '<diagnosticWorkspaceId>'
enableDefaultTelemetry: '<enableDefaultTelemetry>'
lock: 'CanNotDelete'
publicIPAllocationMethod: 'Static'
roleAssignments: [
{
principalIds: [
'<managedIdentityPrincipalId>'
]
principalType: 'ServicePrincipal'
roleDefinitionIdOrName: 'Reader'
}
]
skuName: 'Standard'
tags: {
Environment: 'Non-Prod'
Role: 'DeploymentValidation'
}
zones: [
'1'
'2'
'3'
]
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>npiacom001"
},
// Non-required parameters
"diagnosticEventHubAuthorizationRuleId": {
"value": "<diagnosticEventHubAuthorizationRuleId>"
},
"diagnosticEventHubName": {
"value": "<diagnosticEventHubName>"
},
"diagnosticStorageAccountId": {
"value": "<diagnosticStorageAccountId>"
},
"diagnosticWorkspaceId": {
"value": "<diagnosticWorkspaceId>"
},
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
},
"lock": {
"value": "CanNotDelete"
},
"publicIPAllocationMethod": {
"value": "Static"
},
"roleAssignments": {
"value": [
{
"principalIds": [
"<managedIdentityPrincipalId>"
],
"principalType": "ServicePrincipal",
"roleDefinitionIdOrName": "Reader"
}
]
},
"skuName": {
"value": "Standard"
},
"tags": {
"value": {
"Environment": "Non-Prod",
"Role": "DeploymentValidation"
}
},
"zones": {
"value": [
"1",
"2",
"3"
]
}
}
}
```
</details>
<p>
<h3>Example 2: Min</h3>
<details>
<summary>via Bicep module</summary>
```bicep
module publicIPAddresses './Network/publicIPAddresses/main.bicep' = {
name: '${uniqueString(deployment().name, location)}-test-npiamin'
params: {
// Required parameters
name: '<<namePrefix>>npiamin001'
// Non-required parameters
enableDefaultTelemetry: '<enableDefaultTelemetry>'
}
}
```
</details>
<p>
<details>
<summary>via JSON Parameter file</summary>
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// Required parameters
"name": {
"value": "<<namePrefix>>npiamin001"
},
// Non-required parameters
"enableDefaultTelemetry": {
"value": "<enableDefaultTelemetry>"
}
}
}
```
</details>
<p>

Просмотреть файл

@ -0,0 +1,189 @@
@description('Required. The name of the Public IP Address.')
param name string
@description('Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix.')
param publicIPPrefixResourceId string = ''
@description('Optional. The public IP address allocation method.')
@allowed([
'Dynamic'
'Static'
])
param publicIPAllocationMethod string = 'Dynamic'
@description('Optional. Name of a public IP address SKU.')
@allowed([
'Basic'
'Standard'
])
param skuName string = 'Basic'
@description('Optional. Tier of a public IP address SKU.')
@allowed([
'Global'
'Regional'
])
param skuTier string = 'Regional'
@description('Optional. A list of availability zones denoting the IP allocated for the resource needs to come from.')
param zones array = []
@description('Optional. IP address version.')
@allowed([
'IPv4'
'IPv6'
])
param publicIPAddressVersion string = 'IPv4'
@description('Optional. Resource ID of the diagnostic storage account.')
param diagnosticStorageAccountId string = ''
@description('Optional. Resource ID of the diagnostic log analytics workspace.')
param diagnosticWorkspaceId string = ''
@description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.')
param diagnosticEventHubAuthorizationRuleId string = ''
@description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category.')
param diagnosticEventHubName string = ''
@description('Optional. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system.')
param domainNameLabel string = ''
@description('Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone.')
param fqdn string = ''
@description('Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN.')
param reverseFqdn string = ''
@allowed([
''
'CanNotDelete'
'ReadOnly'
])
@description('Optional. Specify the type of lock.')
param lock string = ''
@description('Optional. Location for all resources.')
param location string = resourceGroup().location
@description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.')
param roleAssignments array = []
@description('Optional. Tags of the resource.')
param tags object = {}
@description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource.')
@allowed([
'allLogs'
'DDoSProtectionNotifications'
'DDoSMitigationFlowLogs'
'DDoSMitigationReports'
])
param diagnosticLogCategoriesToEnable array = [
'allLogs'
]
@description('Optional. The name of metrics that will be streamed.')
@allowed([
'AllMetrics'
])
param diagnosticMetricsToEnable array = [
'AllMetrics'
]
@description('Optional. The name of the diagnostic setting, if deployed. If left empty, it defaults to "<resourceName>-diagnosticSettings".')
param diagnosticSettingsName string = ''
var diagnosticsLogsSpecified = [for category in filter(diagnosticLogCategoriesToEnable, item => item != 'allLogs'): {
category: category
enabled: true
}]
var diagnosticsLogs = contains(diagnosticLogCategoriesToEnable, 'allLogs') ? [
{
categoryGroup: 'allLogs'
enabled: true
}
] : diagnosticsLogsSpecified
var diagnosticsMetrics = [for metric in diagnosticMetricsToEnable: {
category: metric
timeGrain: null
enabled: true
}]
resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2022-07-01' = {
name: name
location: location
tags: tags
sku: {
name: skuName
tier: skuTier
}
zones: zones
properties: {
dnsSettings: !empty(domainNameLabel) ? {
domainNameLabel: domainNameLabel
fqdn: fqdn
reverseFqdn: reverseFqdn
} : null
publicIPAddressVersion: publicIPAddressVersion
publicIPAllocationMethod: publicIPAllocationMethod
publicIPPrefix: !empty(publicIPPrefixResourceId) ? {
id: publicIPPrefixResourceId
} : null
idleTimeoutInMinutes: 4
ipTags: []
}
}
resource publicIpAddress_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock)) {
name: '${publicIpAddress.name}-${lock}-lock'
properties: {
level: any(lock)
notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.'
}
scope: publicIpAddress
}
resource publicIpAddress_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(diagnosticStorageAccountId) || !empty(diagnosticWorkspaceId) || !empty(diagnosticEventHubAuthorizationRuleId) || !empty(diagnosticEventHubName)) {
name: !empty(diagnosticSettingsName) ? diagnosticSettingsName : '${name}-diagnosticSettings'
properties: {
storageAccountId: !empty(diagnosticStorageAccountId) ? diagnosticStorageAccountId : null
workspaceId: !empty(diagnosticWorkspaceId) ? diagnosticWorkspaceId : null
eventHubAuthorizationRuleId: !empty(diagnosticEventHubAuthorizationRuleId) ? diagnosticEventHubAuthorizationRuleId : null
eventHubName: !empty(diagnosticEventHubName) ? diagnosticEventHubName : null
metrics: diagnosticsMetrics
logs: diagnosticsLogs
}
scope: publicIpAddress
}
module publicIpAddress_roleAssignments '.bicep/nested_roleAssignments.bicep' = [for (roleAssignment, index) in roleAssignments: {
name: '${uniqueString(deployment().name, location)}-PIPAddress-Rbac-${index}'
params: {
description: contains(roleAssignment, 'description') ? roleAssignment.description : ''
principalIds: roleAssignment.principalIds
principalType: contains(roleAssignment, 'principalType') ? roleAssignment.principalType : ''
roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName
condition: contains(roleAssignment, 'condition') ? roleAssignment.condition : ''
delegatedManagedIdentityResourceId: contains(roleAssignment, 'delegatedManagedIdentityResourceId') ? roleAssignment.delegatedManagedIdentityResourceId : ''
resourceId: publicIpAddress.id
}
}]
@description('The resource group the public IP address was deployed into.')
output resourceGroupName string = resourceGroup().name
@description('The name of the public IP address.')
output name string = publicIpAddress.name
@description('The resource ID of the public IP address.')
output resourceId string = publicIpAddress.id
@description('The public IP address of the public IP address resource.')
output ipAddress string = contains(publicIpAddress.properties, 'ipAddress') ? publicIpAddress.properties.ipAddress : ''
@description('The location the resource was deployed into.')
output location string = publicIpAddress.location

Просмотреть файл

@ -1,87 +0,0 @@
@description('Required. Name of the Bastion Service.')
param name string
@description('Azure region where the resources will be deployed in')
param location string
@description('Optional. Tags of the resource.')
param tags object = {}
@description('Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix.')
param publicIPPrefixResourceId string = ''
@description('Optional, default is dynamic. The public IP address allocation method.')
@allowed([
'Dynamic'
'Static'
])
param publicIPAllocationMethod string = 'Dynamic'
@description('Optional defaulr is Basic. Name of a public IP address SKU.')
@allowed([
'Basic'
'Standard'
])
param skuName string = 'Basic'
@description('Optional, default is Regional. Tier of a public IP address SKU.')
@allowed([
'Global'
'Regional'
])
param skuTier string = 'Regional'
@description('Optional, default no zones. A list of availability zones denoting the IP allocated for the resource needs to come from.')
param zones array = []
@description('Optional, default is IPv4. IP address version.')
@allowed([
'IPv4'
'IPv6'
])
param publicIPAddressVersion string = 'IPv4'
@description('Optional. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system.')
param domainNameLabel string = ''
@description('Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone.')
param fqdn string = ''
@description('Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN.')
param reverseFqdn string = ''
resource publicIpAddress 'Microsoft.Network/publicIPAddresses@2022-07-01' = {
name: name
location: location
tags: tags
sku: {
name: skuName
tier: skuTier
}
zones: zones
properties: {
dnsSettings: !empty(domainNameLabel) ? {
domainNameLabel: domainNameLabel
fqdn: fqdn
reverseFqdn: reverseFqdn
} : null
publicIPAddressVersion: publicIPAddressVersion
publicIPAllocationMethod: publicIPAllocationMethod
publicIPPrefix: !empty(publicIPPrefixResourceId) ? {
id: publicIPPrefixResourceId
} : null
idleTimeoutInMinutes: 4
ipTags: []
}
}
@description('The name of the public IP address.')
output pipName string = publicIpAddress.name
@description('The resource ID of the public IP address.')
output pipResourceId string = publicIpAddress.id
@description('The public IP address of the public IP address resource.')
output ipAddress string = contains(publicIpAddress.properties, 'ipAddress') ? publicIpAddress.properties.ipAddress : ''