Action Groups to Resource Owners - azure

When creating an Action Group on the Azure Portal, you have the option to create an action on an action group to Email an Azure Resource Manager Role like Owner.
Trying to Automate the action groups per subscription/resource group, I can't find any documentation on how to create such a receiver via Powershell or CLI. There is the standard EmailReceiver and others, but nothing that is specific to the Role of the specific Resource group.
The intention is to create an Action Group that sends an email to everybody in the Owner group. Looking at the templates, it also is blank for all receivers with no indication on actually where it defines the "role" it needs to send to.
Any help will be appreciated.

If I am correctly understanding you. You could try to create an Email ARM Role by using armRoleReceivers parameter. When you do this, you could set the name value as the same as the name for emailReceivers and a specific roleId in the action group. For example, If you want to set a built-in owner role of this, you should set roleId 8e3af657-a8ff-443c-a75c-2fe8c4bcb635.
Something should be like:
"armRoleReceivers": [
{
"name": "string",
"roleId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
}
]
You could find microsoft.insights actionGroups template reference, Here is a template working on my side.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"actionGroupName": {
"type": "string",
"metadata": {
"description": "Unique name (within the Resource Group) for the Action group."
}
},
"actionGroupShortName": {
"type": "string",
"metadata": {
"description": "Short name (maximum 12 characters) for the Action group."
}
}
},
"resources": [
{
"name": "[parameters('actionGroupName')]",
"type": "microsoft.insights/actionGroups",
"apiVersion": "2018-09-01",
"location": "Global",
"properties": {
"groupShortName": "[parameters('actionGroupShortName')]",
"enabled": true,
"emailReceivers": [
{
"name": "contosoEmail",
"emailAddress": "devops#contoso.com"
}
],
"smsReceivers": [
{
"name": "contosoSMS",
"countryCode": "1",
"phoneNumber": "555555"
}
],
"armRoleReceivers": [
{
"name": "contosoEmail",
"roleId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
}
]
}
}
]
}

Related

"Cannot read properties of undefined" when using ResourceSelector on UIDefinition

I'm building an ARM template that deploys some variables and runbooks to the automation account that the user selects.
To guide the user, I use a
{
"name": "AutomationAccount",
"type": "Microsoft.Solutions.ResourceSelector",
"resourceType": "Microsoft.Automation/automationAccounts",
"label": "Automation Account",
"toolTip": "The Automation Account that will host these runbooks.",
"filter": {
"subscription": "onBasics",
"location": "onBasics"
},
"visible": true
}
This correctly displays a dropdown that allows me to select the Automation Account filtered to the subscription and the resource group.
At the end of the UIDefinition.json file, I output the selected value like so:
"outputs": {
"parameters": {
...
"AutomationAccountId": "[steps('basics').AutomationAccount.id]",
...
}
}
(based on the sample output from the documentation for the ResourceSelector)
My ARM template is then supposed to use this value as a parameter:
"parameters": {
...
"AutomationAccountId": {
"type": "string",
"metadata": {
"description": "The resourceId of the Automation Account that will host this runbook."
}
},
...
}
which I then use as part of the name for a new variable:
"resources": [
...
{
"name": "[concat(parameters('AutomationAccountId'), '/MyVariableName')]",
"type": "Microsoft.Automation/automationAccounts/variables",
"apiVersion": "2019-06-01",
"dependsOn": [ ],
"properties": {
"value": "[parameters('SomeVariableValueParameter')]",
"description": "Some description')",
"isEncrypted": false
}
...
The UI displays correctly, allowing me to pick an Automation Account, but when I get to the Review & Create stage, validation fails with the following error message:
with the following error detail:
ERROR TYPE
Cannot read properties of undefined (reading 'subscriptionId')
Can anyone help out?

Azure Lighthouse - Get the region for subscription level deployment

I want to onboard Azure Subscription into my tenant. For that, I created an ARM template with subscriptionDeploymentSchema. If I open this template from the portal, I get prompted to choose a region. Is there any way I get the value of that built-in field into my template and use it?
I want to display value of the "Region" field (built-in) in the "Region Name", which is my field. Is that possible?
I know for the resource group level deployment I can use resourceGroup().location, but that does not work here.
Part of my template:
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mspOfferName": {
"type": "string",
"metadata": {
"description": "Specify a unique name for your offer"
}
},
"mspOfferDescription": {
"type": "string",
"metadata": {
"description": "Name of the Managed Service Provider offering"
}
},
"regionName": {
"type": "string",
"metadata": {
"description": "Should have value of the 'Region' built-in field"
}
}
},
"resources": [
...
{
"name": "myNestedTemplate",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-10-01",
"location": "<i-want-to-use-value-from-the-built-in-field>", // <-- I WANT TO USE REGION FROM THE BUILT-IN FIELD HERE
...
}
],
...
}
Is that even possible? Or should I create a field for user to provide a region? The second option does not make any sens, as you would be prompted to provide two locations.
You can use deployment().location to get the value of the Region field.

