child resources in nested resource in Bicep - azure

I am looking for solution where I can create multiple storage accounts and create child resources like blob for each storage accounts using loops in Bicep.I was able to deploy multiple storage accounts but not getting good examples or documentation on how to create child resources for iterated resources in bicep
#allowed([
'CACN'
'CAEA'
'USE2'
'USCN'
])
param regionCode string
param mandatoryTags object
param sku object = {
name: 'Standard_LRS'
tier: 'Standard'
}
param identity object = {
type: 'SystemAssigned'
}
#allowed([
'None'
'Logging'
'Metrics'
'AzureServices'
])
param bypass string = 'AzureServices'
// array of storage account names
param storageAccounts array
// variables
var kind = 'StorageV2'
var varHTTPSOnly = true
var varEnableNFSv3 = false
var varAllowBlobPublicAccess = false
var tlsVersion = 'TLS1_2'
var enableADLSgen2 = false
resource storageAccountResources 'Microsoft.Storage/storageAccounts#2021-02-01' = [for storageName in storageAccounts: {
name: storageName
location: resourceGroup().location
kind: kind
sku: sku
tags: mandatoryTags
identity: identity
properties: {
accessTier: 'Hot'
supportsHttpsTrafficOnly: varHTTPSOnly
isHnsEnabled: enableADLSgen2
minimumTlsVersion: tlsVersion
isNfsV3Enabled: varEnableNFSv3
allowBlobPublicAccess: varAllowBlobPublicAccess
// network security controls
networkAcls: {
bypass: bypass
defaultAction: 'Deny'
resourceAccessRules: []
virtualNetworkRules: []
ipRules: []
}
routingPreference: {
routingChoice: 'MicrosoftRouting'
publishMicrosoftEndpoints: false
publishInternetEndpoints: false
}
encryption: {
services: {
blob: {
enabled: true
keyType: 'Account'
}
file: {
enabled: true
keyType: 'Account'
}
table: {
enabled: true
keyType: 'Account'
}
queue: {
enabled: true
keyType: 'Account'
}
}
keySource: 'Microsoft.Storage'
}
}
}]
output stgOutput array = [for (name, i) in storageAccounts: {
name: storageAccounts[i].name
}]
resource ${storageName}_default 'Microsoft.Storage/storageAccounts/blobServices#2021-04-01' = {
name: 'default'
properties: {
changeFeed: {
enabled: false
}
restorePolicy : {
enabled: false
}
containerDeleteRetentionPolicy: {
enabled: true
days: 7
}
cors: {
corsRules: []
}
deleteRetentionPolicy: {
enabled: true
days: 7
}
isVersioningEnabled: true
}
}

Looking at the documentation (Iteration for a child resource), you should be able to use an iterator :
resource blobServices 'Microsoft.Storage/storageAccounts/blobServices#2021-04-01' = [for i in range(0, length(storageAccounts)): {
name: '${storageAccountResources[i].name}/default'
properties: {
changeFeed: {
enabled: false
}
restorePolicy: {
enabled: false
}
containerDeleteRetentionPolicy: {
enabled: true
days: 7
}
cors: {
corsRules: []
}
deleteRetentionPolicy: {
enabled: true
days: 7
}
isVersioningEnabled: true
}
}]
For complex arrays, you can use this syntax as well:
resource blobServices 'Microsoft.Storage/storageAccounts/blobServices#2021-04-01' = [for (storageAccount, i) in storageAccounts: {
name: '${storageAccountResources[i].name}/default'
properties: {
changeFeed: {
enabled: storageAccount.changeFeed
}
restorePolicy: {
enabled: storageAccount.restorePolicy
}
...
}
}]

Related

Set Diagnostic Setting for Application Insights

