Using secret from Azure KeyVault in Azure ARM Template - azure

I have a template of container instance with container in azurecr.io
Is it possible to use an Azure Key Vault secret in an ARM Template?
The following examples do not work:
"imageRegistryCredentials": [
{
"server": "***.azurecr.io",
"username": "***",
"password": {
"reference": {
"keyVault": {
"id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
},
"secretName": "[parameters('secretName')]"
}
}
}
],
I have tried it with:
"resources": [
{
...
"properties": {
"parameters":{
"secretPassword": {
"type": "securestring",
"reference": {
"keyVault": {
"id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
},
"secretName": "[parameters('secretName')]"
}
}
},
And:
"imageRegistryCredentials": [
{
"server": "**.azurecr.io",
"username": "**",
"password": "[parameters('secretPassword')]"
}
],
Result:
"error": {
"code": "InvalidTemplate",
"message": "Unable to process template language expressions for resource '/subscriptions/**/resourceGroups/**/providers/Microsoft.ContainerInstance/containerGroups/**' at line '28' and co
lumn '9'. 'The template parameter 'secretPassword' is not found. Please see https://aka.ms/arm-template/#parameters for
usage details.'"
}
}'

So, I've created a workaround, which enables you to relatively simply use any keyvault secret in your template by using a publicly available template on github. See https://github.com/bobvandevijver/azure-arm-keyvault-secret-output for the example.
It would obviously be better if Microsoft just fixed this implementation, but it's something!

You can only use key vault reference in the parameters of the template (or nested template).
so you either need to move this part to the parameters section or move it to the nested template and use this as a parameter to the nested template. here is the sample to pass values from the kv to the nested template:
{
"apiVersion": "2017-05-10",
"name": "[concat('kvReference-', copyIndex())]",
"type": "Microsoft.Resources/deployments",
"copy": {
"name": "kvReference",
"count": 2
},
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "nested_template_uri"
},
"parameters": {
"cer": {
"reference": {
"keyVault": {
"id": "keyvaultId"
},
"secretName": "secretname"
}
}
}
}
},
and you can just use those inputs as parameters inside nested template

Related

Azure IoT Hub - create policy with supplied keys

