Api connections(keyvault, servicebus and blob ) using managed identity through bicep - azure

Hi I am trying to create API connections for Key Vault, service bus and storage account using bicep. unfortunately do not see clear documentation from Microsoft side.
created API connections(Azure Key Vault, Service Bus and storage account) using below code, deployment going successfully but connection gets into error state.
resource ServicebusApiCon 'Microsoft.Web/connections#2016-06-01' = {
name: 'servicebus'
location: Location
kind: 'V2'
properties: {
displayName: 'servicebus'
api: {
name: 'servicebus'
description: 'Connect to Azure Serice Bus to send and receive messages'
id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/
locations/${Location}/managedApis/servicebus'
type: 'Microsoft.Web/locations/managedApis'
}
}
}
resource keyvaultApiCon 'Microsoft.Web/connections#2016-06-01' = {
name: 'keyvault'
location: Location
kind: 'V2'
properties: {
displayName: 'keyvault'
api:{
id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/
locations/${Location}/managedApis/keyvault'
displayName: ' Azure key vault'
type: 'Microsoft.Web/locations/managedApis'
}
}
}
resource blobApiConnection 'Microsoft.Web/connections#2016-06-01' = {
name: 'azureblob'
location: Location
kind: 'V2'
properties: {
displayName: 'azureblob'
api: {
name: 'azureblob'
displayName: 'Azure Blob storage'
id: '/subscriptions/${subscription().subscriptionId}/providers
/Microsoft.Web/locations/${Location}/managedApis/azureblob'
}
}
}
could you please suggest me if i am doing something wrong or missing something

To be honest these connection apis are not documented at all...
Your best shot is to create them from Azure portal with the networking tab open so you can see what are the requests sent:
From there I was able to create connection for
key vault:
param logicAppName string
param location string = resourceGroup().location
param keyVaultName string
param name string = 'keyvault'
// Get a reference to the existing logic app
resource logicApp 'Microsoft.Web/sites#2021-03-01' existing = {
name: logicAppName
}
resource keyvaultConnector 'Microsoft.Web/connections#2018-07-01-preview' = {
name: name
location: location
kind: 'V2'
properties: {
displayName: name
parameterValueType: 'Alternative'
alternativeParameterValues: {
vaultName: keyVaultName
}
api: {
id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/keyvault'
type: 'Microsoft.Web/locations/managedApis'
}
}
}
// Grant permission to the logic app standard to access the connection api
resource keyvaultConnectorAccessPolicy 'Microsoft.Web/connections/accessPolicies#2018-07-01-preview' = {
name: '${keyvaultConnector.name}/${logicAppName}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: subscription().tenantId
objectId: logicApp.identity.principalId
}
}
}
}
output connectionRuntimeUrl string = reference(keyvaultConnector.id, keyvaultConnector.apiVersion, 'full').properties.connectionRuntimeUrl
service bus:
param logicAppName string
param location string = resourceGroup().location
param servicebusName string
param name string = 'servicebus'
// Get a reference to the existing logic app
resource logicApp 'Microsoft.Web/sites#2021-03-01' existing = {
name: logicAppName
}
resource servicebusConnector 'Microsoft.Web/connections#2018-07-01-preview' = {
name: name
location: location
kind: 'V2'
properties: {
api: {
id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/servicebus'
}
displayName: name
parameterValueSet: {
name: 'managedIdentityAuth'
values: {
namespaceEndpoint: {
value: 'sb://${servicebusName}.servicebus.windows.net/'
}
}
}
}
}
// Grant permission to the logic app standard to access the connection api
resource servicebusConnectorAccessPolicy 'Microsoft.Web/connections/accessPolicies#2018-07-01-preview' = {
name: '${servicebusConnector.name}/${logicAppName}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: subscription().tenantId
objectId: logicApp.identity.principalId
}
}
}
}
output connectionRuntimeUrl string = reference(servicebusConnector.id, servicebusConnector.apiVersion, 'full').properties.connectionRuntimeUrl
You still need to grant permissions to the managed identity to access key vault or servicebus.
You also will need to update the connectionRuntimeUrl so probably create an app setting for that so it s easier to update:

Related

Give access to Azure Logic App in a CICD pipeline to connect to a service bus topic with managed identity

