Why does my BICEP template, fail to create authorization rules consistently? - azure

I've created a bicep template for deploying the Azure Service Bus which includes creation of multiple topics, subscriptions, filters, and authorisation rules.
I'm attempting to deploy 24 authorisation rules in a serial for loop after the rest of the servicebus has been created. The first time deployment will always fail with one or two authorisation rules returning with the error MessagingGatewayTooManyRequests or AuthorizationRuleNotFound. A subsequent deployment will always work as expected.
I have tried only using a template that only deploys authorisation rules, and have run into the same problem. The first 18 rules were created almost instantly, then after that they start to show as duplicated in the azure portal and fail.
I have found that I can get closer to my goal by splitting up the policies into multiple dependent deployments, which does slow down the request speed due to the physical overhead from creating a new deployment. I'd rather create a pure solution that is low effort, easy to maintain, and doesn't abuse the limitations of ARM deployments in order to succeed.
Please see the cut down version of my module below;
#description('The namespace of the servicebus resource')
param namespace string = 'myservicebus'
#description('An array of shared access policy configurations for service bus topics')
param sharedAccessPolicies array = [
{
topicName: 'mytopic'
policyName: 'listen-policy'
policyRights: ['Listen']
secretName: 'sb-mytopic-listen'
}
{
topicName: 'mytopic'
policyName: 'send-policy'
policyRights: ['Send']
secretName: 'sb-mytopic-send'
}
]
#batchSize(1)
resource topic_auth_rule 'Microsoft.ServiceBus/namespaces/topics/authorizationRules#2021-11-01' = [for policy in sharedAccessPolicies: {
name: '${namespace}/${policy.topicName}/${policy.policyName}'
properties: {
rights: policy.policyRights
}
}]
I've found a similar post around this issue which is what lead to my current solution. Although I don't understand why this single API endpoint is so aggressively rate limited.
Any advice on this would be much appreciated.

The above code in my question now works as expected. I spent the past month talking to multiple levels of Microsoft support, I managed to get in touch with the ARM team who looked into and resolved the problem.
The alternative solution which I was suggested was to individually register each resource and create a huge dependency chain, see example below.
resource topic_auth_rule_listen 'Microsoft.ServiceBus/namespaces/topics/authorizationRules#2021-11-01' = {
name: '${namespace}/mytopic/listen-policy'
properties: {
rights: [ 'Listen' ]
}
}
resource topic_auth_rule_send 'Microsoft.ServiceBus/namespaces/topics/authorizationRules#2021-11-01' = {
name: '${namespace}/mytopic/send-policy'
properties: {
rights: [ 'Send' ]
}
dependsOn: [ topic_auth_rule_listen ]
}
...

Related

Azure Bicep - What if command showing resource changes when deploying with the same template

I am new to using Azure bicep. I am trying to deploy a simple app service plan/app service with the following bicep file:
resource azBicepAsp1 'Microsoft.Web/serverfarms#2020-12-01' = {
name: 'test-dev-aue-asp1'
location: resourceGroup().location
kind: ''
sku: {
name: 'F1'
capacity: 1
}
}
resource azbicepas 'Microsoft.Web/sites#2021-01-15' = {
name: 'test-dev-aue-wapp1'
location: resourceGroup().location
properties: {
serverFarmId: resourceId('Microsoft.Web/serverfarms', 'test-dev-aue-asp1')
}
dependsOn:[
azBicepAsp1
]
}
using:
az deployment group create -g azbbicepad-dev-au-rg1 -f 2.AppServicePlan.bicep --confirm-with-what-if
It deploys sucesfully, however if I deploy it again with the exact same deployment it says the following changes will be made:
- Delete
+ Create
~ Modify
The deployment will update the following scope:
Scope: /subscriptions/71913b63-cacf-41bf-9da1-e3a1db24e62c/resourceGroups/azbbicepad-dev-au-rg1
~ Microsoft.Web/serverfarms/test-dev-aue-asp1 [2020-12-01]
- kind: "app"
~ sku.capacity: 0 => 1
~ Microsoft.Web/sites/test-dev-aue-wapp1 [2021-01-15]
+ properties.siteConfig.localMySqlEnabled: false
+ properties.siteConfig.netFrameworkVersion: "v4.6"
I don't quite understand why this occurs - could someone please point me in the right direction?
Thanks,
Regarding the app service plan:
if you specify Free tier, the capacity is always 0. When you deploy your template the first time, the capacity specified is ignored and set to 0. When you redeploy, there is a mismatch between what's defined in the template and the target resource.
If you dont specify the kind, the default is app. Same here, there is a mismatch between the template and the target resource.
There is a good explanation on this post.:
Noise
One issue you may see when using this command is noise, where the results show that a resource is being changed when no change will occur. This is usually down to the fact that the information you provide to the ARM API to create or update a resource is less than the data returned when querying it, or that defaults are being used. An example seen early in the preview was when deploying a storage account, if you did not specify the encryption settings in the template (so using the defaults), then What-If showed a change because it thought it was removing these settings.
This is something the ARM team is aware of and are working to remove during the preview. They are asking for everyone using this command to keep an eye out for these issues and log them in this Github issues log. Please do log issues when you see them to help improve this command and get it out of preview as soon as possible.