I'm looking for a way to create access policy in Azure IoT hub but I'd like to supply my own keys.
I can see there is a command in Azure CLI:
az iot hub policy create --hub-name
--name
--permissions
[--resource-group]
[--subscription]
but it does not allow to provide my own keys.
I couldn't find anything interesting on PowerShell as well - seems like there is no command for creating shared access policy at all using PowerShell.
There is a way to use ARM template (seems like it is possible to provide primary and secondary key (https://learn.microsoft.com/en-us/azure/templates/microsoft.devices/iothubs?tabs=json#iothubproperties):
...
"properties": {
"allowedFqdnList": [ "string" ],
"authorizationPolicies": [
{
"keyName": "string",
"primaryKey": "string",
"rights": "string",
"secondaryKey": "string"
}
],
...
but it brings some hassle in terms how to provide the keys and I'm looking for something simple and preety much one-timer.
You can use the below sample arm template which create a basic iot hub & a shared access policy with our own keys. You need to create two files parameters.json & template.json.
template.json file contains the code which resources are going to deploy.
parameters.json file contains the value of those parameters that you have used in the template.json.
Template.json file:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"IotHubs_IotHub_connectionString": {
"type": "SecureString"
},
"IotHubs_IotHub_containerName": {
"type": "SecureString"
},
"IotHubs_IotHub_name": {
"defaultValue": "vedodIotHub",
"type": "String"
},
"IotHubs_Key_Name" : {
"defaultValue" : "newkeyname",
"type": "string"
},
"IotHubs_Key_Primary_value" : {
"type": "string"
},
"IotHubs_Key_Secondary_value":{
"type": "string"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Devices/IotHubs",
"apiVersion": "2021-07-02",
"name": "[parameters('IotHubs_IotHub_name')]",
"location": "eastus",
"sku": {
"name": "S1",
"tier": "Standard",
"capacity": 2
},
"identity": {
"type": "None"
},
"properties": {
"ipFilterRules": [],
"authorizationPolicies": [
{
"keyName": "[parameters('IotHubs_Key_Name')]",
"primaryKey": "[parameters('IotHubs_Key_Primary_value')]",
"secondaryKey" : "[parameters('IotHubs_Key_Secondary_value')]",
"rights": "RegistryRead, RegistryWrite, DeviceConnect"
}
],
"eventHubEndpoints": {
"events": {
"retentionTimeInDays": 1,
"partitionCount": 4
}
},
"routing": {
"endpoints": {
"serviceBusQueues": [],
"serviceBusTopics": [],
"eventHubs": [],
"storageContainers": []
},
"routes": [],
"fallbackRoute": {
"name": "$fallback",
"source": "DeviceMessages",
"condition": "true",
"endpointNames": [
"events"
],
"isEnabled": true
}
},
"storageEndpoints": {
"$default": {
"sasTtlAsIso8601": "PT1H",
"connectionString": "[parameters('IotHubs_IotHub_connectionString')]",
"containerName": "[parameters('IotHubs_IotHub_containerName')]"
}
},
"messagingEndpoints": {
"fileNotifications": {
"lockDurationAsIso8601": "PT1M",
"ttlAsIso8601": "PT1H",
"maxDeliveryCount": 10
}
},
"enableFileUploadNotifications": false,
"cloudToDevice": {
"maxDeliveryCount": 10,
"defaultTtlAsIso8601": "PT1H",
"feedback": {
"lockDurationAsIso8601": "PT1M",
"ttlAsIso8601": "PT1H",
"maxDeliveryCount": 10
}
},
"features": "None"
}
}
]
}
parameters.json file :
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"IotHubs_IotHub_connectionString": {
"value": ""
},
"IotHubs_IotHub_containerName": {
"value": ""
},
"IotHubs_IotHub_name": {
"value": "<IotHubName>"
},
"IotHubs_Key_Name":{
"value" : "<sharedaccesspolicyKeyName>"
},
"IotHubs_Key_Primary_value": {
"value" : "<accesspolicyPrimaryKeyValue>"
},
"IotHubs_Key_Secondary_value":{
"value" : "<accesspolicySecondaryKeyValue>"
}
}
}
Using the below Powershell cmdlets to deploy the create a Iot hub & passing the above template.json & parameters.json file as parameters :
New-AzResourceGroupDeployment -ResourceGroupName <resourcegroupName> -TemplateFile '<pathfortemplate.jsonfile>' -TemplateParameterFile '<Pathforparameters.jsonfile>'
Here is the sample output screenshot for reference:

Deployment Script ARM template in Azure

I am using Deployment Script to run powershell with ARM. It needs user-manged identity with contributor role. I have followed steps in below link but it always gives same error.
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-script-template?tabs=PowerShell
Invalid value for the identities '/subscriptions/<subID>/resourcegroups/<rgname>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test_manged_identity'. The 'UserAssignedIdentities' property keys should only be empty json objects, null or the resource exisiting property.
I have extracted principalId and client Id with below command.
Get-AzUserAssignedIdentity -ResourceGroupName 'rGname'
Below is the template
<pre>
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"name": {
"type": "string",
"defaultValue": "'ds test'"
},
"utcValue": {
"type": "string"
},
"subscriptionId": {
"type": "string",
"defaultValue": ""
}
},
"resources": [
{
"type": "Microsoft.Resources/deploymentScripts",
"apiVersion": "2019-10-01-preview",
"identity": {
"type": "userAssigned",
"userAssignedIdentities": {
"/subscriptions/subid/resourcegroups/rGname/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test_manged_identity": {
"ClientId": "value",
"PrincipalId": "value"
}
}
},
"kind": "AzurePowerShell", // or "AzureCLI"
"location": "[resourceGroup().location]",
"name": "runPowerShellInlineWithOutput",
"properties": {
"containerSettings": {
"containerGroupName": "deployscriptrun"
},
"storageAccountSettings": {
"storageAccountName": "allscriptstorage",
"storageAccountKey": "key"
},
"azPowerShellVersion": "3.0", // or "azCliVersion": "2.0.80"
"environmentVariables": [
{
"name": "someSecret",
"secureValue": "if this is really a secret, don't put it here... in plain text..."
}
],
"scriptContent" : "write-host 'hello world'",
"supportingScriptUris": [],
//"timeout": "PT30M",
"cleanupPreference": "OnSuccess",
"retentionInterval": "P1D"
}
}
],
"outputs": {
}
}
</pre>
With
"userAssignedIdentities": {
"/subscriptions/subid/resourcegroups/rGname/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test_manged_identity": {}
}
I get below error
{
"code": "DeploymentScriptOperationFailed",
"message": "The client 'id' with object id 'id' does not have authorization to perform action 'Microsoft.Resources/subscriptions/providers/read' over scope '/subscriptions/id' or the scope is invalid. If access was recently granted, please refresh your credentials."
}
according to the article linked it should look like this:
"userAssignedIdentities": {
"/subscriptions/subid/resourcegroups/rGname/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test_manged_identity": {}
}