I am trying to get a logic app to read messages from a service bus topic. I am getting the error with the connection in logic app designer as :
Could not retrieve values. Error code: 'Unauthorized', Message: 'The remote server returned an error: (401) Unauthorized. Manage,EntityRead claims required for this operation. TrackingId:, SystemTracker:, Timestamp: clientRequestId: '. More diagnostic information: x-ms-client-request-id is ''.
currently I have tried the following in my cicd pipeline:
Grant permission to the logic app standard to access the connection api
resource servicebusConnectorAccessPolicy 'Microsoft.Web/connections/accessPolicies#2018-07-01-preview' = {
name: '${servicebusConnector.name}/${logicAppName}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: subscription().tenantId
objectId: logicApp.identity.principalId
}
}
}
}
Get this error:
ERROR: {"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 "error": {\r\n "code": "InvalidTemplate",\r\n "message": "Unable to process template language expressions for resource '/subscriptions//resourceGroups//providers/Microsoft.Web/connections/servicebus/accessPolicies/' at line '124' and column '5'. 'The language expression property 'principalId' doesn't exist, available properties are 'type, userAssignedIdentities'.'",\r\n "additionalInfo": [\r\n {\r\n "type": "TemplateViolation",\r\n "info": {\r\n "lineNumber": 124,\r\n "linePosition": 5,\r\n "path": ""\r\n }\r\n }\r\n ]\r\n }\r\n}"}]}}
also:
resource logicAppServiceBusRoleAssignment 'Microsoft.Authorization/roleAssignments#2020-10-01-preview' = {
scope: serviceBusNamespace
name: guid('${serviceBusNamespaceName}-${roleDefinitionId}')
properties: {
principalType: 'ServicePrincipal'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
principalId: logicApp.identity.principalId
}
}
which yields this error:
ERROR: {"code": "InvalidTemplateDeployment", "message": "The template deployment failed with error: 'Authorization failed for template resource '' of type 'Microsoft.Authorization/roleAssignments'. The client '' with object id '' does not have permission to perform action 'Microsoft.Authorization/roleAssignments/write' at scope '/subscriptions//resourceGroups//providers/Microsoft.ServiceBus/namespaces//providers/Microsoft.Authorization/roleAssignments/'.'."}
for the role, it lacks permissions to add the role.
my logic app bicep file is as follows:
param logicAppName string // The name of the logic app to create.
param location string //Location for all resources.
param workflowDefinition object // the workflow schema in json
param connectorName string
param serviceBusNamespaceName string
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities#2022-01-31-preview' = {
name: <managedIDname>
location: location
}
resource servicebusConnector 'Microsoft.Web/connections#2016-06-01' = {
name: connectorName
location: location
kind: 'V2'
properties: {
api: {
id: concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/servicebus')
}
displayName: connectorName
parameterValueSet: {
name: 'managedIdentityAuth'
values: {
namespaceEndpoint: {
value: '<endpoint>'
}
}
}
}
}
resource logicApp 'Microsoft.Logic/workflows#2019-05-01' = {
name: logicAppName
location: location
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
tags: {
displayName: logicAppName
}
properties: {
state: 'Enabled'
definition: workflowDefinition.definition
parameters: workflowDefinition.parameters
}
}
and for the service bus I have the following code:
param serviceBusNamespaceName string //Name of the Service Bus namespace
param serviceBusQueueName string // Name of the Queue
param location string // Location for all resources.
param topicApprovalName string // name of the topic for approval
param topicApprovalSubscriptionName string // name of the topic subscription
param connectorName string // name of the connector
param logicAppName string
param roleDefinitionId string = '8e3af657-a8ff-443c-a75c-2fe8c4bcb635'
resource logicApp 'Microsoft.Logic/workflows#2019-05-01' existing = {
name: logicAppName
}
resource lamanagedidentity 'Microsoft.ManagedIdentity/userAssignedIdentities#2022-01-31-preview' existing = {
name: 'managedIdentity'
}
resource serviceBusNamespace 'Microsoft.ServiceBus/namespaces#2022-01-01-preview' = {
name: serviceBusNamespaceName
location: location
sku: {
name: 'Standard'
}
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${lamanagedidentity.id}': {}
}
}
properties: {}
}
resource serviceBusQueue 'Microsoft.ServiceBus/namespaces/queues#2022-01-01-preview' = {
parent: serviceBusNamespace
name: serviceBusQueueName
properties: {
lockDuration: 'PT5M'
maxSizeInMegabytes: 1024
requiresDuplicateDetection: false
requiresSession: false
defaultMessageTimeToLive: 'P10675199DT2H48M5.4775807S'
deadLetteringOnMessageExpiration: false
duplicateDetectionHistoryTimeWindow: 'PT10M'
maxDeliveryCount: 10
autoDeleteOnIdle: 'P10675199DT2H48M5.4775807S'
enablePartitioning: false
enableExpress: false
}
}
resource topic 'Microsoft.ServiceBus/namespaces/topics#2021-11-01' = {
name: topicApprovalName
parent: serviceBusNamespace
}
resource topicsubscription 'Microsoft.ServiceBus/namespaces/topics/subscriptions#2022-01-01-preview' = {
name: topicApprovalSubscriptionName
parent: topic
}
resource sbNamespaceAuthRules 'Microsoft.ServiceBus/namespaces/AuthorizationRules#2022-01-01-preview' = {
name: <auth name>
parent: serviceBusNamespace
properties: {
rights: [
'Listen'
'Manage'
'Send'
]
}
}
resource servicebusConnector 'Microsoft.Web/connections#2018-07-01-preview' = {
name: connectorName
location: location
kind: 'V2'
properties: {
api: {
id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/servicebus'
}
displayName: connectorName
parameterValueSet: {
name: <name>
values: {
namespaceEndpoint: {
value: '<endpoint>'
}
}
}
}
}
// Grant permission to the logic app standard to access the connection api
resource servicebusConnectorAccessPolicy 'Microsoft.Web/connections/accessPolicies#2018-07-01-preview' = {
name: '${servicebusConnector.name}/${logicAppName}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: subscription().tenantId
objectId: logicApp.identity.principalId
}
}
}
}
//output connectionRuntimeUrl string = reference(servicebusConnector.id, servicebusConnector.apiVersion, 'full').properties.connectionRuntimeUrl
Not sure why this isn't working... the issue that I'm landing on is the object id of this:
resource servicebusConnectorAccessPolicy 'Microsoft.Web/connections/accessPolicies#2018-07-01-preview' = {
name: '${servicebusConnector.name}/${logicAppName}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: subscription().tenantId
objectId: logicApp.identity.principalId
}
}
}
}
any help or advice would be welcome, I've been bashing my head against this for three days, and it just won't work.
thank you very much
I tried using a keyvault and connecting with a primary connection string, this did not work.
I have tried managed identity and roles, but both are not working for me.
it can find the connection, but gives an access error as cited above.
I was expecting for the connection to be authorized and for there to not be an error with the access policy.