ARM Deployment error: Unable to freeze secondary namespace before creating pairing, this is probably because secondary namespace is not empty

I have two premium Service bus instances deployed manually through the azure portal. They don't have geo-recovery alias configured and the service bus instances have been operational for about a year.
Now, I'm trying automate the deployment process of these service bus instances and also add a georecovery alias resource to it as follows:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespaceName": {
"type": "string",
"metadata": {
"description": "Name of the Service Bus namespace"
}
},
"serviceBusQueueName": {
"type": "string",
"metadata": {
"description": "Name of the Queue"
}
},
"serviceBusLocation": {
"type": "string"
},
"sku": {
"type": "object",
"defaultValue": "Standard"
},
"serviceBusTopicName": {
"type": "string"
},
"serviceBusSubscriptionName": {
"type": "string"
},
"isAliasEnabled": {
"type": "bool"
},
"isQueueCreationEnabled": {
"type": "bool"
},
"aliasName": {
"type": "string"
},
"partnerNamespace": {
"type": "string"
}
},
"variables": {
"defaultSASKeyName": "RootManageSharedAccessKey",
"authRuleResourceId": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', parameters('serviceBusNamespaceName'), variables('defaultSASKeyName'))]",
"sbVersion": "2017-04-01"
},
"resources": [
{
"apiVersion": "2018-01-01-preview",
"name": "[parameters('serviceBusNamespaceName')]",
"type": "Microsoft.ServiceBus/Namespaces",
"location": "[parameters('serviceBusLocation')]",
"sku": {
"name": "[parameters('sku').name]",
"tier": "[parameters('sku').tier]",
"capacity": "[parameters('sku').capacity]"
},
"properties": {
"zoneRedundant": false
},
"resources": [
{
"apiVersion": "2017-04-01",
"name": "[parameters('aliasName')]",
"type": "disasterRecoveryConfigs",
"condition": "[parameters('isAliasEnabled')]",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceName'))]"
],
"properties": {
"partnerNamespace": "[parameters('partnerNamespace')]"
}
}
]
}
]
}
I'm using the same template to deploy the primary and secondary instances separately. Note that the disasterRecoveryConfigs resource will only be deployed when it's the primary instance.
This template successfully deploys the secondary namespace, but the primary namespace deployment fails with the following error:
Unable to freeze secondary namespace before creating pairing, this is
probably because secondary namespace is not empty.
Which is correct i.e. the secondary namespace has a couple of topics/subscriptions and queues already created. I don't want to delete them and just want to pair the primary and secondary namespaces.
How can this be done?
I had a similar issue with the Service Bus Geo-Recovery ARM Template. I read the exception closely; its state that the secondary namespace is not empty means we have to delete the topic and queue from the secondary namespace, then run the template again. It will work and create the topic and queue again based on the primary namespace.
But if you run the template a second time, you will get a different exception, which is that the secondary namespace cannot be updated (since it’s in geo-pairing). It’s strange, but by design, you cannot update the secondary namespace while it’s in Geo Pairing, and even if you remove Geo Pairing, your secondary namespace should be empty without any instances such as Topic, Queue, etc.
How to overcome this?
Lets consider, now I wanted to add the Topic or Queue in existing deployment by using the ARM template then, you will ran into the issue when your template is in the pipeline or anywhere and needs to run multiple times and update the existing primary namespace.
1. Quick Fix (one time only second time manually again you have to do the following steps)
Login to the Azure Portal
Go to the your primary Service bus Namespace
Click on the Geo-Recovery option under setting section
At the right hand side at the top find the option break pairing and
click on it.
It will break the pairing & if you not follow this step you will get the exception, Secondary Namespaces can not be updated
Next, delete the secondary Namespace instance or Namespace and run
the pipeline. it will work.
If you not follow above step then you will get error unable to freeze secondary Namespace.
The above is the one time fix, if you run template again you have to repeat above process manually again.
2. Automation using CI-CD DevOps Pipeline or CLI or PowerShell
The most of the time ARM templates runs in the pipeline and there is option to break the pairing using the Azure CLI or PowerShell. You should consider the adding two task in the YAML file
First Task, to break the Pairing
Azure CLI
az servicebus georecovery-alias break-pair --resource-group myresourcegroup --namespace-name primarynamespace --alias myaliasname
PowerShell
Set-AzureRmServiceBusGeoDRConfigurationBreakPair -ResourceGroupName $resourcegroup -Name $aliasname -Namespace $primarynamespace
Second Task, to delete the secondary namespace instances (topic,
Queue) or delete entire Namespace.
PowerShell
Remove-AzServiceBusNamespace -ResourceGroup Default-ServiceBus-WestUS -NamespaceName SB-Example1
To remove Topic or Queue instead of Namespace, refer the following documentation.
Azure Service Bus Management Common PowerShell commands
Also if you are running template locally, you can add small script or CLI command prior to run your template.
Does it affect on ConnectionString or Data after deleting Secondary Namespace or instances?
Its valid question, what will happens to the connection string or data since some clients are already using it, The answer is connection string wont be change if we delete the secondary namespace because in Geo recovery scenario we are supposed to be use alias connection string so there is no impact on existing customers.
Regarding the second question about the data, the answer is secondary namespace wont store any data it has only the meta data, meaning in the case of failover secondary namespace start working.
So during the deployment deleting secondary namespace instances or namespace wont impact on anything.
Is there any better option?
Might be you are thinking, why should I follow such a long process but the above problem because of the Geo Recovery design (service bus, event hub, event grid etc.) and there is no other option.
I hope Microsoft will come up with some better approach in the future.
If you try to create a pairing between a primary namespace with a private endpoint and a secondary namespace without a private endpoint, the pairing will fail.
You could refer to this template allows you to configure Service Bus Geo-disaster recovery alias.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespaceNamePrimary": {
"type": "string",
"metadata": {
"description": "Name of Service Bus namespace"
}
},
"serviceBusNamespaceNameSecondary": {
"type": "string",
"metadata": {
"description": "Name of Service Bus namespace"
}
},
"aliasName": {
"type": "string",
"metadata": {
"description": "Name of Geo-Recovery Configuration Alias "
}
},
"locationSecondaryNamepsace": {
"type": "string",
"defaultValue": "South Central US",
"metadata": {
"description": "Location of Secondary namespace"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location of Primary namespace"
}
}
},
"variables": {
"defaultSASKeyName": "RootManageSharedAccessKey",
"defaultAuthRuleResourceId": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', parameters('serviceBusNamespaceNamePrimary'), variables('defaultSASKeyName'))]"
},
"resources": [
{
"apiVersion": "2017-04-01",
"name": "[parameters('serviceBusNamespaceNameSecondary')]",
"type": "Microsoft.ServiceBus/Namespaces",
"location": "[parameters('locationSecondaryNamepsace')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 4
},
"tags": {
"tag1": "value1",
"tag2": "value2"
}
},
{
"apiVersion": "2017-04-01",
"type": "Microsoft.ServiceBus/Namespaces",
"dependsOn": [ "[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceNameSecondary'))]" ],
"name": "[parameters('serviceBusNamespaceNamePrimary')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 4
},
"tags": {
"tag1": "value1",
"tag2": "value2"
},
"resources": [
{
"apiVersion": "2017-04-01",
"name": "[parameters('aliasName')]",
"type": "disasterRecoveryConfigs",
"dependsOn": [ "[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceNamePrimary'))]" ],
"properties": {
"partnerNamespace": "[resourceId('Microsoft.ServiceBus/Namespaces', parameters('serviceBusNamespaceNameSecondary'))]"
}
}
]
}
],
"outputs": {
"NamespaceDefaultConnectionString": {
"type": "string",
"value": "[listkeys(variables('defaultAuthRuleResourceId'), '2017-04-01').primaryConnectionString]"
},
"DefaultSharedAccessPolicyPrimaryKey": {
"type": "string",
"value": "[listkeys(variables('defaultAuthRuleResourceId'), '2017-04-01').primaryKey]"
}
}
}