I have created a diagnostic setting for a Log Analytics Workspace.
I'd also like to create and automate a diagnostic setting for workspace-based in Application Insights.
However, I am not sure if that makes sense.
I have created a diagnostic setting as followed:
resource appDiagnostics 'Microsoft.Insights/diagnosticSettings#2021-05-01-preview' = {
name: appSettingName
scope: applicationInsights
properties: {
storageAccountId: storageAccountId
logs: [
{
category: 'Metrics'
enabled: true
}
{
category: 'Dependencies'
enabled: true
}
{
category: 'Exceptions'
enabled: true
}
{
category: 'PageViews'
enabled: true
}
{
category: 'PerformanceCounters'
enabled: true
}
{
category: 'Requests'
enabled: true
}
{
category: 'SystemEvents'
enabled: true
}
{
category: 'Traces'
enabled: true
}
]
metrics: [
{
category: 'AllMetrics'
enabled: true
}
]
}
}
However, I always get an error that my log categories are not valid. Is it because the data is double?
If you look at Azure Monitor Logs references, you will see that all log names have the App prefix so you should be able to do something like that:
var logTypes = [
'AppMetrics'
'AppDependencies'
'AppExceptions'
'AppPageViews'
'AppPerformanceCounters'
'AppRequests'
'AppSystemEvents'
'AppTraces'
'AppAvailabilityResults'
'AppBrowserTimings'
'AppEvents'
]
resource appDiagnostics 'Microsoft.Insights/diagnosticSettings#2021-05-01-preview' = {
name: appSettingName
scope: applicationInsights
properties: {
storageAccountId: storageAccountId
logs: [for logType in logTypes: {
category: logType
enabled: true
}]
metrics: [
{
category: 'AllMetrics'
enabled: true
}
]
}
}
I also got the same error when I executed in my environment.
First of all, if you are trying to enable diagnostic settings(components) for any resource (Eg: Application Insights), Create a new workspace-based application insights and add that resource in the code with the existing keyword as shown below.
resource component 'Microsoft.Insights/components#2020-02-02' existing = {
name: 'new'
}
Application Insights:
Refer MsDoc.
And
Verify the list of supported categories as #Thomas has also given, check the prefix and modify accordingly.
I've taken your code and made a few changes and enabled diagnostic settings for application insights successfully.
param workspaceId string
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-09-01' existing = {
name: 'newstoragejahnavi'
}
resource component 'Microsoft.Insights/components#2020-02-02' existing = {
name: 'new'
}
resource appdiagnostics 'Microsoft.Insights/diagnosticSettings#2021-05-01-preview' = {
name: 'newsetting'
scope: component
properties: {
storageAccountId: storageAccount.id
workspaceId: workspaceId
logs: [
{
category: 'AppDependencies'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
{
category: 'AppExceptions'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
{
category: 'AppPageViews'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
{
category: 'AppPerformanceCounters'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
{
category: 'AppRequests'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
{
category: 'AppSystemEvents'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
{
category: 'AppTraces'
categoryGroup: ''
Retentiondays: 'xx'
enabled: true
}
]
metrics: [
{
category: 'Allmetrics'
enabled: true
}
]
}
}
Deployment succeeded:
Output:

This expression is referencing its own declaration, which is not allowed.bicep(BCP079) Bicep errr

I have a bicep file which is supposed to create a virtual network gateway. I have broken it down by having a seperate bicep file that creates the virtual network. What I really ought to do is have a module for the vnet creation and another for the virtual network gateway, as bicep is new to me, I prefer to do things with little steps and then improve.
What am I trying to achieve ?
Create a virtual network gateway using bicep. I have it as an ARM template which currently works. I converted the ARM template to a bicep file, and this has failed to successfully deploy.
param location string = resourceGroup().location
param rg string = resourceGroup().name
param virtual_network_name string = 'my_virtual_network'
param gwSubnetName string = 'myGatewaySubnet'
param public_ip_gateway string = 'my_public_ip'
param p2s_vpn_name string = 'myPoint_toSite'
param p2s_subnet_name string = 'p2s_subnet'
resource public_ip_gateway_resource 'Microsoft.Network/publicIPAddresses#2022-01-01' = {
name: public_ip_gateway
location: location
sku: {
name: 'Basic'
tier: 'Regional'
}
properties: {
ipAddress: '40.161.130.50'
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Dynamic'
idleTimeoutInMinutes: 4
ipTags: []
}
}
resource virtual_network_name_GatewaySubnet 'Microsoft.Network/virtualNetworks/subnets#2022-01-01' = {
name: '${virtual_network_name}/GatewaySubnet'
properties: {
addressPrefix: '10.2.255.0/25'
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
dependsOn: [
virtual_network_name_resource
]
}
resource virtual_network_name_p2s_subnet 'Microsoft.Network/virtualNetworks/subnets#2022-01-01' = {
name: '${virtual_network_name}/p2s_subnet'
properties: {
addressPrefix: '10.2.1.0/24'
serviceEndpoints: []
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
dependsOn: [
virtual_network_name_resource
]
}
resource p2s_vpn_name_resource 'Microsoft.Network/virtualNetworkGateways#2022-01-01' = {
name: p2s_vpn_name
location: location
properties: {
enablePrivateIpAddress: false
ipConfigurations: [
{
name: 'default'
id: '${p2s_vpn_name_resource.id}/ipConfigurations/default'
properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: public_ip_gateway_resource.id
}
subnet: {
id: virtual_network_name_GatewaySubnet.id
}
}
}
]
natRules: []
enableBgpRouteTranslationForNat: false
disableIPSecReplayProtection: false
sku: {
name: 'VpnGw1'
tier: 'VpnGw1'
}
gatewayType: 'Vpn'
vpnType: 'RouteBased'
enableBgp: false
activeActive: false
vpnClientConfiguration: {
vpnClientAddressPool: {
addressPrefixes: [
'119.x.x.0/24'
]
}
vpnClientProtocols: [
'OpenVPN'
]
vpnAuthenticationTypes: [
'Certificate'
]
vpnClientRootCertificates: [
{
name: 'Rahman'
id: '${p2s_vpn_name_resource.id}/vpnClientRootCertificates/MyCert'
properties: {
publicCertData: 'xxxxxxxxxxx=='
}
}
]
vpnClientRevokedCertificates: []
radiusServers: []
vpnClientIpsecPolicies: []
}
bgpSettings: {
asn: 65515
bgpPeeringAddress: '10.2.255.126'
peerWeight: 0
bgpPeeringAddresses: [
{
ipconfigurationId: '${p2s_vpn_name_resource.id}/ipConfigurations/default'
customBgpIpAddresses: []
}
]
}
customRoutes: {
addressPrefixes: []
}
vpnGatewayGeneration: 'Generation1'
}
}
resource virtual_network_name_resource 'Microsoft.Network/virtualNetworks#2022-01-01' = {
name: virtual_network_name
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.2.0.0/16'
]
}
subnets: [
{
name: 'GatewaySubnet'
id: resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name ,gwSubnetName)
properties: {
addressPrefix: '10.2.255.0/25'
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
{
name: 'p2s_subnet'
// id: virtual_network_name_p2s_subnet.id
id: resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name ,p2s_subnet_name)
properties: {
addressPrefix: '10.1.1.0/24'
serviceEndpoints: []
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
]
virtualNetworkPeerings: []
enableDdosProtection: false
}
}
what have I done ?
I have tried to get around circular reference issues by creating the virtual network first, and referencing it using the example below.
instead of id: virtual_network_name_p2s_subnet.id I have changed it to
id: resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name ,p2s_subnet_name)
However I'm unsure as to how to deal with cases like
ipconfigurationId: '${p2s_vpn_name_resource.id}/ipConfigurations/default' when the virtual networ gateway has not been created, I have no way of knowing what the ipconfigurationID would be.
This leads to the error
This expression is referencing its own declaration, which is not allowed.bicep(BCP079)
Few things here,
You're defining the subnets multiple times: in the vnet resource and separately. You only need to define them once inside the vnet resource. As you suggested you could then reference them like that:
resourceId(rg, 'Microsoft.Network/virtualNetworks/subnets', virtual_network_name_resource.name ,p2s_subnet_name)
If you need to reference the same resource, you could always do it like that as well:
resourceId('Microsoft.Network/virtualNetworkGateways/ipConfigurations', p2s_vpn_name, 'default')
Here is is simplified version of your template:
param location string = resourceGroup().location
param virtual_network_name string = 'my_virtual_network'
param gwSubnetName string = 'myGatewaySubnet'
param public_ip_gateway string = 'my_public_ip'
param p2s_vpn_name string = 'myPoint_toSite'
param p2s_subnet_name string = 'p2s_subnet'
resource public_ip_gateway_resource 'Microsoft.Network/publicIPAddresses#2022-01-01' = {
name: public_ip_gateway
location: location
sku: {
name: 'Basic'
tier: 'Regional'
}
properties: {
ipAddress: '40.161.130.50'
publicIPAddressVersion: 'IPv4'
publicIPAllocationMethod: 'Dynamic'
idleTimeoutInMinutes: 4
ipTags: []
}
}
resource virtual_network_resource 'Microsoft.Network/virtualNetworks#2022-01-01' = {
name: virtual_network_name
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.2.0.0/16'
]
}
subnets: [
{
name: gwSubnetName
properties: {
addressPrefix: '10.2.255.0/25'
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
{
name: p2s_subnet_name
properties: {
addressPrefix: '10.1.1.0/24'
serviceEndpoints: []
delegations: []
privateEndpointNetworkPolicies: 'Disabled'
privateLinkServiceNetworkPolicies: 'Enabled'
}
type: 'Microsoft.Network/virtualNetworks/subnets'
}
]
virtualNetworkPeerings: []
enableDdosProtection: false
}
}
resource p2s_vpn_name_resource 'Microsoft.Network/virtualNetworkGateways#2022-01-01' = {
name: p2s_vpn_name
location: location
properties: {
enablePrivateIpAddress: false
ipConfigurations: [
{
name: 'default'
properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: public_ip_gateway_resource.id
}
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', virtual_network_resource.name, gwSubnetName)
}
}
}
]
natRules: []
enableBgpRouteTranslationForNat: false
disableIPSecReplayProtection: false
sku: {
name: 'VpnGw1'
tier: 'VpnGw1'
}
gatewayType: 'Vpn'
vpnType: 'RouteBased'
enableBgp: false
activeActive: false
vpnClientConfiguration: {
vpnClientAddressPool: {
addressPrefixes: [
'119.x.x.0/24'
]
}
vpnClientProtocols: [
'OpenVPN'
]
vpnAuthenticationTypes: [
'Certificate'
]
vpnClientRootCertificates: [
{
name: 'Rahman'
properties: {
publicCertData: 'xxxxxxxxxxx=='
}
}
]
vpnClientRevokedCertificates: []
radiusServers: []
vpnClientIpsecPolicies: []
}
bgpSettings: {
asn: 65515
bgpPeeringAddress: '10.2.255.126'
peerWeight: 0
bgpPeeringAddresses: [
{
ipconfigurationId: resourceId('Microsoft.Network/virtualNetworkGateways/ipConfigurations', p2s_vpn_name, 'default')
customBgpIpAddresses: []
}
]
}
customRoutes: {
addressPrefixes: []
}
vpnGatewayGeneration: 'Generation1'
}
}

