Unknow KeyVault access policy from Bicep - azure

I am trying to add KeyVault and access policy from Bicep, but it is adding unknown in the access policy. If I add the same from the portal it is correctly added.
param systemLabel string = 'developer-3'
param vaultName string = 'developer-3'
param location string = resourceGroup().location
param sku string = 'Standard'
param tenantId string = 'tenantId'
param objectId string = 'objectId'
#description('Tags that our resources need')
param tags object = {
displayName: 'keyvault-${toLower(systemLabel)}'
}
param enabledForDeployment bool = true
param enabledForTemplateDeployment bool = true
param enabledForDiskEncryption bool = true
param enableRbacAuthorization bool = false
param softDeleteRetentionInDays int = 90
resource keyvault 'Microsoft.KeyVault/vaults#2021-06-01-preview' = {
name: vaultName
location: location
tags: {
DisplayName: tags.displayName
}
properties: {
tenantId: tenantId
sku: {
family: 'A'
name: sku
}
accessPolicies: []
enabledForDeployment: enabledForDeployment
enabledForDiskEncryption: enabledForDiskEncryption
enabledForTemplateDeployment: enabledForTemplateDeployment
softDeleteRetentionInDays: softDeleteRetentionInDays
enableRbacAuthorization: enableRbacAuthorization
}
}
resource accessPolicies 'Microsoft.KeyVault/vaults/accessPolicies#2021-11-01-preview' = {
name: 'add'
parent: keyvault
properties: {
accessPolicies: [
{
tenantId: tenantId
objectId: objectId
permissions: {
secrets: [
'get'
'list'
]
}
}
]
}
}
The aim is to add both the keyvault and access policy from the Bicep.

#Thomas was right. I was using the wrong objectId though I copied the objectId from app registration service principle.
However, for anyone facing this issue. Add access policy to your keyvault from the portal (GUI) and then look for Export template in Automation section. The right object Id is there in the template.

Related

How can I create a resource group and add a key vault to it using Bicep?

I'm trying to create a resource group and add a key vault to it.
However, I'm not able to set the new resource group as a target resource group for the key vault.
How can I have the key vault assigned to the newly created resource group without creating a second Bicep module for it?
var loc = 'westus'
// outputs the newly created resource group
module rgCreate 'test.rg.bicep' = {
scope: subscription()
name: 'rgCreate'
params: {
rgLocation: loc
}
}
resource keyVault 'Microsoft.KeyVault/vaults#2021-10-01' = {
name: 'Test'
location: loc
properties: {
enabledForTemplateDeployment: true
sku: {
family: 'A'
name: 'standard'
}
tenantId: tenant().tenantId
}
}
This is the workflow I'm aiming at:
First, if the resource group does not exist, you can't have targetScope = 'resourceGroup' in the main.bicep file. The command az deployment group create will fail:
{"code": "ResourceGroupNotFound", "message": "Resource group '' could not be found."}
You could always trigger the deployment form another resource that already exists (Not sure if it s a good idea tho).
An approach could be to have you main.bicep invoking two modules: one for resource group creation, one for resource creation:
// =========== rg.bicep ===========
// Setting target scope
targetScope = 'subscription'
param name string
param location string
// Creating resource group
resource rg 'Microsoft.Resources/resourceGroups#2021-01-01' = {
name: name
location: location
}
// =========== resources.bicep ===========
param location string = resourceGroup().location
param keyVaultName string
...
//Deploying key vault
resource keyVault 'Microsoft.KeyVault/vaults#2021-10-01' = {
name: keyVaultName
location: location
properties: {
enabledForTemplateDeployment: true
sku: {
family: 'A'
name: 'standard'
}
tenantId: tenant().tenantId
}
}
// Deploying other resources
...
// =========== main.bicep ===========
// Setting target scope
targetScope = 'subscription'
// Parameters
param rgName string = 'test-rg'
param rgLocation string = 'westus'
param keyVaultName string
...
// Creating resource group
module rgModule 'rg.bicep' = {
scope: subscription()
name: '${rgName}-create'
params:{
name: rgName
location: rgLocation
}
}
// Deploying resources in the newly created resource
module resources 'resources.bicep' = {
name: '${rgName}-resources-deployment'
scope: resourceGroup(rgName)
dependsOn: [ rgModule ]
params: {
location: rgLocation
keyVaultName: keyVaultName
...
}
}
To be honest, you could just run az group create command before deploying your template it will make things simpler.