How to reference System Assigned Identity in Bicep when deploying Key Vault Access Policy

For a project I want to deploy three related resources to Azure through Bicep templates: 1) App Service with System Assigned Managed Identity, 2) Key Vault and 3) Access policy for the App Service (step 1) to the Key Vault (step 2).
The AppService deployment outputs the principalId of the System Assigned Identity which is then later on used when deploying the KeyVaultAccessPolicy.
However, when I run the AZ CLI (az deployment sub create --location WestEurope --template-file ./main.bicep --parameters ./parameters/parameters-dev.json)
to deploy this to Azure I get the following error:
'The language expression property 'outputs' doesn't exist, available properties are 'templateHash, parameters, mode, provisioningState, timestamp, duration, correlationId, providers, dependencies, outputResources'.
Does anyone have an idea why referencing the principalId of the App Service does not work here? Many thanks for any help.
Modules and main.bicep:
main.bicep
module appService 'modules/appService.bicep' = {
name: 'deployAppService'
scope: resourceGroup(appServiceResourceGroup)
params: {
name: appServiceName
location: appServiceLocation
alwaysOn: appServiceAlwaysOn
apimIpAddress: appServiceApimIpAddress
appServicePlanResourceGroup: appServicePlanResourceGroup
appServicePlanName: appServicePlanName
}
}
module keyVault 'modules/keyVault.bicep' = {
name: 'deployKeyVault'
scope: resourceGroup(appServiceResourceGroup)
params: {
name: keyVaultName
dependsOn: [ appService ]
location: appServiceLocation
}
}
module keyVaultAccessPolicy 'modules/keyVaultAccessPolicy.bicep' = {
name: 'deployKeyVaultAccessPolicy'
scope: resourceGroup(appServiceResourceGroup)
params: {
name: '${appServiceName}-ap'
dependsOn: [ keyVault ]
objectId: appService.outputs.appServiceManagedIdentity
}
}
appService.bicep
resource appService 'Microsoft.Web/sites#2020-12-01' = {
name: name
location: location
kind: 'app'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: '${subscription().id}/resourceGroups/${appServicePlanResourceGroup}/providers/Microsoft.Web/serverfarms/${appServicePlanName}'
enabled: true
}
}
output appServiceManagedIdentity string = appService.identity.principalId
keyVault.bicep
resource keyVault 'Microsoft.KeyVault/vaults#2022-07-01' = {
name: name
location: location
dependsOn: dependsOn
properties: {
enabledForDeployment: true
enabledForTemplateDeployment: true
enabledForDiskEncryption: true
tenantId: subscription().tenantId
accessPolicies: []
sku: {
name: 'standard'
family: 'A'
}
}
}
keyVaultAccessPolicy.bicep
resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies#2022-07-01' = {
name: name
dependsOn: dependsOn
properties: {
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: objectId
permissions: {
secrets: [
'get'
]
}
}
]
}
}
Already found the answer:
I missed that modules already contain an dependsOn property and so there is no need to pass the dependencies as param.
The KeyVaultAccessPolicy's name did not contain a reference to the parent resource (KeyVault), see name: '${keyVaultName}/add' below
See working modules and main.bicep below:
main.bicep
module appService 'modules/appService.bicep' = {
name: 'deployAppService'
scope: resourceGroup(appServiceResourceGroup)
params: {
name: appServiceName
location: appServiceLocation
alwaysOn: appServiceAlwaysOn
apimIpAddress: appServiceApimIpAddress
appServicePlanResourceGroup: appServicePlanResourceGroup
appServicePlanName: appServicePlanName
}
}
module keyVault 'modules/keyVault.bicep' = {
scope: resourceGroup(appServiceResourceGroup)
name: 'keyVaultDeploy'
params: {
location: appServiceLocation
name: keyVaultName
}
}
module keyVaultAccessPolicy 'modules/keyVaultAccessPolicy.bicep' = {
scope: resourceGroup(appServiceResourceGroup)
name: 'keyVaultAccessPolicyDeploy'
dependsOn: [
keyVault
]
params: {
keyVaultName: keyVaultName
objectId: appService.outputs.appServiceManagedIdentity
}
}
appService.bicep
resource appService 'Microsoft.Web/sites#2020-12-01' = {
name: name
location: location
kind: 'app'
identity: {
type: 'SystemAssigned'
}
properties: {
// left out
}
}
output appServiceManagedIdentity string = appService.identity.principalId
keyVault.bicep
resource keyVault 'Microsoft.KeyVault/vaults#2022-07-01' = {
name: name
location: location
properties: {
enabledForDeployment: true
enabledForTemplateDeployment: true
enabledForDiskEncryption: true
tenantId: subscription().tenantId
accessPolicies: []
sku: {
name: 'standard'
family: 'A'
}
}
}
keyVaultAccessPolicy.bicep
resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies#2022-07-01' = {
name: '${keyVaultName}/add'
properties: {
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: objectId
permissions: {
secrets: [
'get'
]
}
}
]
}
}
Just for a heads up you don't need to pass these stuffs with parameters.
Just use the existing tag with the scope it will be easier to get datafrom any resource.
https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/existing-resource#different-scope