How to pass DevOps release secrets to ARM for Key Vault Deployment

I am trying to deploy a key vault with secretName and secretValue and I have created a variable group in azure devops with all the secrets and I am using the below parameters in parameter file, but when this gets deployed the secret value gets stored as $(secret) and not the password actually stored in the task group in Azure DevOps.
"secretsObject": {
"value": {
"secrets": [
{
"secretName": "App012",
"secretValue": "$(mysecret)"
},
and this is what I got in the key vault template:
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(parameters('keyVaultName'), '/', parameters('secretsObject').secrets[copyIndex()].secretName)]",
"apiVersion": "2018-02-14",
"dependsOn": [
"[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]"
],
"copy": {
"name": "secretsCopy",
"count": "[length(parameters('secretsObject').secrets)]"
},
"properties": {
"value": "[parameters('secretsObject').secrets[copyIndex()].secretValue]"
}
}
]
}
Any idea how to pass the "secretvalue" as a variable?
I believe your asking how to leverage your secrets that are stored as a variable group to be deployed securely with your ARM template via Azure DevOps. If that is the case look at using Override Template Parameters in your release task.
This would be in the format of -NameOfARMParameter $(NameofDevOpsVariable)
In your case it would be -mysecret $(NameOfDevOpsVariable)
The deployment .json should look like this for parameter declaration:
"secretValue": {
"type": "string",
"metadata": {
"description": "This is for receiving a value from DevOps releases of the secret to be stored in the key vault"
}
},
"secretName": {
"type": "string",
"metadata": {
"description": "Name of the Secret"
}
},
For the actual deployment
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(variables('keyVaultName'),'/',parameters('secretName'))]",
"apiVersion": "2018-02-14",
"properties": {
"contentType": "text/plain",
"value": "[parameters('secretValue')]"
},
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
]
},
And the parameters file doesn't need to have anything in it if these values will be fed from Dev Ops
You need to create a parameter file with the secret / link to Key Vault.
Here's a sample of it:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminLogin": {
"value": "exampleadmin"
},
"adminPassword": {
"reference": {
"keyVault": {
"id": "/subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.KeyVault/vaults/<vault-name>"
},
"secretName": "ExamplePassword"
}
},
"sqlServerName": {
"value": "<your-server-name>"
}
}
}
More info:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/parameter-files
and https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/add-template-to-azure-pipelines

Azure Resource Manager: How to specify optional parameters in linked templates