How do i create an access policy for my azure function with bicep?

I have a resource defined in my bicep file like this below, these are two of the resources in my file, i deploy an azure function with the test_resource below, this works fine.
resource test_resource 'Microsoft.Web/sites#2021-03-01' = {
name: resourceName
location: location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
httpsOnly: true
serverFarmId: appServicePlan_ResourceId
}
}
and i am attempting to create an access policy as shown below, however i get an error regard the objectId, is there a way to configure the access policy for the above resource, perharps i am passing the wrong id in
"Invalid value found at accessPolicies[0].ObjectId:
but i am passing the test_resource.id as shown in the keyvault_access_policy resource definition.
resource devops_keyvault 'Microsoft.KeyVault/vaults#2021-10-01' existing = {
name: keyVaultName
}
resource keyvault_access_policy 'Microsoft.KeyVault/vaults/accessPolicies#2021-10-01' = {
name: 'add'
parent: devops_keyvault
properties: {
accessPolicies: [
{
objectId: test_resource.id
permissions: {
'keys': []
'secrets': [
'list'
'get'
]
'certificates': [
'list'
'get'
]
}
tenantId: subscription().tenantId
}
]
}
}
Looking at the documentation:
objectId: The object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies.
In your case it should be the the principal ID of the managed identity:
objectId: test_resource.identity.principalId

How to pass CosmosDb SQL Account as bicep module parameter?