Azure function app's signalr_extension is not populated to use in signalR upstreams when creating a function app by Bicep

I created an Azure Function App by Bicep and tried to get the signalr_extension's value to use in the "upstream" configuration section of a serverless Azure SignalR Service. This is how I try to obtain this value in Bicep:
var signalRKey = listKeys(resourceId('Microsoft.Web/sites/host', funcAppName, 'default'), '2022-03-01').systemkeys.signalr_extension
This is how I configure the signalR service's upstream:
urlTemplate: 'https://${funcAppName}.azurewebsites.net/runtime/webhooks/signalr?code=${signalRKey}'
Running the bicep templates leads to the failure below:
Encountered an error (ServiceUnavailable) from host runtime.
When I remove the {signalRKey} from urlTemplate and replace it with a fictitious hard-coded value, the signalR is provisioned successfully.
The other thing that I noticed was that the singalr_extension key value was not populated after the function app was provisioned.
What am I missing in this exercise?
This feature is not available and feasible in App Service Plans. The signalr_extension must be populated manually after deploying the function app and signalR.
The signalr_extension is only created once you've deployed your function app with a SignalRTrigger function.
You can generate this key upfront if you're deploying the Function App and signalR service at the same time:
param functionAppName string
// Create the function app key for signalR
resource signalRKey 'Microsoft.Web/sites/host/systemkeys#2021-03-01' = {
name: '${functionAppName}/default/signalr_extension'
properties: {
name: 'signalr_extension'
}
}
The ARM API to generate function keys is just pointing to the function app API so it could take some time before it become available (see issue on github).
I managed to get this working consistently by deploying the systemkey and signalr using module.
Also for function app running on linux, the AzureWebJobsStorage setting is mandatory.
functionapp-systemkey.bicep module:
param functionAppName string
param keyName string
resource signalRKey 'Microsoft.Web/sites/host/systemkeys#2021-03-01' = {
name: '${functionAppName}/default/${keyName}'
properties: {
name: keyName
}
}
signalr.bicep module:
param location string = resourceGroup().location
param signalRName string
param functionAppName string
resource signalR 'Microsoft.SignalRService/signalR#2022-02-01' = {
name: signalRName
location: location
sku: {
name: 'Free_F1'
tier: 'Free'
capacity: 1
}
properties: {
features: [
{
flag: 'ServiceMode'
value: 'Serverless'
}
{
flag: 'EnableConnectivityLogs'
value: 'true'
}
]
cors: {
allowedOrigins: [
'*'
]
}
tls: {
clientCertEnabled: false
}
upstream: {
templates: [
{
hubPattern: '*'
eventPattern: '*'
categoryPattern: '*'
auth: {
type: 'None'
}
urlTemplate: 'https://${signalRName}.azurewebsites.net/runtime/webhooks/signalr?code=${listKeys(resourceId('Microsoft.Web/sites/host', functionAppName, 'default'), '2022-03-01').systemkeys.signalr_extension}'
}
]
}
}
}
main.bicep:
param location string = resourceGroup().location
param storageName string
param appServicePlanName string
param functionAppName string
param signalRName string
resource storage 'Microsoft.Storage/storageAccounts#2021-09-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
}
}
resource appServicePlan 'Microsoft.Web/serverfarms#2021-03-01' = {
name: appServicePlanName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
size: 'Y1'
family: 'Y'
capacity: 0
}
kind: 'functionapp'
properties: {
perSiteScaling: false
elasticScaleEnabled: false
maximumElasticWorkerCount: 1
isSpot: false
reserved: true
isXenon: false
targetWorkerCount: 0
targetWorkerSizeId: 0
zoneRedundant: false
}
}
resource functionApp 'Microsoft.Web/sites#2021-03-01' = {
name: functionAppName
location: location
kind: 'functionapp,linux'
properties: {
serverFarmId: appServicePlan.id
clientAffinityEnabled: false
clientCertEnabled: false
httpsOnly: true
siteConfig:{
linuxFxVersion: 'DOTNET|6.0'
use32BitWorkerProcess: true
ftpsState: 'FtpsOnly'
cors: {
allowedOrigins: [
'https://portal.azure.com'
]
supportCredentials: false
}
minTlsVersion: '1.2'
appSettings: [
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet'
}
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${listKeys(storage.id, '2019-06-01').keys[0].value};EndpointSuffix=core.windows.net;'
}
]
}
}
}
var signalrKeyName = 'signalr_extension'
module signalrKey 'modules/functionapp-systemkey.bicep' = {
name: '${functionAppName}-systemkey-${signalrKeyName}'
params: {
functionAppName: functionApp.name
keyName: signalrKeyName
}
}
module signalr 'modules/signalr.bicep' = {
name: signalRName
params: {
location: location
functionAppName: functionApp.name
signalRName: signalRName
}
dependsOn:[
signalrKey
]
}

