Azure ARM Template - accessing a resource Id created by one ARM template in another ARM template - json

We deploy azure resources using an ARM template as part of our build process before deploying the actual application.
So far all our application resources are self contained within a resource group. e.g. A web app that requires a sql server and a storage account are clubbed into one resource group.
However we have come across a scenario/need where we need to share a resource eg. storage account across resource groups. Resource Group A has the storage account and Resource Group B's web app requires the connection string/app keys pertaining to the storage account in its appconfig.json/web.config.
Question
How do I build the connection string for the app in resource group B to connect to a resource in resource group A as I need to obtain the Id of the resource group A in B
Here is how i build the connection string if they are in the same resource group
"variables"
{
"storageAccounts_id": "[concat(**resourceGroupA**().id,'/providers/Microsoft.Storage/storageAccounts/', variables('storageAccntName'))]",
},
"resources": [
{
"apiVersion": "2015-08-01",
"type": "config",
"name": "connectionstrings",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('MyWebSiteName'))]"
],
"properties": {
"AzureWebJobsDashboard": {
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccntName'),';AccountKey=',concat(listKeys(variables('storageAccounts_id'),'2015-05-01-preview').key1))]",
"type": "Custom"
},
}
}
]
Notes:
I did go through this site https://azure.microsoft.com/en-us/documentation/articles/resource-group-linked-templates/ about linked templates, but it does not suit our current build process which uses Octo (unless there is something I may be missing) which deployes the ARM first then the application (web).