How would I create a cosmos db account and pass it as a parameter to a bicep module? I would like enhance this sample bicep script by moving the role definition and role assignment to a separate module.
Here is my attempt at creating a module (that compiles and creates a CosmosDBAccount with no errors):
//#description ('cosmosDbAccount')
//param cosmosDbAccount object
#description ('cosmosDbAccountId')
param cosmosDbAccountId string
#description ('cosmosDbAccountName')
param cosmosDbAccountName string
#description('iteration')
param it int
#description('Principal ID of the managed identity')
param principalId string
var roleDefId = guid('sql-role-definition-', principalId, cosmosDbAccountId)
var roleDefName = 'Custom Read/Write role-${it}'
var roleAssignId = guid(roleDefId, principalId, cosmosDbAccountId)
resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions#2021-06-15' = {
name: '${cosmosDbAccountName}/${roleDefId}'
properties: {
roleName: roleDefName
type: 'CustomRole'
assignableScopes: [
cosmosDbAccountId
]
permissions: [
{
dataActions: [
'Microsoft.DocumentDB/databaseAccounts/readMetadata'
'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*'
]
}
]
}
}
resource roleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments#2021-06-15' = {
name: '${cosmosDbAccountName}/${roleAssignId}'
properties: {
roleDefinitionId: roleDefinition.id
principalId: principalId
scope: cosmosDbAccountId
}
}
Here is my attempt at calling the module:
#batchSize(1)
module cosmosRole 'cosmosRole.bicep' = [for (princId, jj) in principals: {
name: 'cosmos-role-definition-and-assignment-${jj}'
params: {
// cosmosDbAccount: cosmosDbAccount
cosmosDbAccountId: cosmosDbAccount.id
cosmosDbAccountName: cosmosDbAccount.name
principalId: princId
it: jj
}
}]
As you can see, the original code uses cosmosDbAccount.id and I have replaced this with a string called cosmosDbAccountId. When I try un-comment the above code and pass the cosmosDbObject and use the original syntax ("cosmosDbAccount.id" and "cosmosDbAccount.name") I get this error
ERROR: ..."Deployment template validation failed: 'The template variable 'roleDefId' is not valid: The language expression property 'id' doesn't exist, available properties are 'apiVersion, location, tags, identity, kind, properties, condition, deploymentResourceLineInfo, existing, isConditionTrue, subscriptionId, resourceGroupName, scope, resourceId, referenceApiVersion, isTemplateResource, isAction, provisioningOperation'..
Questions:
I would prefer the original syntax (fewer parameters) inside my new module. How do I do this?
How do I confirm the script created the roleAssignment and roleDefinition? I cannot find these in the azure portal. When I use the bicep output statement they appear but I would like to see them using the portal web page.
Few things here.
Passing a resource type parameter is an experimental feature, you will have to enable it (see Proposal - simplifying resource referencing for more details)
Before deploying your bicep file, you will need to set this environment variable:
# powershell example
$env:BICEP_RESOURCE_TYPED_PARAMS_AND_OUTPUTS_EXPERIMENTAL="true"
It will still show errors in visual studio code but the deployment was successful.
Here is the modified module with a parameter of type resource:
param cosmosDbAccount resource 'Microsoft.DocumentDB/databaseAccounts#2021-11-15-preview'
param it int
param principalId string
var roleDefId = guid('sql-role-definition-', principalId, cosmosDbAccount.id)
var roleDefName = 'Custom Read/Write role-${it}'
var roleAssignId = guid(roleDefId, principalId, cosmosDbAccount.id)
resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions#2021-06-15' = {
name: '${cosmosDbAccount.name}/${roleDefId}'
properties: {
roleName: roleDefName
type: 'CustomRole'
assignableScopes: [
cosmosDbAccount.id
]
permissions: [
{
dataActions: [
'Microsoft.DocumentDB/databaseAccounts/readMetadata'
'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*'
]
}
]
}
}
resource roleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments#2021-06-15' = {
name: '${cosmosDbAccount.name}/${roleAssignId}'
properties: {
roleDefinitionId: roleDefinition.id
principalId: principalId
scope: cosmosDbAccount.id
}
}
In the main bicep file, we can then pass the cosmosDbAccount as a parameter:
#batchSize(1)
module cosmosRole 'cosmosRole.bicep' = [for (princId, jj) in principals: if (!empty(principals)) {
name: 'cosmos-role-definition-and-assignment-${jj}'
params: {
cosmosDbAccount: cosmosDbAccount
principalId: princId
it: jj
}
}]
This solution is still experimental and while running the az deployment group create, you will see this big warning:
WARNING: Resource-typed parameters and outputs in ARM are experimental, and should be enabled for testing purposes only. Do not enable this setting for any production usage, or you may be unexpectedly broken at any time!
If you don't want to pass two parameters, you could declare an existing resource in your module and just pass the cosmosDbAccountName parameter:
param cosmosDbAccountName string
param it int
param principalId string
var roleDefId = guid('sql-role-definition-', principalId, cosmosDbAccount.id)
var roleDefName = 'Custom Read/Write role-${it}'
var roleAssignId = guid(roleDefId, principalId, cosmosDbAccount.id)
resource cosmosDbAccount 'Microsoft.DocumentDB/databaseAccounts#2021-11-15-preview' existing = {
name: cosmosDbAccountName
}
resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions#2021-06-15' = {
name: '${cosmosDbAccount.name}/${roleDefId}'
properties: {
roleName: roleDefName
type: 'CustomRole'
assignableScopes: [
cosmosDbAccount.id
]
permissions: [
{
dataActions: [
'Microsoft.DocumentDB/databaseAccounts/readMetadata'
'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*'
]
}
]
}
}
resource roleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments#2021-06-15' = {
name: '${cosmosDbAccount.name}/${roleAssignId}'
properties: {
roleDefinitionId: roleDefinition.id
principalId: principalId
scope: cosmosDbAccount.id
}
}
You main file will look like that:
#batchSize(1)
module cosmosRole 'cosmos-module.bicep' = [for (princId, jj) in principals: if (!empty(principals)) {
name: 'cosmos-role-definition-and-assignment-${jj}'
params: {
cosmosDbAccountName: cosmosDbAccount.name
principalId: princId
it: jj
}
}]
Regarding your second question, if you navigate to your cosmos db account and then click on the export template button, you should be able to see the created roles and related assignments (I know it s not ideal...):

Azure bicep Pass Storage Account Connection String to Secret Keyvault loop issue