Azure Bicep - Connect Azure API Management (API) to Azure Function App

I can see within the Azure Management Console, specifically within the Azure API Management Service, via the GUI you are able to use Azure Functions to form an API.
I am trying to implement the same via Azure Bicep, but I do not see any options in the Bicep documentation for API Management - API Service.
In the GUI, I see something like this:
This allows me to specify my Function App:
However, within the Bicep Documentation, I don't see anything where I would expect to: Microsoft.ApiManagement service/apis
I have instead tried using the Microsoft.ApiManagement service/backends but that doesn't give the same experience and I haven't managed to get that to work.
So my question is, how do I connect my Azure API Management service to an Azure Site (app) which is set as a suite of Azure Functions?
You need to create backend and all api definitions manually. The portal gives you a nice creator and does all those REST calls for you. With bicep (and ARM) which is operating directly on the REST endpoints of each resource provider you need to build own solution.
Perhaps there’re somewhere some existing templates that can do this but personally I didn’t see any yet.
I added OpenAPI specifications to my functionApps to produce the sawgger \ -openAPI link (or file). Then leveraged the OpenAPI file to build the APIs.
// Create APIM Service
resource apimServiceRes 'Microsoft.ApiManagement/service#2021-08-01' = {
name: 'apim service name'
location: resourceGroup().location
sku:{
capacity: 0
name: 'select a sku'
}
identity:{
type: 'SystemAssigned'
}
properties:{
publisherName: 'your info'
publisherEmail: 'your info'
}
}
// Create the API Operations with:
resource apimApisRes 'Microsoft.ApiManagement/service/apis#2021-08-01' = {
name: '${apimServiceRes.name}/name-to-represent-your-api-set'
properties: {
format: 'openapi-link'
value: 'https://link to your swagger file'
path: ''
}
}

How can I adapt an existing resource with Azure Bicep?

I'm currently porting some infrastructure as code scripts from Azure CLI to Azure Bicep. Among many other things, the Bicep files should create a subnet and allow access from this subnet to an existing Azure SQL Server and an existing Storage Account.
For the SQL Server, this is simple - I can reference the existing server resource and declare a child resource representing the VNET rule:
resource azureSqlServer 'Microsoft.Sql/servers#2021-05-01-preview' existing = {
name: azureSqlServerName
resource vnetRule 'virtualNetworkRules' = {
name: azureSqlServerVnetRuleName
properties: {
virtualNetworkSubnetId: subnetId
}
}
}
However, with the Storage Account, the network rules are not child resources, but a property of the Storage Account resource (properties.networkAcls.virtualNetworkRules). I cannot declare all the details of the Storage Account in my Bicep file because that resource is way out of scope from the deployment I'm currently working on. In essence, I want to adapt the existing resource, just ensuring a single rule is present.
The following does not work because existing cannot be combined with properties:
resource storageAccount 'Microsoft.Storage/storageAccounts#2021-06-01' existing = {
name: storageAccountName
properties: {
networkAcls: {
virtualNetworkRules: [
{
id: subnetId
action: 'Allow'
}
]
}
}
}
Is there any way I can adapt just a tiny bit of an existing resource using Bicep?
UPDATE: I just realized you came from Azure CLI and was trying to find a way in bicep - sorry for not answering your actual question - anyway your post made me think about this in another way other than bicep, so my "answer" is what I came up with...
...sounds like we thought about this in the same manner; using bicep to pimp an existing Storage Account, granting a new subnet access. However I ended up using AzureCLI az storage account network-rule add
e.g.
newSubnet='/subscriptions/<subscr-guid>/resourceGroups/<rg-name-where-vnet-resides>/providers/Microsoft.Network/virtualNetworks/<vnet-name>/subnets/<subnet-name>'
az storage account network-rule add -g <rg-name-where-sa-resides> --account-name <storage-account-name> --subnet $newSubnet
run this from a terminal or put it in an AzureCLI task in a devops pipeline (which is what I needed)
The existing keyword in bicep is used to tell bicep that the resource already exists and you just want a symbolic reference to that resource in the code. If the resource doesn't exist it's likely that the the deployment will fail in some way.
Your first snippet is equivalent to:
resource vnetRule 'Microsoft.Sql/servers/virtualNetworkRules#2021-05-01-preview' = {
name: '${azureSqlServerName}/${azureSqlServerVnetRuleName}'
properties: {
virtualNetworkSubnetId: subnetId
}
}
In your second snippet since you want to update properties you have to provide the complete declaration of the resource, IOW you have to define and deploy the storageAccount. This isn't unique to bicep, it's the way the declarative model in Azure works.
That said, if you want to deploy to another scope in bicep, you can use a module with the scope property. E.g.
module updateStorage 'storage.bicep' = {
scope: resourceGroup(storageResourceGroupName)
name: 'updateStorage'
}
The downside is that you need to make sure you define/declare all the properties need for that storageAccount which is not ideal. There are some ways you can author around that, but if the storageAccount doesn't exist, the deployment is guaranteed to fail. For example, you could assert the storageAccount exists, fetch its properties and then union or modify the properties in the module. You might be able to make that work (depending on the extent of your changes) but it's a bit of an anti-pattern in a declarative model.
That help?