Stop Creation of Resources on Azure Subscription

I need to stop creation of all resources on my azure subscription except for:
Logic Apps
Dashboards
Solutions
the only way I can think of doing this right now is via Azure Policy, will anyone know how to write such policy?
well, you basically need to use not and anyof in combination with deny:
"if": {
"not": {
"anyOf": [
{
"field": "type",
"equals": "Microsoft.Logic/workflows"
},
{
"field": "type",
"equals": "Microsoft.OperationsManagement/solutions"
},
{
"field": "type",
"equals": "Microsoft.Portal/dashboards"
}
]
}
},
"then": {
"effect": "Deny"
}
resource types might be wrong, but I'm not sure what are you after exactly.
Policies require definitions (where the policy logic is written) and then a policy assignment (where the definition is assigned to a scope). Policy definitions can be grouped into Policy Initiatives (AKA Policy Set Definitions). These Initiatives can also be assigned to a scope. Scopes can be defined at the Resource Group level, Subscription level, or Management Group level.
Policies can be written and assigned through the portal by first creating a policy definition and then assigning it. IMO this can be a bit cumbersome when done through the portal. Or they can be deployed via ARM template. Unfortunately, the portal template deployment is not currently configured to deploy at anything other than at the resource group level (08/29/2019). But it is much easier to write and deploy via the deployment API. I use Postman to do this.
A subscription scoped (as you are describing) policy deployment can be done via PUT to the following URI.
https://management.azure.com/subscriptions/:subscriptionId/providers/Microsoft.Resources/deployments/mypolicydeployment?api-version=2019-05-01
Where :subscriptionId is Postman parameter notation for your actual Subscription ID.
You will need to obtain a bearer token to authenticate for the PUT request and that user must have permissions to deploy and assign policies. That is a whole other topic, you can learn more about that here (https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code).
Also, I supply a "Content-Type" = "application/json" header with my PUT request.
My this is my body payload for your policy.
{
"location": "westus2",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"subscriptionId": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Authorization/policyDefinitions",
"name": "my-deny-policy",
"apiVersion": "2018-05-01",
"location": "westus2",
"properties": {
"displayName": "My Deny Policy",
"policyType": "Custom",
"description": "This policy DENYS all resource creation except, Logic Apps, Dashboards, and Solutions.",
"mode": "All",
"policyRule": {
"if": {
"not": {
"anyOf": [
{
"field": "type",
"equals": "Microsoft.Logic/workflows"
},
{
"field": "type",
"equals": "Microsoft.OperationsManagement/solutions"
},
{
"field": "type",
"equals": "Microsoft.Portal/dashboards"
}
]
}
},
"then": {
"effect": "Deny"
}
}
}
},
{
"name": "my-policy-assignment",
"type": "Microsoft.Authorization/policyAssignments",
"apiVersion": "2018-05-01",
"location": "westus2",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"displayName": "My Policy Assignment",
"policyDefinitionId": "[concat('/subscriptions/', parameters('subscriptionId'), '/providers/Microsoft.Authorization/policyDefinitions/my-deny-policy')]",
"scope": "[concat('/subscriptions/', parameters('subscriptionId'), '/')]",
"notScopes": [],
"parameters": {},
"description": "This assignment contains my policy to DENY creation of all resources except logic apps, dashboards, and solutions.",
"metadata": {}
},
"dependsOn": [
"my-deny-policy"
]
}
]
},
"parameters": {
"subscriptionId": {
"value": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX"
}
}
}
}
The deployment template contains a definition containing the policy you have described, as well as a policy assignment. The policy assignment is set to "dependsOn" the policy definition. This is because the policy assignment depends on the existence of the definition to deploy properly. Otherwise, there will be a race condition that you will always lose.
Certain fields can be broken out into parameters as I have done with the subscription ID. In order to apply at another subscription scope, simply change the parameter value and make sure your bearer token is authorized for that subscription.
Where exactly you stock in creating azure policy?
Refer this doc, You can restrict/allow upon resource types
Make a Custom RBAC Role with "ACTIONS" only for these 3 you want.
Policy is OK here but it depends on the User role if he would be able to Unassign such policy from the Subscription.
To prevent user to do so:
Apply policy on level higher then subscrption (mgmt group) where user has no rights.
OR disallow user (in RBAC role) to work on Policy
Definitions & Assigments.
OR Create this Policy with Blueprint and
set ReadOnly Lock for this Bluepring Assignment.

