Azure LogicApp ARM template and AzSK checker - azure

I am working on ARM template development for LogicApp and want to make my ARM template complaint to AzSk.
In my template I have following required objects for this component:
"ipAddressRangeForContents": {
"type": "array",
"defaultValue": [],
"metadata": {
"description": "(AzSk required this parameter to be set) IPv4 or IPv6 address range, this will restrict content IP range. This array should have object as a member with following key 'addressRange'. You can specify as many subnets as you want"
}
},
"ipAddressRangeForInbound": {
"type": "array",
"defaultValue": [],
"metadata": {
"description": "(AzSk required this parameter to be set) IPv4 or IPv6 address range, this will restrict inbound IP range. This array should have object as a member with following key 'addressRange'. You can specify as many subnets as you want. Default value is empty array which will restric access to 'Only other Logic Apps'."
}
Here is an example from parameters file for same section:
"ipAddressRangeForContents": {
"value": [
{
"addressRange": "10.123.0.0/24"
},
{
"addressRange": "10.124.0.0/24"
}
]
},
"ipAddressRangeForInbound": {
"value": [
{
"addressRange": "10.135.0.0/24"
},
{
"addressRange": "10.136.0.0/24"
}
]
}
The reason I implemented it this way is flexibility for user to specify as many address ranges as user wants.
AzSk returning me an error if I scan my ARM template:
Starting analysis: [FileName: .\logicapp.json]
--------------------------------------------------------------------------------
Failed: [Azure_LogicApps_AuthZ_Provide_Triggers_Access_Control]
Failed: [Azure_LogicApps_AuthZ_Provide_Contents_Access_Control]
--------------------------------------------------------------------------------
Summary Total Failed
------- ----- ------
High 2 2
------ ------ ------
Total 2 2
------ ------ ------
Even if my template has these parameters.
The reason it's failing it cannot locate property addressRange inside ARM template:
ExpectedProperty
$.properties.accessControl.triggers.allowedCallerIpAddresses.addressRange
$.properties.accessControl.contents.allowedCallerIpAddresses.addressRange
I can fix it by hardcoding my template to:
"properties": {
"accessControl": {
"contents": {
"allowedCallerIpAddresses": {
"addressRange": "[variables('some_range')]"
}
But this will make it less functional since it can accept only one addressRange at deployment phase.
Is there is a way to make template complaint and flexible in the same time?
Thank you in advance!

Related

Authorized IP Addresses for AKS using ARM Template

I am trying to deploy an AKS with authorized IP ranges enabled by default. I'm utilizing the following in my code:
parameters: {
"AuthorizedIpRanges": {
"type": "string",
"default": "1.0.0.1,1.0.0.2,1.0.0.3"
}
}
variables: {
"authorizedIpRanges": "[split(parameters('AuthorizedIPRanges'),',')]"
}
properties: {
"apiServerAccessProfile": {
"authorizedIPRanges": "[variables('authorizedIpRanges')]"
}
}
This deploys successfully, and I can see the Authorized IP Ranges checkbox checked in Portal, but there are no IP addresses listed.
I'm aware it takes an array of strings, but when I try to set the AuthorizedIpRanges type to "array" it is unable to process the json at all. Trying without the split gives "APIServerAccessProfile.properties.apiServerAccessProfile.authorizedIPRanges accept type []string, not type string"
I also do not have any spaces after the commas, as shown in the example above.
Any help is appreciated!

Multiple Vms Arm template with different Vm names,sizes and same custom

I have seen many templates to create multi vms as loop using copy function. Ex: vm1, vm2 etc. But this is not how we put in practice as each vm has different function and the naming convention doesn't help.
I am trying to create a template with different vM names, sizes and a single custom Image.
Can anyone please help?
I suggest using an array of name/value pairs, either in the parameters or variables section of your template, for example,
"parameters": {
"vms": {
"type": "array",
"defaultValue": [
{
"name": "vm1",
"size": "Standard_DS1_v2"
},
{
"name": "vm2",
"size": "Standard_A1_v2"
}
]
}
}
Then you can dereference the array with
"copy": {
"name": "vmCopy",
"count": "[length(parameters('vms'))]"
}
and
parameters('vms')[copyIndex()].name
parameters('vms')[copyIndex()].size
By using parameters, we can differentiate the VM names, sizes etc:
"parameters": {
"org": {
"type": "array",
"defaultValue": [
"contoso",
"fabrikam",
"coho"
]
}
},
<![endif]-->
As Copy functions can get the correct value from parameter array and can set the count with length() automatically.
Refer to MS Docs to understand more.
Also have a look on this answer, thanks to SamaraSoucy for explanation.

Looping through complex JSON variables in ARM templates

In my ARM template I have a variable called "subnets" which can be of 3 types.
If it is of typeA then I want 4 subnets of the given names and addresses; if it's typeB then 2 subnets, and so on.
"variables": {
"subnets" : {
"typeA" : {
"network" : "3.0/24",
"directory" : "5.0/24",
"documents" : "8.0/24",
"security" : "10.0/24",
},
"typeB" : {
"directory" : "10.0/24",
"database" : "11.0/24",
},
"dmz" : {
"directory" : "12.0/24",
"database" : "15.0/24", }
}
}
In the ARM template I have a parameter which tells me what type to use. So I have a segment like the below which uses a condition to match on the subnetType being typeA and creates a virtual network accordingly.
{
"type": "Microsoft.Network/virtualNetworks",
"condition" : "[contains(parameters('subnetType'), 'typeA')]",
"apiVersion": "2018-10-01",
...
"copy" : [ {
"name" : "subnets",
"count" : "[length(array(variables('subnets').typeA))]",
"input": {
"name": "...",
"properties": {
"addressPrefix": "..."
}
}
} ]
}
}
As you can see above, I have a copy block within this VirtualNetwork resource, and I want to create the various subnets for the typeA network. I figure I could convert subnets.typeA to an array and get the length of it to loop over (that's the idea, I don't know if it actually works) but I am not clear how to extract the subnet name and addressprefix from my variable above.
so there are 2 issues here:
no way to loop object keys in arm templates
use of different resources in the template to create subnets
there is no way to work around the first limitation that I know of, whereas the second limitation is mostly due to you trying to work around the first one. I'd go for a completely different approach:
"networks": [
{
"name": "typeA",
"subnets": [
{
"name": "network",
"addressSpace": "3.0/24"
},
{
"name": "directory",
"addressSpace": "5.0/24"
},
{
"name": "documents",
"addressSpace": "8.0/24"
},
{
"name": "security",
"addressSpace": "10.0/24"
}
]
},
{
// second virtual network
},
{
// x virtual network
}
]
the main downside here - you'd have to have a nested deployment, because you cannot actually iterate array inside array, so you'd have to feed each object inside array into a deployment that would create a virtual network that can contain various subnets.
You can consult this link for an example of this exact approach or the official Azure Building Blocks thingie way of doing this (which is quite similar in the approach, but the implementation is different).
You could, get away with different resources instead of iterations, but that means you are less flexible and each time you make a change to the input everything breaks or just doesnt work like you think it would (your way of doing this would fall apart if dmz doesnt exist in that variable, you'll get a compilation error, similarly if you add another key to the object, say applicationgateway it will work, but that virtual network won't get created)

Azure: Cannot use output from Linked Template in IF condition

I'm trying to deploy a Virtual network using ARM template with multiple subnets. I have a linked template which creates NSGs,route table and assigns it to a specific subnet. I'm using copy to create multiple subnets. Route table should be assigned to only one particular subnet. I control this using If condition. The issue here is i'm not able to use the linked template output in the If condition. It fails with below error.
'{
"error": {
"code": "InvalidTemplate",
"message": "Unable to process template language expressions for resource
'/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks/' at line '143' and column '9'. 'The provided
arguments for template language function 'if' is not valid: all arguments should be of type 'boolean'. Please see https://aka.ms/arm-template-expressions#if for usage details.'"
}
}'
Main Template (Subnet Creation snippet):-
"copy": [
{
"name": "subnets",
"count": "[length(parameters('subnetList'))]",
"input": {
"name": "[parameters('subnetList')[copyIndex('subnets')].name]",
"properties": {
"addressPrefix": "[parameters('subnetList')[copyIndex('subnets')].addressprefix]",
"networkSecurityGroup": "[if(equals(parameters('subnetList')[copyIndex('subnets')].name, 'GatewaySubnet'), json('null'), variables('nsgId'))]",
"routeTable": "[if(bool(parameters('subnetList')[copyIndex('subnets')].useRouteTable), reference('routeTableDeployment').outputs.resourceID.value, json('null'))]"
}
}
}
]
Route Table (Output snippet):-
"outputs": {
"resourceID": {
"type": "object",
"value": {
"id": "[resourceId('Microsoft.Network/routeTables', variables('routeTableName')]"
}
}
}
It works if I define a variable and pass it to if condition similar to nsg as below:-
"routeTableId": {
"id": "[resourceId('Microsoft.Network/routeTables', 'routeTableName')]"
}
"routeTable": "[if(bool(parameters('subnetList')[copyIndex('subnets')].useRouteTable), variables('routeTableId'), json('null'))]"

How to dynamically create Azure KeyVault reference in ARM template?

I'm using the following piece of code in my ARM template parameters file to retrieve the secret value from keyvault:
"parameters": {
"mailAccount": {
"reference": {
"keyVault": {
"id": "/subscriptions/GUID/resourceGroups/KeyVaultRG/providers/Microsoft.KeyVault/vaults/KeyVault"
},
"secretName": "mailAccount"
}
},
and in the template file:
"appSettings": [
{
"name": "mailAccount",
"value": "[parameters('mailAccount')]"
},
{
I'd like to know if it is possible to reference a KeyVault by its name using dynamically constructed object (i.e. not /subscriptions/GUID/resourceGroups/KeyVaultRG/providers/Microsoft.KeyVault/vaults/KeyVault but [resourceId(subscription().subscriptionId, resourcegroup().name, 'Microsoft.KeyVault/vaults', parameters('KeyVaultName'))]) or [resourceId('Microsoft.KeyVault/vaults', parameters('KeyVaultName'))] ?
In fact, the main objective is to be able to pass the different KeyVault names when deploying templates - where the similar values are stored.
The need to have several KeyVaults is justified by the resources (and cost) separation.
Now I see only validation errors saying ~ resourceId function cannot be used while referencing parameters.
I cannot use nested\linked templates (and output values).
What I am usually doing to avoid this limitation of the resourceId function is to define a variable with the value of the parameter, then using the variable instead in the resourceId function.
Example:
"parameters": {
"KeyVaultName": {
"type": "string",
"metadata": {
"description": "Key Vault Name"
}
}
},
"variables": {
"KeyVaultName": "[parameters('KeyVaultName')]"
}
Then when I am referencing the KeyVault resource I reference it using the variable like this:
"[resourceId('Microsoft.KeyVault/vaults', variables('KeyVaultName')]"

Resources