For this scenario where the storage account name is known and does not depend on the resource group (eg, uniqueString(resourceGroup().id)), then you can simply use the longer form for resourceId(). The full form looks like:
resourceId([subscriptionId], [resourceGroupName], resourceType, resourceName1, [resourceName2]...)
so we can optionally supply subscriptionId and resourceGroupName.
listKeys(resourceId(parameters('ResourceGroupAName'), 'Microsoft.Storage/storageAccounts', variables('ccPaymentStorageName'))
If it was in a different subscription, you could also specify the subscription.
listKeys(resourceId(parameters('SubscriptionId'), parameters('ResourceGroupAName'), 'Microsoft.Storage/storageAccounts', variables('ccPaymentStorageName'))
If your storage account name depends on the resource group like
"storageName": "[concat('mystorage', uniqueString(resourceGroup().id))]" // in Resource Group A
then you'll either need to always run the template that creates this account and output the storageName and the resourceGroup or find a way to reference the other resource group to get it's id so that the name can be re-created.
I have been able to use something like this to "re-create" the resource group id so I can generate the proper name of the storage account.
"otherResourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('ResourceGroupName'))]"
Then I can use that to generate the name appropriately:
"storageAccountName": "[concat('mystorage', uniqueString(variables('otherResourceGroupId')))]"

You can try below(for an example ):-
"subNetId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('virtualNetworkNameRG'), '/providers/', 'Microsoft.Network/virtualNetworks/',parameters('virtualNetworkName'),'/subnets/', parameters('subnetName'))]",
refer https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions

Related

ARM template to create a VM using an existing VNet and subnet

recently I started learning/working with ARM templates and JSON so I'm a complete newbie to this. I've been asked to make a template that creates a virtual machine selecting an existing virtual network and subnet within a subscription.
Everything works fine, except that whenever I make the deployment, the template creates a new vnet and subnet with randomized names instead of letting me pick from an existing one (the VM creates correctly though).
I used https://github.com/Azure/azure-quickstart-templates/blob/master/101-vm-simple-rhel/azuredeploy.json quickstart template as a base and added a few lines (which I will put below) to let me type the name of my vnet and subnet as it does with the VM name, but it keeps creating new ones even though I type the name correctly.
The lines I added to the code in the Parameters section are:
"virtualNetworkName": {
"type": "string",
"metadata": {
"description": "VNet to which the VM will connect."
}
},
"subnetName": {
"type": "string",
"metadata": {
"description": "Subnet to which the VM will connect."
}
}
Thank you in advance for your time!
To create a VM with the existing VNet base on the quickstart template you used, you only need to delete the virtual network resource in the resources block and the dependency on it and all the variables about the VNet and subnet except the variable subnetRef, then change this variable with your parameters like this if the VNet in the same resource group with the VM:
"subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]",
If the existing VNet in another resource group but in the same subscription, then the variable subnetRef should be changed like this:
"subnetRef": "[resourceId('otherResourceGroup', 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]",
According to the changes, the template will use the existing VNet and subnet instead of creating new ones.
Take a look at this sample:
https://github.com/Azure/azure-quickstart-templates/tree/master/100-marketplace-sample
It shows how you can use a pattern for new/existing/none on resources in a template.

CAS Multifactor Authentication Provider Selection

I am working with cas-overlay-template project in version 6.1.4. I have implemented two mfa providers on my CAS, Google Authenticator and CAS Simple. Both are working, I have tested them separately and I have got the results I've expected.
Until now, I have been activating the mfa modifying the cas.properties file adding this properties: cas.authn.mfa.globalProviderId=mfa-gauth when I wanted to use Google, or cas.authn.mfa.globalProviderId=mfa-simple when I used the CAS itself.
Well, in CAS documentation is mentioned that is possible to enable a provider selection menu, if resolved more than one just by adding this propertie: cas.authn.mfa.provider-selection-enabled=true. So, my configuration is the following:
cas.authn.mfa.provider-selection-enabled=true
cas.authn.mfa.globalProviderId=mfa-gauth
cas.authn.mfa.globalProviderId=mfa-simple
But when I try to login with any user (I'm using the default one casuser:Mellon), CAS don't show me a menu in which I can select the following mfa provider, It directly goes to mfa-simple provider.
What am I doing wrong?
Well, in CAS documentation is mentioned that is possible to enable a provider selection menu, if resolved more than one just by adding this properties:
So far so good.
So, my configuration is the following:
That's the problem. You are not resolving/triggering more than just one provider. You start with mfa-gauth and then override it with mfa-simple. In CAS 6.1.x, the globalProviderId only accepts a single identifier. It's not a list or a container of any kind to accept more than one value. This has been addressed in the next coming release.
At the moment, to resolve more than one provider you will need to assign the MFA providers to a registered service definition. Like so:
{
"#class": "org.apereo.cas.services.RegexRegisteredService",
"serviceId": "^(https|imaps)://.*",
"name": "Example",
"id": 1,
"description": "This service definition defines a service.",
"evaluationOrder": 1,
"multifactorPolicy" : {
"#class" : "org.apereo.cas.services.DefaultRegisteredServiceMultifactorPolicy",
"multifactorAuthenticationProviders" : [ "java.util.LinkedHashSet", [ "mfa-duo", "mfa-gauth" ] ]
}
}
This means, provider selection can be enabled on a per-application basis. Alternatively, you can write a small groovy script to return more than one provider back to CAS, allowing the selection menu to display the menu items.
Read this post for full details.

AWS CloudFormation Template to Create EC2 - List IAM Roles

I'm trying to get a AWS CloudFormation template to provide a drop down list of IAM roles as part of a EC2 creation template. I have this working for subnet ID, VPC and security group but stuck on getting it to work for IAM role.
In the code snippet below my template prompts for a VpcName from a drop down list but it fails when trying to generate the list for InstanceProfile. I've tried a number of different combinations such as:
"Type" : "AWS::IAM::Role"
"Type" : "AWS::IAM::ROLE"
"Type" : "AWS::IAM::Role:Id"
"Type" : "AWS::IAM::ROLE:ID"
},
"InstanceProfile": {
"Description": "Select the role for this EC2 instance",
"Type" : "AWS::IAM::InstanceProfile"
},
"VpcName" : {
"Description" : "Select the VPC for this EC2 Instances",
"Type" : "AWS::EC2::VPC::Id"
},
What you're using for the mentioned parameters are a special kind of CloudFormation parameter types: AWS-Specific Parameter Types. With these parameters you get the mentioned dropdowns and additional validation of the specified values, but they have to be explicitly supported by CloudFormation for each resource type. The types of the parameters you have working are supported by CloudFormation (subnet ID by AWS::EC2::Subnet::Id, VPC by AWS::EC2::VPC::Id and security group by AWS::EC2::SecurityGroup::GroupName or AWS::EC2::SecurityGroup::Id), while there is no such type for IAM roles as of now.
Therefore there is unfortunately no way to get such a dropdown for IAM roles, until AWS implements an AWS-specific parameter type for IAM roles. I suggest you open an AWS support case as feature request for such a parameter type as more of such requests make it more likely that this gets prioritized by AWS.

Unable to extend schema within a verified sub domain directory

I live in an enterprise environment where most of our production domains are currently non-routable (e.g. .local).
I tried extending the schema but since the non-routable cannot be verified and the default .onmicrosoft I don't think could either. My enterprise allows me to easily create subdomains so I attached it and verified for testing purposes and ran into the same verified domain error.
Per the documentation, I should be able to either us the ID of my domain name or just the scheme name and get 8 random-alpha-chars added. Neither approach works in this case.
POST: https://graph.microsoft.com/v1.0/schemaExtensions
{
"id": "idmdomain.sub.domain.net_Owners",
"description": "Owners of the group",
"targetTypes": [
"Group"
],
"properties": [{
"name": "PrimaryOwners",
"type": "String"
},
{
"name": "SecondaryOwners",
"type": "String"
}
]
}
Message Received:
{
"code": "BadRequest",
"message": "Your organization must own the namespace idmdomain.sub.domain.net as a part of one of the verified domains.",
"request-id": "1c7363f9-d54b-408a-8b29-2c0d2a94280a",
"date": "2018-03-22T21:47:22"
}
From the documentation:
If you already have a vanity .com,.net, .gov, .edu or a .org domain that you have verified with your tenant, you can use the domain name along with the schema name to define a unique name, in this format {domainName}_{schemaName}.
For example, if your vanity domain is contoso.com, you can define an id of, contoso_mySchema. This is the preferred option.
So in your example, idmdomain.sub.domain.net_Owners should simply be domain_Owners. It shouldn't include idmdomain, sub, net or any ..
Thank you Marc for pointing me in the correct direction. Even though my app had the correct delegated permissions (Directory.AccessAsUser.All) I now understand that I needed to execute this change in the user context instead of application as application is not supported.
For those that come behind me {domainName}_{schemaName} works if you validate your domain, if dont and you just leave schemename then the generated guid works as documented. I recommended reviewing the two links below as they were what finally unlocked the puzzle for me.
Helped me understand how this is working (authentication vs authorization)
https://developer.microsoft.com/en-us/graph/docs/concepts/rest
Helped me setup postman to quickly validate
https://blogs.msdn.microsoft.com/softwaresimian/2017/10/05/using-postman-to-call-the-graph-api-using-azure-active-directory-aad/
I should add for the postman route, a few changes...
Auth URL
https://login.microsoftonline.com/yourtennantid/oauth2/authorize?resource=https%3A%2F%2Fgraph.microsoft.com
Access Token URL
https://login.microsoftonline.com/yourtennantid/oauth2/token
Scope = Directory.AccessAsUser.All

Applying Sqlfilter to ServiceBus topic trigger in Azure Function?

So we have a Azure ServiceBus topic triggering a Azure Function. Problem is we need to apply a filter on the subscription. Json looks like this:
"bindings": [
{
"name": "mySbMsg",
"type": "serviceBusTrigger",
"direction": "in",
"topicName": "testtopic",
"subscriptionName": "AllMessages",
"connection": "RootManageSharedAccessKey",
"accessRights": "Manage"
}
Any ideas?
we have a Azure ServiceBus topic triggering a Azure Function. Problem is we need to apply a filter on the subscription.
As far as I know, Azure Functions do not provide a direct way to set up filters for an existing subscription while defining the function bindings and other configuration settings in function.json. If you’d like to apply filters for subscriptions, you could set up filters when you create subscriptions. For more information about creating subscriptions with filters, please refer to this documentation.
You can create a new subscriber with filter using Microsoft.ServiceBus; inside some temporary application (some cloud service or even console application).
When the new subscriber is subscribed, kill it.
Then use the same subscription name in your Function, the events will be filtered.
WindowsAzure.ServiceBus.5.0.0 library, which provides you to create filters for the subscription which is already present.
Alternatively, you can go with tools like Serverless360, Here this will have an option to create filters for Topic Subscriptions.
Refer this blog for more details.