Bicep Template for Azure Automation Account. Azure Role assignment to Managed Identity problem

I have created a basic Bicep template to deploy Azure Automation Acount. It contains a Runbook with the Powershell script and the linked Schedule. So far so good. The problem is to assign the Azure Role (Owner, Contributor, Reader) to the Managed Identity of this AA. I have all the needed values but have no idea how to put them together. To assign Azure Role via Bicep Template you should get the principalId of your Managed Identity of this AA which is pretty easy:
resource autaccount 'Microsoft.Automation/automationAccounts#2021-06-22'
**************************************************************************
output AutAccountPrincipalId string = autaccount.identity.principalId
My idea was to pass the value from this output to the parameter or variable and then use it in the next resource block. It turned out I can not pass the output as the parameter to the next resource block. Can someone assist me with this? The question is - how to use the value from one Bicep resource block in the other resource block?
This is the Bicep template to create Automation Account:
#description('Specifies the location for all resources.')
param location string = resourceGroup().location
var accountname = 'Snapshot'
var runbookname = 'CreateSnapshot'
var schedulename = 'SnapshotHourly'
resource autaccount 'Microsoft.Automation/automationAccounts#2021-06-22' = {
name: accountname
location: location
tags: {
test: 'true'
}
identity: {
type: 'SystemAssigned'
}
properties: {
disableLocalAuth: false
encryption: {
identity: {
}
keySource: 'Microsoft.Automation'
}
publicNetworkAccess: false
sku: {
capacity: null
family: null
name: 'Basic'
}
}
}
resource runbook1 'Microsoft.Automation/automationAccounts/runbooks#2019-06-01' = {
parent: autaccount
name: runbookname
location: location
properties: {
runbookType: 'PowerShell'
logVerbose: false
logProgress: false
logActivityTrace: 0
publishContentLink: {
uri: 'https://raw.githubusercontent.com/................'
}
}
}
resource schedule1 'Microsoft.Automation/automationAccounts/schedules#2020-01-13-preview' = {
parent: autaccount
name: schedulename
properties: {
startTime: '23:30'
expiryTime: ''
interval: 1
frequency: 'Hour'
timeZone: 'Europe/Riga'
}
}
resource link 'Microsoft.Automation/automationAccounts/jobSchedules#2020-01-13-preview' = {
name: guid('xxx05')
parent: autaccount
dependsOn: [
runbook1
]
properties: {
parameters: {}
runbook: {
name: runbookname
}
schedule: {
name: schedulename
}
}
}
output AutAccountPrincipalId string = autaccount.identity.principalId
The last resource block which actually assigns the Azure Role to MI is as follows:
#description('The principal to assign the role to')
param principalId string = 'abc897c3-ac9a-42e6-bc3f-xxxxxxxxxxxx'
#description('Built-in role to assign')
#allowed([
'Owner'
'Contributor'
'Reader'
])
//param builtInRoleType string = 'Owner'
#description('A new GUID used to identify the role assignment')
param roleNameGuid string = newGuid()
var Owner = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635'
//var Contributor = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c'
//var Reader = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
resource roleassignment 'Microsoft.Authorization/roleAssignments#2020-08-01-preview' = {
name: roleNameGuid
properties: {
principalId: principalId
roleDefinitionId: Owner
}
}
I acquired the principalID value manually from Portal but to automate the thing need it to pass from the blocks above, from output above or by some other way. Can someone assist with that?
Thank you in advance!
The updated code is:
#description('Specifies the location for all resources.')
param location string = resourceGroup().location
var accountname = 'SnapshotMgmtv11'
var runbookname = 'Create11'
var schedulename = 'SnapshotHourly11'
resource autaccount 'Microsoft.Automation/automationAccounts#2021-06-22' = {
name: accountname
location: location
tags: {
test: 'true'
}
identity: {
type: 'SystemAssigned'
}
properties: {
disableLocalAuth: false
encryption: {
identity: {
}
keySource: 'Microsoft.Automation'
}
publicNetworkAccess: false
sku: {
capacity: null
family: null
name: 'Basic'
}
}
}
resource runbook1 'Microsoft.Automation/automationAccounts/runbooks#2019-06-01' = {
parent: autaccount
name: runbookname
location: location
properties: {
runbookType: 'PowerShell'
logVerbose: false
logProgress: false
logActivityTrace: 0
publishContentLink: {
uri: 'https://raw.githubusercontent.com/..................'
}
}
}
resource schedule1 'Microsoft.Automation/automationAccounts/schedules#2020-01-13-preview' = {
parent: autaccount
name: schedulename
properties: {
startTime: '08:30'
expiryTime: ''
interval: 1
frequency: 'Hour'
timeZone: 'Europe/Riga'
}
}
resource link 'Microsoft.Automation/automationAccounts/jobSchedules#2020-01-13-preview' = {
name: guid('riniv011')
parent: autaccount
dependsOn: [
runbook1
]
properties: {
parameters: {}
runbook: {
name: runbookname
}
schedule: {
name: schedulename
}
}
}
#description('A new GUID used to identify the role assignment')
param roleNameGuid string = newGuid()
//var Owner = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635'
var Contributor = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c'
//var Reader = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7'
resource roleassignment 'Microsoft.Authorization/roleAssignments#2020-08-01-preview' = {
name: roleNameGuid
dependsOn: [
autaccount
]
properties: {
principalId: autaccount.identity.principalId
roleDefinitionId: Contributor
}
}
If you are deploying role assignement for resource group scope then you can use the something like below:
I tested it for creating only automation account and assigning the owner role at resource group for the system assigned identity of the automation account.
param location string = resourceGroup().location
var accountname = 'Snapshot'
resource autaccount 'Microsoft.Automation/automationAccounts#2021-06-22' = {
name: accountname
location: location
tags: {
test: 'true'
}
identity: {
type: 'SystemAssigned'
}
properties: {
disableLocalAuth: false
encryption: {
identity: {
}
keySource: 'Microsoft.Automation'
}
publicNetworkAccess: false
sku: {
capacity: null
family: null
name: 'Basic'
}
}
}
param roleNameGuid string = guid('Owner')
var Owner = '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635'
resource roleassignment 'Microsoft.Authorization/roleAssignments#2020-08-01-preview' = {
name: roleNameGuid
properties: {
principalId: autaccount.identity.principalId
roleDefinitionId: Owner
principalType:'ServicePrincipal'
}
}
Output:
Update:
For the below error :
Please add the principalType:'ServicePrincipal' in the role assignment block , as I have updated in the above code.