logic app connection to storage account failing

I have created logic app storage connection using below code but unfortunately it is throwing error.
resource blobConnector 'Microsoft.Web/connections#2018-07-01-preview' = {
name: 'apic-d365-azureblob12345'
location: Location
kind: 'V2'
properties: {
alternativeParameterValues: {}
api: {
id: 'subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${Location}/managedApis/azureblob'
}
customParameterValues: {}
displayName: 'azureblob'
parameterValueSet: {
name: 'managedIdentityAuth'
values: {}
}
}
}
Role assignment:
resource blobcontributorroleassignment 'Microsoft.Authorization/roleAssignments#2020-10-01-preview' = {
name: guid(resourceGroup().id, logicappsite.id, blobcontributorroledefination.id)
properties: {
roleDefinitionId: blobcontributorroledefination.id
principalType: 'ServicePrincipal'
principalId: logicappsite.identity.principalId
}
}
below is the error it is throwing while making connection
"error": "'Operation not supported with AAD authentication, use Azure Storage Account name/key connection instead
Could someone help me if I am missing something or doing wrong.
Thanks in advance.
You also need to create an access policy to allow the logic app to access the connection api:
// Grant permission to the logic app standard to access the connection api
resource blobConnectorAccessPolicy 'Microsoft.Web/connections/accessPolicies#2018-07-01-preview' = {
name: '${blobConnector.name}/${logicappsite.name}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: subscription().tenantId
objectId: logicappsite.identity.principalId
}
}
}
}

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
]
}

