I am creating an EventGrid API Connection using an ARM Template. It gets created successfully, however, i still have to authenticate it by hand via Azure Portal.
Here is my ARM Template:
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[parameters('azureEventGridConnectionAPIName')]",
"location": "[resourceGroup().location]",
"properties": {
"api": {
"id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/', 'azureeventgrid')]"
},
"displayName": "[parameters('azureEventGridConnectionAPIName')]"
},
"dependsOn": []
}
]
Am i missing something in the template that is responsible for authenticating the Connection right away?
Is there a way to authenticate that connection using for example Azure PowerShell so i can automate that process?
Am i missing something in the template that is responsible for authenticating the Connection right away?
Yes, we could create a service principal authentication during deploy. Following is the demo code.
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[parameters('azureEventGridConnectionAPIName')]",
"location": "[resourceGroup().location]",
"properties": {
"api": {
"id": "[concat('/subscriptions/subscriptionId', '/providers/Microsoft.Web/locations/', 'eastasia', '/managedApis/', 'azureeventgrid')]"
},
"parameterValues": {
"token:clientId": "[parameters('clientId')]",
"token:clientSecret": "[parameters('clientSecret')]",
"token:TenantId": "[parameters('TenantId')]",
"token:grantType": "[parameters('grantType')]"
},
"displayName": "[parameters('azureEventGridConnectionAPIName')]"
},
"dependsOn": []
}
]
Parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"azureEventGridConnectionAPIName": {
"value": "azureEventGridConnectionAPIName"
},
"clientId": {
"value": "clientId"
},
"clientSecret": {
"value": "secret key"
},
"TenantId": {
"value": "tenant id"
},
"grantType": {
"value": "client_credentials"
}
}
}
Related
I am trying to build an ARM template file for my Azure project. My requirement here is to,
Create a Log Analytics Workspace
Create an Automation Account
Create a variable in the Automation Account that stores the workspace id of Log Analytics Workspace.
This is pretty simple via portal but is there a way to do the same using ARM Templates?
I am using the below code but I get "Invalid JSON - Kindly check the value of the variable." error.
Here's the below ARM template snippet:
{
"type": "Microsoft.Automation/automationAccounts/variables",
"apiVersion": "2022-08-08",
"name": "[concat(parameters('automationAccount_name'), '/', parameters('automationAccount_logAnalytics_workspaceId_variable_name'))]",
"dependsOn": [
"[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccount_name'))]"
],
"properties": {
"isEncrypted": true,
"value": "[reference(resourceId('Microsoft.OperationalInsights/workspaces', parameters(<workspace_name>))).customerId]",
"description": "The Workspace ID of Log Analytics Workspace."
}
}
With the help of this arm template, I created a template with few changes to link workspace and automation account by storing in a variable and was able to do it successfully as follows:
deploy.json:
"resources": [
{
"type": "Microsoft.OperationalInsights/workspaces",
"apiVersion": "2020-08-01",
"name": "[parameters('workspace')]",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "[parameters('sku')]"
}
}
},
{
"type": "Microsoft.Automation/automationAccounts",
"apiVersion": "2020-01-13-preview",
"name": "[parameters('automationAccount')]",
"location": "[parameters('automationAccountLocation')]",
"dependsOn": [
"[parameters('workspace')]"
],
"properties": {
"sku": {
"name": "Basic"
}
}
},
{
"type": "Microsoft.OperationalInsights/workspaces/linkedServices",
"apiVersion": "2020-08-01",
"name": "[concat(parameters('workspace'), '/' , 'Automation')]",
"location": "[parameters('location')]",
"dependsOn": [
"[parameters('workspace')]",
"[parameters('automationAccount')]"
],
"properties": {
"resourceId": "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccount'))]"
}
}
]
}
Parameters.json:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sku": {
"value": "xxxx"
},
"workspace": {
"value": "myworkspace"
},
"automationAccount": {
"value": "myautomation"
}
}
}
Deployment succeeded:
Output after deployment:
We need to have a Function App created for accessing Office 365 instance. The access is using Certificate authentication. Hence we are uploading the certificate into Azure Key Vault and need to import the Certificate from Key Vault.
We are using ARM Templates for the Azure Resource Deployment. We are trying to create Azure Key Vault Certificate as mentioned in the link
https://erwinstaal.nl/posts/using-an-arm-template-to-deploy-your-ssl-certificate-stored-in-keyvault-on-an-web-app/
upload .pfx certificate through azure devops pipeline
As mentioned in the above pages, we are able to create new secrets in Key Vault. But, we do not see the imported certificate in the list of Certificates (when checked in the Azure Portal UI) and also, we are not able to Import the Certificates in the Function App. Is this not supported in the current ARM Template Key Vault commandlet? How can this be fixed?
As mentioned in the above pages, we are able to create new secrets in
Key Vault. But, we do not see the imported certificate in the list of
Certificates (when checked in the Azure Portal UI)
This is because ARM Template doesn't have a property to upload a certificate so instead it stores a base64 encoded value of the PFX certificate in the Secret in a application/x-pkcs12 like below :
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVault": {
"type": "string",
"defaultValue" :"funccertimporttestkv"
},
"TestCedential_1": {
"type": "secureString",
"defaultValue":"MIIKYAIBAzCCChwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXhp4XPejOrOIgc9/6dkfBBSgxY73wtbf+G3N7KTYP1LKKHS0YwICB9A="
},
"TestCedentialName_1": {
"type": "string",
"defaultValue": "funcAppValidationCert"
}
},
"variables": {
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(parameters('keyVault'), '/', parameters('TestCedentialName_1'))]",
"apiVersion": "2015-06-01",
"properties": {
"contentType": "application/x-pkcs12",
"value": "[parameters('TestCedential_1')]"
}
}
],
"outputs": {}
}
we are not able to Import the Certificates in the Function App. Is
this not supported in the current ARM Template Key Vault commandlet?
How can this be fixed?
If you are using a template like below :
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"envName": {
"defaultValue": "qa",
"type": "String"
},
"certificateName": {
"type": "string",
"defaultValue": "funcAppValidationCert"
},
"domainName": {
"type": "string",
"defaultValue": "localhost"
},
"keyvaultName": {
"type": "string",
"defaultValue": "funccertimporttestkv"
},
"password": {
"type": "string",
"defaultValue": "Password#1234"
}
},
"variables":{
"functionStorageAccountName" :"[concat('storaccfn',parameters('envName'),resourceGroup().location)]",
"appServicePlanName" :"[concat('plan-myapp-',parameters('envName'),resourceGroup().location)]",
"sitesFunctionAppName" :"[concat('func-ans-',parameters('envName'),resourceGroup().location)]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-04-01",
"name": "[variables('functionStorageAccountName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"properties": {
"supportsHttpsTrafficOnly": true
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-02-01",
"name": "[variables('appServicePlanName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"kind": "app",
"properties": {
"perSiteScaling": false,
"maximumElasticWorkerCount": 1,
"isSpot": false,
"reserved": false,
"isXenon": false,
"hyperV": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[variables('sitesFunctionAppName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('functionStorageAccountName'))]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"enabled": true,
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
"httpsOnly": true,
"siteConfig": {
"appSettings":[
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionStorageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('functionStorageAccountName')),'2017-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('functionStorageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('functionStorageAccountName')),'2017-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(variables('sitesFunctionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "1"
},
{
"name": "WEBSITE_TIME_ZONE",
"value": "UTC"
}
]
}
}
},
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2016-08-01",
"name": "[concat(variables('sitesFunctionAppName'), '/', parameters('domainName'))]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/certificates', parameters('certificateName'))]",
"[resourceId('Microsoft.Web/sites', variables('sitesFunctionAppName'))]"
],
"properties": {
"siteName": "[variables('sitesFunctionAppName')]",
"hostNameType": "Verified",
"sslState": "SniEnabled",
"thumbprint": "[reference(resourceId('Microsoft.Web/certificates', parameters('certificateName'))).Thumbprint]"
}
},
{
"type": "Microsoft.Web/certificates",
"name": "[parameters('certificateName')]",
"apiVersion": "2016-03-01",
"location": "[resourceGroup().location]",
"properties": {
"keyVaultId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyvaultName'))]",
"keyVaultSecretName": "[parameters('certificateName')]",
"password": "[parameters('password')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
},
"dependsOn":[
"[resourceId('Microsoft.Web/sites', variables('sitesFunctionAppName'))]"
]
}
]
}
And facing a Problem of Bad Request which says not able to access the keyvault like below:
Then Add Microsoft.Azure.CertificateRegistration (i.e. ObjectId : ed47c2a1-bd23-4341-b39c-f4fd69138dd3) , Microsoft Azure App Service (Internal) (i.e. ObjectId : 505e3754-d8a9-4f8b-97b6-c3e48ac7a543) & Microsoft Azure App Service (i.e. ObjectId : f8daea97-62e7-4026-becf-13c2ea98e8b4) in access policy for keyvault.
And If you get the below after solving the above then please check if you have converted the certificate value to a proper base64 encoded value.
Then you can refer this SO thread to properly provide a base64 value of the certificate.
Output:
After successful deployment you can see this TLS/SSL settings :
Can anyone help me find the client secret for a system assigned identity in an ARM template, or suggest an alternative approach?
I've got an ARM template which creates a Logic App with system assigned identity, and now I want to set up an API connection to trigger from Event Grid (without using the portal UI or a separate powershell command).
I can't figure out how to get the client secret for the system assigned identity. This would allow me to follow the answers in these previous questions:
Create API Connection for Azure Data Factory with service principal authentication using ARM Template
How to authenticate an Azure EventGrid API Connection using a script?
Here's what I have so far:
"resources": [
{
"apiVersion": "2016-06-01",
"type": "Microsoft.logic/workflows",
"name": "[variables('logicName')]",
"location": "[resourceGroup().location]",
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[variables('connections_azuretables_name')]"
],
"properties": {
"state": "Enabled",
"definition": {
<<SNIP>>
}
}
},
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('azureEventGridConnectionAPIName')]",
"location": "[resourceGroup().location]",
"properties": {
"api": {
"id": "[concat('/subscriptions/subscriptionId', '/providers/Microsoft.Web/locations/', 'eastasia', '/managedApis/', 'azureeventgrid')]"
},
"parameterValues": {
"token:clientId": "[reference(variables('logicName'), '2016-06-01', 'Full').identity.principalId]",
"token:clientSecret": "########### STUCK HERE #################",
"token:TenantId": "[reference(variables('logicName'), '2016-06-01', 'Full').identity.tenantId]",
"token:grantType": "client_credentials"
},
"displayName": "[variables('azureEventGridConnectionAPIName')]"
},
"dependsOn": []
}
],
A managed identity has no client secret. It only has certificates, which you cannot access.
The template would have to execute within the logic app to get the access token, which I doubt it can do.
For anyone wondering, it is pretty straightforward to create a Service Principal manually and then feed it into the ARM template:
> az ad sp create-for-rbac --name MyPrincipal
{
"appId": "##############",
"displayName": "MyPrincipal",
"name": "http://MyPrincipal",
"password": "##############",
"tenant": "##############"
}
Now pass the appId (as clientId) password (as clientSecret) and tenant (as tenantId) into the parameterValues block in Microsoft.Web/connections. This will set up an Event Grid API connection for your logic app, but with implications for access policies and overhead of identity management outside of the ARM template.
The actual solution I've used is to create a webhook event subscription on Event Grid and then set up my logic app to have a web hook trigger. This works just fine.
Here's a sample solution:
{
"name": "[parameters('topicName')]",
"type": "Microsoft.EventGrid/topics",
"location": "[resourceGroup().location]",
"apiVersion": "2018-01-01",
"properties": { }
},
{
"name": "[concat(parameters('topicName'), '/Microsoft.EventGrid/', variables('topicSubscriptionName'))]",
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"location": "[resourceGroup().location]",
"apiVersion": "2018-01-01",
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": "[listCallbackURL(resourceId('Microsoft.Logic/workflows/triggers', parameters('logicName'), 'WorkaroundWebhookTrigger'), '2016-06-01').value]"
}
},
"filter": {
"includedEventTypes": [
"All"
]
}
},
"dependsOn": [
"[parameters('topicName')]",
"[parameters('logicName')]"
]
},
{
"apiVersion": "2016-06-01",
"type": "Microsoft.logic/workflows",
"name": "[parameters('logicName')]",
"location": "[resourceGroup().location]",
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [],
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"WorkaroundWebhookTrigger": {
"type": "Request",
"kind": "Http",
"inputs": {
"schema": {
"properties": {
"data": {
"properties": {
"lorem": {
"type": "integer"
},
"ipsum": {
"type": "string"
}
},
"type": "object"
},
"dataVersion": {
"type": "string"
},
"eventTime": {
"type": "string"
},
"eventType": {
"type": "string"
},
"id": {
"type": "string"
},
"metadataVersion": {
"type": "string"
},
"subject": {
"type": "string"
},
"topic": {
"type": "string"
}
},
"type": "object"
}
}
}
},
<snip>
In logic app i'm using salesforce connector after deployment i observe for api connection while authorize i'm getting login.salesforce.com but i want it as test.salesforce.com which is sandbox url.
Is there any way to define that ?
below parameters are there in logic app currently unable to see anything to define url.
"parameters": {
"$connections": {
"value": {
"SalesforceConnection": {
"id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', 'southcentralus', '/managedApis/', 'salesforce')]",
"connectionId": "[resourceId('Microsoft.Web/connections', parameters('salesforce_conn_name'))]",
"connectionName": "[parameters('salesforce_conn_name')]"
}
}
}
}
{
"type": "MICROSOFT.WEB/CONNECTIONS",
"apiVersion": "2016-06-01",
"name": "[parameters('salesforce_conn_name')]",
"location": "southcentralus",
"properties": {
"api": {
"id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', 'southcentralus', '/managedApis/', 'salesforce')]"
},
"displayName": "[parameters('salesforce_conn_name')]"
}
}
You are not passing the parameterValues, use the below ARM template and it should work connecting to sandbox environment:
{
"type": "MICROSOFT.WEB/CONNECTIONS",
"apiVersion": "2016-06-01",
"name": "salesforceapiconnection",
"location": "[resourceGroup().location]",
"properties": {
"api": {
"id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', 'centralus', '/managedApis/', 'salesforce')]"
},
"displayName": "Salesforce API Connection",
"parameterValues": {
//The Salesforce Login URI. For Production, use https://login.salesforce.com
"token:LoginUri": "[if(equals(parameters('environment'), 'production'), 'https://login.salesforce.com', 'https://test.salesforce.com')]",
"salesforceApiVersion": "v47",
"privacySetting": "Organizational"
}
}
}
I have a site with custom hostnames configured with hostnameBindings in the ARM template. This deploys fine.
I have also the SSL certificate created and verified from Azure, with the corresponding thumbprint.
In the Azure site I am also able to bind the certificate to the app service.
But when I use the ARM template to assign the SSL from the template in the hostnameBindings it gives an error that the certificate was not found...
I don't understand what goes wrong...
My guesses:
the certificate is in a different resource group so it cannot be
found, but in the template settings I cannot set the group.
in the Azure website before I can use the SSL I have to import, so maybe I am missing this step in the ARM template?
using wrong thumbprint?
In the hostnameBindings I am defining only the thumbprint and the sslState
Any idea which step I am missing?
thank you
UPDATE
My parameter json file:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.5.0.8",
"parameters": {
"baseResourceName": {
"value": "base-name"
},
"environments": {
"value": [
"preview"
]
},
"hostNames": {
"value": [
{
"name": "myhostname.example.com",
"sslState": "SniEnabled",
"thumbprint": "9897LKJL88KHKJH8888KLJLJLJLKJLJLKL4545"
},
{
"name": "myhostname2.example.com"
}
]
},
"ipSecurityRestrictions": {
"value": []
}
}
}
My template json file:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.5.0.8",
"parameters": {
"hostName": {
"defaultValue": [],
"type": "array",
"metadata": {
"description": "The custom hostnames of sites"
}
}
},
"variables": {
"standardPlanMaxAdditionalSlots": 4,
"appName": "[concat(parameters('baseResourceName'), '-private')]",
"appServicePlanName": "[concat(parameters('baseResourceName'), '-appServicePlan')]",
"appInsightName": "[concat(parameters('baseResourceName'), '-appInsight')]",
"ipSecurityRestrictions": "[parameters('ipSecurityRestrictions')]"
},
"resources": [
{
"type": "Microsoft.Web/serverfarms",
"comments": "AppPlan for app.",
"sku": {
"name": "[if(lessOrEquals(length(parameters('environments')), variables('standardPlanMaxAdditionalSlots')), 'S1', 'P1')]"
},
"tags": {
"displayName": "AppServicePlan-Private"
},
"name": "[variables('appServicePlanName')]",
"kind": "app",
"apiVersion": "2016-09-01",
"location": "[resourceGroup().location]",
"properties": {},
"dependsOn": []
},
{
"type": "Microsoft.Web/sites",
"comments": "This is the private web app.",
"kind": "app",
"apiVersion": "2016-03-01",
"name": "[variables('appName')]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "WebApp"
},
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
"siteConfig": {
"appSettings": [],
"phpVersion": "",
"ipSecurityRestrictions": "[variables('ipSecurityRestrictions')]",
"http20Enabled": true,
"minTlsVersion": "1.2"
}
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
"[resourceId('microsoft.insights/components/', variables('appInsightName'))]"
]
},
{
"type": "Microsoft.Web/sites/hostnameBindings",
"name": "[concat(variables('appName'), '/', parameters('hostName')[copyIndex()].Name)]",
"apiVersion": "2016-03-01",
"location": "[resourceGroup().location]",
"properties": "[parameters('hostName')[copyIndex()]]",
"condition": "[greater(length(parameters('hostName')), 0)]",
"copy": {
"name": "hostnameCopy",
"count": "[length(parameters('hostName'))]",
"mode": "Serial"
},
"dependsOn": [
"[concat('Microsoft.Web/sites/',variables('appName'))]"
]
}
]
}
completely unrelated, did you test your condition greater(..., 0) with zero length array? pretty sure it will blow up.
on the subject. i think you can maybe make it work if you link your certificate resource to the app service plan. so this is an operation that is performed on the certificate resource. this is totally possible if you use keyvault to store the certificate
{
"apiVersion": "2016-03-01",
"name": "[variables('certificateName')]",
"location": "[resourceGroup().location]",
"type": "Microsoft.Web/certificates",
"dependsOn": [
"[parameters('appServicePlan')]"
],
"properties": {
"keyVaultId": "kvResourceId",
"keyVaultSecretName": "secretName",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlan'))]"
}
}