Bicep: unable to set storage account to web app resource

I've some experience using Azure CLI, Az Module and ARM templates... Anyway I'm experimenting problems in setting a storage account to a web app.
This is the bicep source (still a work in progress):
#allowed([
'dev'
'qta'
'ppd'
'prd'
])
param targetEnv string = 'dev'
#allowed([
'southafricanorth'
'southafricawest'
'northeurope'
'westeurope'
'australiaeast'
'australiasoutheast'
'australiacentral'
'australiacentral2'
'eastasia'
'southeastasia'
'brazilsouth'
'brazilsoutheast'
'centralus'
'eastus'
'eastus2'
'westus'
'westus2'
'westus3'
'northcentralus'
'southcentralus'
])
param location string = 'westeurope'
param planName string = 'testplan1'
param planGroup string = 'rgdoftempdev'
var locationMap = {
'southafricanorth': 'af'
'southafricawest': 'af'
'northeurope': 'eu'
'westeurope': 'eu'
'australiaeast': 'pc'
'australiasoutheast': 'pc'
'australiacentral': 'pc'
'australiacentral2': 'pc'
'eastasia': 'as'
'southeastasia': 'as'
'brazilsouth': 'sa'
'brazilsoutheast': 'sa'
'centralus': 'us'
'eastus': 'us'
'eastus2': 'us'
'westus': 'us'
'westus2': 'us'
'westus3': 'us'
'northcentralus': 'us'
'southcentralus': 'us'
}
var locationAcr = locationMap[location]
// var hash = substring(uniqueString(subscription().subscriptionId), 0, 4)
var appName = 'bvdof'
var insightsName = '${appName}-appinsights-${locationAcr}-${targetEnv}'
var storageName = '${appName}sa${locationAcr}${targetEnv}'
var webAppName = '${appName}-webapp-${locationAcr}-${targetEnv}'
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-06-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku: {
name: 'Premium_LRS'
}
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: true
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
keySource: 'Microsoft.Storage'
services: {
blob: {
keyType: 'Account'
enabled: true
}
file: {
keyType: 'Account'
enabled: true
}
}
}
accessTier: 'Hot'
}
}
resource appInsights 'Microsoft.Insights/components#2020-02-02' = {
name: insightsName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
publicNetworkAccessForIngestion: 'Enabled'
publicNetworkAccessForQuery: 'Enabled'
}
}
resource webApplication 'Microsoft.Web/sites#2021-02-01' = {
dependsOn: [
appInsights
storageAccount
]
name: webAppName
location: resourceGroup().location
kind: 'app'
properties: {
httpsOnly: true
serverFarmId: '/subscriptions/${subscription().id}/resourceGroups/${planGroup}/providers/Microsoft.Web/serverfarms/${planName}'
clientAffinityEnabled: true
siteConfig: {
appSettings: [
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsights.properties.InstrumentationKey
}
// {
// name: 'AzureWebJobsDashboard'
// value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
// }
// {
// name: 'AzureWebJobsStorage'
// value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
// }
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageName};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
}
{
name: 'WEBSITE_CONTENTSHARE'
value: webAppName
}
{
name: 'ANCM_ADDITIONAL_ERROR_PAGE_LINK'
value: 'https://${webAppName}.scm.azurewebsites.net/detectors?type=tools&name=eventviewer'
}
{
name: 'APPINSIGHTS_PROFILERFEATURE_VERSION'
value: '1.0.0'
}
{
name: 'APPINSIGHTS_SNAPSHOTFEATURE_VERSION'
value: '1.0.0'
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: 'InstrumentationKey=${appInsights.properties.InstrumentationKey};IngestionEndpoint=https://${location}.in.applicationinsights.azure.com/'
}
]
}
}
}
This is the error I get after partially failed deployment (storage and app insights created):
{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"{\r\n \"Code\": \"BadRequest\",\r\n \"Message\": \"There was a conflict. The remote name could not be resolved: 'bvdofsaeudev.file.core.windows.net'\",\r\n \"Target\": null,\r\n \"Details\": [\r\n {\r\n \"Message\": \"There was a conflict. The remote name could not be resolved: 'bvdofsaeudev.file.core.windows.net'\"\r\n },\r\n {\r\n \"Code\": \"BadRequest\"\r\n },\r\n {\r\n \"ErrorEntity\": {\r\n \"ExtendedCode\": \"01020\",\r\n
\"MessageTemplate\": \"There was a conflict. {0}\",\r\n \"Parameters\": [\r\n \"The remote name could not be resolved: 'bvdofsaeudev.file.core.windows.net'\"\r\n ],\r\n \"Code\": \"BadRequest\",\r\n \"Message\": \"There was a conflict. The remote name could not be resolved: 'bvdofsaeudev.file.core.windows.net'\"\r\n }\r\n }\r\n ],\r\n \"Innererror\": null\r\n}"}]}}
What is wrong with this definition?
I tested your code and faced the same error as you can see below:
The error in the code is that you are using a Premium_LRS sku and kind is storageV2 . So , it doesn't create a File service in the Storage account only Blob service . For which reason , app is not able to find the remote name of the storage account file server.
There can be two solutions as below:
Just Changing the Sku name from Premium_LRS to Standard_LRS in the storage account resource as below:
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-06-01' = {
name: storageName
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: true
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
keySource: 'Microsoft.Storage'
services: {
blob: {
keyType: 'Account'
enabled: true
}
file: {
keyType: 'Account'
enabled: true
}
}
}
accessTier: 'Hot'
}
}
Output:
If you want to use Premium_LRS then Change the Kind to FileStorage instead of StorageV2 as below, so that it create a premium storage account with File service and not Blob service:
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-06-01' = {
name: storageName
location: location
kind: 'FileStorage'
sku: {
name: 'Premium_LRS'
}
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: true
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
keySource: 'Microsoft.Storage'
services: {
blob: {
keyType: 'Account'
enabled: true
}
file: {
keyType: 'Account'
enabled: true
}
}
}
accessTier: 'Hot'
}
}
Outputs:

Resources