How to create Azure Front Door Standard/Premium with custom domain using Bicep?

In the classic Azure Front Door you can just point a DNS CNAME to your Front Door and validate it. In the new Azure Front Door Standard/Premium a CNAME must be validated using a TXT record on your DNS.
When creating a domain with a Bicep script in a build pipeline, the pipeline will run until terminated by timeout. The domain is, however, created. After that we would need to go in to the Azure Portal, get a validation value and put that into a TXT record in our DNS.
Is TXT record validation the only way and is how can this be done without the build pipeline timeouting?
The timeout cannot be avoided today due to a bug in ARM / Front Door.
According to these GitHub Issues, the issue should be resolved "in a few weeks".
https://github.com/Azure/bicep/issues/4483
https://github.com/Azure/bicep/issues/3568
https://github.com/MicrosoftDocs/azure-docs/issues/78229
They also contain some Bicep samples. I did not copy any code to the answer since it is not working at this point in time.
Solution for Constant Custom Domains
If you don't need to associate new domains on the fly, there is a viable solution because _dnsauth TXT validation for domain ownership must be performed only once. Using ARM template export and ARM to bicep converter az bicep decompile --file arm.json helped us to design this solution.
In our setup, we first linked the domain manually via Azure Portal and added it to bicep after successful validation. This way we can redeploy and update FrontDoor Standard/Premium via bicep without losing our manually added custom domain. For this, the resource in bicep must have the same name as the manually created domain as displayed in the endpoint manager:
resource myCustomDomain 'Microsoft.Cdn/profiles/customdomains#2021-06-01' = {
parent: profile
name: 'my-custom-domain-example-com'
properties: {
hostName: 'my-custom-domain.example.com'
tlsSettings: {
certificateType: 'ManagedCertificate'
minimumTlsVersion: 'TLS12'
}
}
}
In addition, the id of the custom domain must be added to each route that should be associated with it:
resource myRoute 'Microsoft.Cdn/profiles/afdEndpoints/routes#2020-09-01' = {
name: 'myRoute'
properties: {
customDomains: [
{
id: myCustomDomain.id
}
]
// ...
}
}
A Web Application Firewall (WAF) can be linked in the same way via security policy:
resource securityPolicy 'Microsoft.Cdn/profiles/securityPolicies#2020-09-01' = {
parent: profile
name: 'mySecurityPolicy'
properties: {
parameters: {
type: 'WebApplicationFirewall'
wafPolicy: {
id: myWafPolicy.id
}
associations: [
{
domains: [
{
id: endpoint.id // the default endpoint
},
{
id: myCustomDomain.id
}
]
patternsToMatch: [
'/*'
]
}
]
}
}
}

Setting the `customDomainVerificationId` property on an AppService in a Bicep deployment has no effect

I'm creating an App Service via Bicep, and trying to set the "Custom Domain Verification ID" property, so that I can setup the correct TXT records for verification (before the Bicep deployments run).
resource app_service 'Microsoft.Web/sites#2021-01-15' = {
name: name
location: location
properties: {
serverFarmId: plan_id
siteConfig: {
netFrameworkVersion: 'v4.6'
}
customDomainVerificationId: custom_domain_verification_id
}
}
But, the value I set isn't respected and will be something else under "Custom Domains" on the App Service.
Is this property meant to be read only?
Update
Seems like this might be a readonly property actually. It's the same across the entire Subscription, so makes sense that it can't be set on an individual AppService. Reported an issue here.
Yes, this property should be read only. It’s filled when app service is created.
If you don’t mind, please report this inaccuracy on https://aka.ms/bicep-type-issues

Resources