How to define identity based data access in the bicep template

I have the below as the bicep template, I want to use the identity based connection, how can I build the template accordingly.
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference#connecting-to-host-storage-with-an-identity
I used the guidance here https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/quickstart-create-bicep-use-visual-studio-code?tabs=PowerShell , for deployment.
New-AzResourceGroup -Name exampleRG -Location eastus
New-AzResourceGroupDeployment -ResourceGroupName exampleRG -TemplateFile ./main.bicep -storageName "{your-unique-name}"
But, I am getting error while addressing the template file - Code=InvalidTemplateDeployment; Message=The template deployment 'bicepeg' is
not valid according to the validation procedure
var baseName = uniqueString('identityRepro', subscription().id)
var location = 'uksouth'
resource stg 'Microsoft.Storage/storageAccounts#2019-06-01' = {
name: baseName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
resource asp 'Microsoft.Web/serverfarms#2019-08-01' = {
name: baseName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
}
}
resource ai 'Microsoft.Insights/components#2015-05-01' = {
name: baseName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
}
}
resource fa 'Microsoft.Web/sites#2019-08-01' = {
name: baseName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: asp.id
}
kind: 'functionapp'
resource appSettings 'config#2018-11-01' = {
name: 'appsettings'
properties: {
'AzureWebJobsStorage__accountName': stg.name
'FUNCTIONS_WORKER_RUNTIME': 'powershell'
'FUNCTIONS_WORKER_RUNTIME_VERSION': '~7'
'APPINSIGHTS_INSTRUMENTATIONKEY': ai.properties.InstrumentationKey
}
}
}
resource blobContrib 'Microsoft.Authorization/roleAssignments#2020-04-01-preview' = {
name: guid(fa.name, stg.name, 'ba92f.........d-a403-e96b0029c9fe')
properties: {
principalId: fa.identity.principalId
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'ba92f.......-a403-e96b0029c9fe')
principalType: 'ServicePrincipal'
}
scope: stg
}
I think your problem is the id of the role. Roles are defined at subscription level, not in resource group. In your code instead resourceId function use subscriptionResourceId.
Update: as you clarified more on github issue, your additional problem was how the name is being constructed. uniqueString function generate an pseudo-random string (a hash) based on the seed - the parameters you provide to the function. when you give exactly this same values - you will get this same result.
Below code is working for me
var baseName = uniqueString(resourceGroup().id)
var location = 'uksouth'
resource stg 'Microsoft.Storage/storageAccounts#2019-06-01' = {
name: baseName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
resource asp 'Microsoft.Web/serverfarms#2019-08-01' = {
name: baseName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
}
}
resource ai 'Microsoft.Insights/components#2015-05-01' = {
name: baseName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
}
}
resource fa 'Microsoft.Web/sites#2019-08-01' = {
name: baseName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: asp.id
}
kind: 'functionapp'
resource appSettings 'config#2018-11-01' = {
name: 'appsettings'
properties: {
'AzureWebJobsStorage__accountName': stg.name
'FUNCTIONS_WORKER_RUNTIME': 'powershell'
'FUNCTIONS_WORKER_RUNTIME_VERSION': '~7'
'APPINSIGHTS_INSTRUMENTATIONKEY': ai.properties.InstrumentationKey
}
}
}
resource blobContrib 'Microsoft.Authorization/roleAssignments#2020-04-01-preview' = {
name: guid(fa.name, stg.name, 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
properties: {
principalId: fa.identity.principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
principalType: 'ServicePrincipal'
}
scope: stg
}
In your code use resourceGroup().id as uniqueString parameter - as it contains unique guid of your subscription and a resource group name, which has to be unique in the subscription - your hash also should be unique. providing only subscription().id will generate same string for all deployments to that subscription and resource group in it.

Resources