I have a the following bicep script to perform the following steps:
Create storage accounts based on code
create a key
encrypt storage account with the correct key
generate a secret connection string (storage account) into a key vault
The infra is splitted into 2 resource groups:
rg-shared => where the 2 key vault are (1 keyvault for key and GUID, and 1 keyvault for secrets (connection string)
rg-storage-account => where all the storage account get created
In azure bicep I have the following scripts:
Storage.bicep
param ManagedIdentityid string
param uri string
param kvname string
param keyvaultrg string = 'XXXX' //<== SHARED Resource Group
var keyVaultKeyPrefix = 'Key-Data-'
var storagePrefix = 'sthritesteur'
param tenantCodes array = [
'aabb'
'bbcc'
'ccdd'
]
// Create storage accounts
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-04-01' = [for tenantCode in tenantCodes: {
name: '${storagePrefix}${tenantCode}'
location: resourceGroup().location
kind: 'StorageV2'
sku: {
name: 'Standard_RAGRS'
}
// Assign the identity
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${ManagedIdentityid}':{}
}
}
properties: {
allowCrossTenantReplication: true
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
allowSharedKeyAccess: true
networkAcls: {
bypass: 'AzureServices'
virtualNetworkRules: []
ipRules: []
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
identity: {
// specify which identity to use
userAssignedIdentity: ManagedIdentityid
}
keySource: 'Microsoft.Keyvault'
keyvaultproperties: {
keyname: '${kvname}-${keyVaultKeyPrefix}${toUpper(tenantCode)}'
keyvaulturi:uri
}
services: {
file: {
keyType: 'Account'
enabled: true
}
blob: {
keyType: 'Account'
enabled: true
}
}
}
accessTier: 'Hot'
}
}]
resource storage_Accounts_name_default 'Microsoft.Storage/storageAccounts/blobServices#2021-04-01' = [ for (storageName, i) in tenantCodes :{
parent: storageAccount[i]
name: 'default'
properties: {
changeFeed: {
enabled: false
}
restorePolicy: {
enabled: false
}
containerDeleteRetentionPolicy: {
enabled: true
days: 7
}
cors: {
corsRules: []
}
deleteRetentionPolicy: {
enabled: true
days: 30
}
isVersioningEnabled: true
}
}]
module connectionString 'shared.bicep' = [for (storageName, i) in tenantCodes :{
scope: resourceGroup(keyvaultrg)
name: storageName
params: {
storageAccountString: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount[i].name};AccountKey=${listKeys(storageAccount[i].id, storageAccount[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
}
}]
keyvaultclient.bicep
param deploymentIdOne string = newGuid()
param deploymentIdTwo string = newGuid()
output deploymentIdOne string = '${deploymentIdOne}-${deploymentIdTwo}'
output deploymentIdTwo string = deploymentIdTwo
param storagerg string = 'XXXX' //<=== Storage Accounts Resource Groups
param sharedManagedIdentity string = 'mgn-identity-shared'
param keyvaultmain string = 'XXXX' //<=== KeyVault Name where to create GUID AND Keys
param tenantCodes array = [
'aabb'
'bbcc'
'ccdd'
]
var clientDataKeyPrefix = 'Key-Data-'
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities#2018-11-30' = {
name: sharedManagedIdentity
location: resourceGroup().location
}
resource keyVaultClients 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultmain
}
resource kvClientsKey 'Microsoft.KeyVault/vaults/keys#2021-06-01-preview' = [for code in tenantCodes: {
parent:keyVaultClients
name: '${keyVaultClients.name}-${clientDataKeyPrefix}${toUpper(code)}'
properties: {
keySize: 2048
kty: 'RSA'
// Assign the least permission
keyOps: [
'unwrapKey'
'wrapKey'
]
}
}]
resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies#2021-06-01-preview' = {
parent:keyVaultClients
name: 'add'
properties: {
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: managedIdentity.properties.principalId
permissions: {
// minimum required permission
keys: [
'get'
'unwrapKey'
'wrapKey'
]
}
}
]
}
}
resource clientLearnersGuid 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
parent:keyVaultClients
name: '${keyVaultClients.name}${tenant}'
properties: {
contentType: 'GUID Key'
value: '${deploymentIdOne}-${deploymentIdTwo}'
}
dependsOn:kvClientsKey
}]
module StorageAccount 'storage.bicep' = [for (storageName, i) in tenantCodes :{
scope: resourceGroup(storagerg)
name: storageName
params: {
ManagedIdentityid:managedIdentity.id
kvname:keyVaultClients.name
uri:keyVaultClients.properties.vaultUri
}
dependsOn:clientLearnersGuid
}]
shared.bicep
param keyvaultshared string = 'XXXX' //<=== Key Vault Where to Store the Storage Connection String Secret
param storageAccountString string
param tenantCodes array = [
'aabb'
'bbcc'
'ccdd'
]
resource keyVaultShared 'Microsoft.KeyVault/vaults#2021-06-01-preview' existing = {
name: keyvaultshared
}
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
parent:keyVaultShared
name: '${keyVaultShared.name}-test${tenant}'
properties:{
contentType: '${tenant} Storage Account Connection String'
value: storageAccountString
}
}]
Those script performs all the steps I needed based on the tenantCode. Which is just perfect. If I have only 1 tenantCode declared, everything goes smooth and perfect, but the issue I am facing raises when I try to declare more than 1. And this is the problem in details.
When I declare more than 1 code, the script still created all the resources I needed: Storage accounts,Keys,Encryptions, GUID and ConnectionStrings Secrets. But it fails anyway on the ConnectionStrings Secret.
The reason why it fails it because in those files at this block of code:
Shared.bicep
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for tenant in tenantCodes: {
parent:keyVaultShared
name: '${keyVaultShared.name}-test${tenant}'
properties:{
contentType: '${tenant} Storage Account Connection String'
value: storageAccountString
}
}]
and
keuvaultsclient.bicep*
module StorageAccount 'storage.bicep' = [for (storageName, i) in tenantCodes :{
scope: resourceGroup(storagerg)
name: storageName
params: {
ManagedIdentityid:managedIdentity.id
kvname:keyVaultClients.name
uri:keyVaultClients.properties.vaultUri
}
dependsOn:clientLearnersGuid
}]
I have a multiple loop, on which I realised that in my shared keyvault under secrets, I have the correct amount of secrets (with 3 tenant codes I have 3 secrets) and under each secret I have 3 versions (for each tenant code it generate a new version for each secret). This looping error causes bicep script to fail with the following message:
{"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":"Conflict","message":"{\r\n \"status\": \"Failed\",\r\n \"error\": {\r\n \"code\": \"ResourceDeploymentFailure\",\r\n \"message\": \"The resource operation completed with terminal provisioning state 'Failed'.\",\r\n \"details\": [\r\n {\r\n \"code\": \"DeploymentFailed\",\r\n \"message\": \"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.\",\r\n \"details\": [\r\n {\r\n \"code\": \"Conflict\",\r\n \"message\": \"{\\r\\n \\\"error\\\": {\\r\\n \\\"code\\\": \\\"StorageAccountOperationInProgress\\\",\\r\\n \\\"message\\\": \\\"An operation is currently performing on this storage account that requires exclusive access.\\\"\\r\\n }\\r\\n}\"\r\n },\r\n {\r\n \"code\": \"Conflict\",\r\n \"message\": \"{\\r\\n \\\"error\\\": {\\r\\n \\\"code\\\": \\\"StorageAccountOperationInProgress\\\",\\r\\n \\\"message\\\": \\\"An operation is currently performing on this storage account that requires exclusive access.\\\"\\r\\n }\\r\\n}\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n}"}]}}
I am totally blocked at this stage and as I am a bicep beginner, I run out of all options and test to try to solve this issue.
How to reproduce
Create 2 resource groups(one for the key vaults and one for the storage accounts)
Update parameters with the correct kv names
In all files add atleast 2 tenantCode on each file
execute the command az deployment group create -f ./keyvaultsclient.bicep -g <rg-where-keyvaults-are>
I hope I explained clearly enough the issue I am facing and please if you need more details just let me know.
Thank you so much for your time and help
I tested the same code by doing some changes, Please try doing the same changes in the .bicep files :
keyvaultclient.bicep:
Removed the loop for module as its creating 2 modules for the same thing.
module StorageAccount './storage.bicep' = {
scope: resourceGroup(storagerg)
name: 'NestedStorage'
params: {
ManagedIdentityid:managedIdentity.id
kvname:keyVaultClients.name
uri:keyVaultClients.properties.vaultUri
}
dependsOn:clientLearnersGuid
}
storage.bicep:
Removed the loop for module and added the loop for only storage connection string which will store the outputs in array and pass it to the next module.
module connectionString './shared.bicep'={
scope: resourceGroup(keyvaultrg)
name: 'KeyvaultNested'
params: {
storageAccountString: [for (tenant,i) in tenantCodes :{
id:'DefaultEndpointsProtocol=https;AccountName=${storageAccount[i].name};AccountKey=${listKeys(storageAccount[i].id, storageAccount[i].apiVersion).keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
}]
}
}
shared.bicep:
Changed the parameter type of StorageAccountString from string to array and added [for (tenant,i) in tenantCodes in the secret part so that I can give the value as storageAccountString[i].id .
param storageAccountString array
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets#2021-06-01-preview' = [for (tenant,i) in tenantCodes: {
parent:keyVaultShared
name: '${keyVaultShared.name}-test${tenant}'
properties:{
contentType: '${tenant} Storage Account Connection String'
value: storageAccountString[i].id
}
}]
Outputs:

Assign ManagedID to KeyVault Access Policy

I have a bicep template that creates 2 webApps and a KeyVault. Each WebApp is created with a managedID which I need to add to Keyvault so the webapp can pull in the secrets.
But when creating 2 webapps, I can't work out how to assign both ManagedIDs to KeyVault.
The bicep template is using modules
name: 'ciKeyVault'
params: {
keyVaultName: keyVaultName
aclBypass: keyVaultSettings.aclBypass
aclDefaultAction: keyVaultSettings.aclDefaultAction
enabledForDeployment: keyVaultSettings.enabledForDeployment
enabledForDiskEncryption: keyVaultSettings.enabledForDiskEncryption
enabledForTemplateDeployment: keyVaultSettings.enabledForTemplateDeployment
keyPermissions: keyVaultSettings.keyPermissions
keyVaultSettings: keyVaultSettings
secretsPermissions: keyVaultSettings.secretsPermissions
skuFamily: keyVaultSettings.skuFamily
skuName: keyVaultSettings.skuName
tenantId: subscription().tenantId
objectId: 'b71e61c4-7cff-41d0-8370-a7d9c01dde84'
}
}
and the objectId needs to be retrieved from the AppService Deployment. using this module:
module AppService '../../../Modules/Azure.App.Service.template.bicep' = [for i in range(0, length(webAppSettings.webApps)): {
name: webAppSettings.webApps[i].Name
dependsOn: [
frontEndAppServicePlan
]
params: {
webAppName: webAppSettings.webApps[i].appServiceType == 'functionApp' ? toLower('fnc-${webAppSettings.webApps[i].name}-${resourceGroupNameSuffix}') : toLower('web-${webAppSettings.webApps[i].name}-${resourceGroupNameSuffix}')
hostingPlan: frontEndAppServicePlan.outputs.hostingPlanId
virtualNetworkResourceGroup: virtualNetworkResourceGroup
environmentName:environmentName
webAppSettings:webAppSettings
appServiceType: webAppSettings.webApps[i].appServiceType
LinuxFX:webAppSettings.webApps[i].LinuxFX
appSettings:webAppSettings.webapps[i].appSettings
}
}]
Its fine when its a single appService cause I can reference the ID using output usid string = AppServices.identity.principalId
but when I have 2 appServices I can't work out how to pass in both IDs
Any ideas?
Cheers
Let's say you have a module Azure.App.Service.template.bicep that looks like that:
param webAppName string
...
// Create the web app
resource webApp 'Microsoft.Web/sites#2020-09-01' = {
name: webAppName
location: resourceGroup().location
identity: {
type: 'SystemAssigned'
}
...
}
output usid string = webApp.identity.principalId
In the parent template you can create an array of module to create your webapps (the same way you are doing it) and then create an access policies resource to grant access to key vault to all the web apps.
...
// Create the app services
module AppServices '../../../Modules/Azure.App.Service.template.bicep' = [for webApp in webAppSettings.webApps: {
name: webApp.Name
params: {
webAppName: webApp.Name
...
}
}]
// Granting the app services access ot key vault
resource appServicesKeyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies#2019-09-01' = {
name: '${keyVaultName}/add'
properties: {
accessPolicies: [for i in range(0, length(webAppSettings.webApps)): {
tenantId: subscription().tenantId
objectId: AppServices[i].outputs.usid
permissions: {
secrets: keyVaultSettings.secretsPermissions
keys: keyVaultSettings.keyPermissions
}
}]
}
}

Resources