I'm making use of linked templates to deploy common resources. In this case I'm deploying a VM which has an optional parameter defined AdminPassword that is only required in certain scenarios (namely when the parameter PasswordAuthenticationDisabled is set to false):
"parameters": {
"AdminPassword": {
"type": "securestring",
"defaultValue": null,
"metadata": {
"description": "Password when password-based authentication isn't disabled"
}
},
"PasswordAuthenticationDisabled": {
"type": "bool",
"defaultValue": "true",
"metadata": {
"description": "Should password-based authentication thorugh SSH be disabled"
}
}
}
I'm referencing the linked template as follows:
{
"type": "Microsoft.Resources/deployments",
"name": "[variables('nameDeploymentVmAttacker1')]",
"apiVersion": "2017-05-10",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(variables('urlTemplates'), '/vm/ubuntu-18.04.json')]"
},
"parameters": {
"Name": {
"value": "[variables('nameVmAttacker1')]"
},
"Region": {
"value": "[resourceGroup().location]"
},
"AdminUsername": {
"value": "[parameters('AdminUsername')]"
},
"AdminSshKey": {
"value": "[parameters('AdminSshKey')]"
},
"VmSize": {
"value": "[parameters('VmSize')]"
},
"VnetName": {
"value": "[variables('nameVnet')]"
},
"PasswordAuthenticationDisabled": {
"value": true
}
}
}
}
Without the optional parameter specified. This leads to ARM complaining about the missing parameter: Deployment template validation failed: 'The value for the template parameter 'AdminPassword' at line '25' and column '26' is not provided. Please see https://aka.ms/arm-deploy/#parameter-file for usage details.
How can I tell the calling template to honor the optionality of the parameter and just go with the default value?
Set the defaultValue to something other than null, e.g. an empty string. For this scenario, you can also do something like this: https://github.com/Azure/azure-quickstart-templates/blob/master/100-marketplace-sample/azuredeploy.json#L36

ARM template error 'properties.api' is not valid from parameter file?

I have created parameter file for LogicApp project.
When I try to deploy using this parameter file it is giving following error -
Template deployment returned the following errors:
Resource MICROSOFT.WEB/CONNECTIONS 'demo-sbs' failed with message '{
"error": {
"code": "InvalidRequestContent",
"message": "The request content is not valid and could not be deserialized: 'The 'id' property 'aaaaaaa-aaaa-aaaa-aaaaa-aaaaaaaa/providers/Microsoft.Web/locations/westeurope/managedApis/servicebus' under 'properties.api' is not valid.'."
}
}'
LogicApp.dev.parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"logicAppName": {
"value": "demoapp"
},
"ResourceGroupName": {
"value": "demo1"
},
"logicAppLocation": {
"value": "westeurope"
},
"logicAppEnvironment": {
"value": "DEV"
},
"sbs_Name": {
"value": "demo-sbs"
},
"sbs_Connection_Name": {
"value": "demo-sbs"
},
"sbs_Connection_DisplayName": {
"value": "demo-sbs"
},
"nok_cb2b_we_sbs_connectionString": {
"value": "Endpoint=sb://demo-sbs.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=asdasd/assasad"
},
"LogicAppIntegrationAccountName": {
"value": "intdemo"
},
"subscriptionId": {
"value": "aaaaaaa-aaaa-aaaa-aaaaa-aaaaaaaa"
}
}
}
LogicApp.json (resources section)
"resources": [
{
"type": "MICROSOFT.WEB/CONNECTIONS",
"apiVersion": "2016-06-01",
"name": "[parameters('demo-sbs_Connection_Name')]",
"location": "[parameters('logicAppLocation')]",
"properties": {
"api": {
"id": "[concat(parameters('subscriptionId'), '/providers/Microsoft.Web/locations/', parameters('logicAppLocation'), '/managedApis/', 'servicebus')]"
},
"displayName": "[parameters('demo-sbs_Connection_DisplayName')]",
"parameterValues": {
"connectionString": "[parameters('demo-sbs_connectionString')]"
}
}
}
the problem is with below line -
when I tried to use parameter for subscriptionId like concat(parameters('subscriptionId') it give above error and if I use concat(subscription().id it works fine.
I want to use parameter for subscriptionId also.
This is the correct syntax for what you are doing:
"api":{
"id":"[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/serviceBus')]"
}
Well, thats because thats not how resource id looks like in azure.
/subscriptions/subscription_guid/resourceGroups/resource_group_name/providers/microsoft.insights/components/resource_name
this is how it looks. to créate it you could use resourceId function. Link
Or you can use concat, but you would need to créate the same string, you can use resourceGroup().id to help you with that.

Resources