ARM deployment fails when properties are passed an an object

When deploying an ARM template using resource iteration, I'd like to pass the resource properties as an object.
Doing this would allow for a different set of parameters to exist within each element the copy array. The reason for this is because some properties may need to be conditionally included or excluded depending on the values of others. For example, in the case of an API Management product, the documentation states the following with regard to the subscriptionsLimit property -
Can be present only if subscriptionRequired property is present and has a value of false.
However, when deploying the example template below the deployment hangs in Azure. Looking in to the related events, I can see that the action the deploy the resource keeps failing with an Internal Server Error (500), but there are no additional details.
If I refer to each parameter in the properties object using variables('productsJArray')[copyIndex()].whatever then the deployment succeeds. However, this is undesirable as it means that every properties object would have to contain identical parameters, which is not always permissible and may cause the deployment to fail.
Example template
Note that I've output variables('productsJArray')[copyIndex()] and it is a valid object. I've even copied the output in to the template and deployed it successfully.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiManagementServiceName": {
"type": "string",
"metadata": {
"description": "The name of the API Management instance."
}
},
"productsJson": {
"type": "string",
"metadata": {
"description": "A JSON representation of the Products to add."
}
}
},
"variables": {
"productsJArray": "[json(parameters('productsJson'))]"
},
"resources": [
{
"condition": "[greater(length(variables('productsJArray')), 0)]",
"type": "Microsoft.ApiManagement/service/products",
"name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex()].name)]",
"apiVersion": "2018-06-01-preview",
"properties": "[variables('productsJArray')[copyIndex()]]",
"copy": {
"name": "productscopy",
"count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]"
}
}
]
}
Example parameters
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiManagementServiceName": {
"value": "my-api-management"
},
"productsJson": {
"value": "[{\"name\":\"my-product\",\"displayName\":\"My Product\",\"description\":\"My product is awesome.\",\"state\":\"published\",\"subscriptionRequired\":true,\"approvalRequired\":false}]"
}
}
}
Output of variable 'productsJArray[0]'
"outputs": {
"properties": {
"type": "Object",
"value": {
"approvalRequired": false,
"description": "My product is awesome.",
"displayName": "My Product",
"name": "my-product",
"state": "published",
"subscriptionRequired": true
}
}
}
The issue here was that I was passing including name parameter along with other parameters when setting resource properties. This is obviously wrong, but it would have been helpful if MS had handled the error in a more human friendly way (guess they can't think of everything).
I've updated my incoming productsJson parameter -
[{\"name\":\"cs-automation\",\"properties\":{\"displayName\":\"CS Automation Subscription\",\"state\":\"published\",\"description\":\"Allows access to the ConveyorBot v1 API.\",\"subscriptionRequired\":true,\"approvalRequired\":false}}]
And I'm now passing only the required 'properties' -
"resources": [
{
"type": "Microsoft.ApiManagement/service/products",
"name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex()].name)]",
"apiVersion": "2018-06-01-preview",
"properties": "[variables('productsJArray')[copyIndex()].properties]"
}
]

Resources