Is it possible to upload APNS Certificates to the azure notification hub programatically or via the CLI - azure

We are investigating the azure notification hub, and while we have had success sending/receiving messages from it, we also require programatic configuration of the hub.
It seems that the only way possible to create the notification hub is via the azure cli with an azuredeploy.json ARM template like this one. However, I can't find any information about adding an APNS certificate to that.
Looking at the Automation Script generated from our hub, there is no evidence of the google firebase API key or the APNS certificate. Is this possible or do these need to be done through the azure portal at all times.
UPDATED: I have managed to create a notification hub namespace using the arm template with little issue, however I am getting a "bad request" (correlation id - 3faee649-7084-436d-8d7e-4a9c6f79cc4e) when trying to create the notification hub itself with the apns certificate.
this post is someone having a similar problem, however their key for the apns is a lot shorter than mine. I literally created a base64 string from the certificate file which is 5000+ characters wrong, I assume that is incorrect, but I can't figure out what value from apple is meant to go in here.
My template looks like this:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Gcm.GoogleApiKey": {
"type": "string",
"metadata": {
"description": "Google Cloud Messaging API Key"
},
"defaultValue": ""
},
"Apns.apnsCertificate": {
"type": "string",
"metadata": {
"description": "A certificate (in base 64 format) provided by Apple on the iOS Provisioning Portal"
}
},
"Apns.certificateKey": {
"type": "string",
"metadata": {
"description": "The Certificate Key provided by the iOS Provisioning Portal when registering the application"
},
"defaultValue": ""
},
"Apns.endpoint": {
"type": "string",
"metadata": {
"description": "The APNS endpoint to which our service connects. This is one of two values: gateway.sandbox.push.apple.com for the sandbox endpoint or gateway.push.apple.com, for the production endpoint. Any other value is invalid"
},
"defaultValue": "gateway.sandbox.push.apple.com"
}
},
"variables": {
"hubVersion": "[providers('Microsoft.NotificationHubs', 'namespaces').apiVersions[0]]",
"notificationHubNamespace": "[concat('hubv2', uniqueString(resourceGroup().id))]",
"notificationHubName": "notificationhub"
},
"resources": [
{
"name": "[variables('NotificationHubNamespace')]",
"location": "[resourceGroup().location]",
"type": "Microsoft.NotificationHubs/namespaces",
"apiVersion": "2017-04-01",
"comments": "Notification hub namespace",
"properties": {
"namespaceType": "NotificationHub"
},
"resources": [
{
"name": "[concat(variables('NotificationHubNamespace'),'/',variables('NotificationHubName'))]",
"location": "[resourceGroup().location]",
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs",
"apiVersion": "2017-04-01",
"properties": {
"GcmCredential": {
"properties": {
"googleApiKey": "[parameters('Gcm.GoogleApiKey')]",
"gcmEndpoint": "https://android.googleapis.com/gcm/send"
}
},
"apnsCredential": {
"properties": {
"apnsCertificate" : "[parameters('Apns.apnsCertificate')]",
"certificateKey" : "[parameters('Apns.certificateKey')]",
"endpoint" : "[parameters('Apns.endpoint')]"
}
}
},
"dependsOn": [
"[concat('Microsoft.NotificationHubs/namespaces/', variables('NotificationHubNamespace'))]"
]
}
]
}
],
"outputs": {
}
}

In the apnsCredentials property, the apsnCertificate is the base64 string from file and the certificatekey is your certificate password which needs to be a strong password. Are you following the same?
Also, is there an inner error message you see. If yes, what is it?
Thanks,
Amol

Related

How to return Azure Eventhub primary and secondary connection keys as ARM template output?

I have prepared an ARM template for deploying an Azure Eventhub instance and wonder how to access the both connection keys for returning them as output?
I would like to return a string in the form:
Endpoint=sb://my-eventhub.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=ojZMQcJD7uYifxJyGeXG6tNDdZyaC1/h5tmX6ODVfmY=
Here is my current template:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"clusterName": {
"type": "string",
"defaultValue": "eventhub",
"metadata": {
"description": "Name for the Event Hub cluster."
}
},
"namespaceName": {
"type": "string",
"defaultValue": "namespace",
"metadata": {
"description": "Name for the Namespace to be created in cluster."
}
}
},
"variables": {
"clusterName": "[concat(resourceGroup().name, '-', parameters('clusterName'))]",
"namespaceName": "[concat(resourceGroup().name, '-', parameters('namespaceName'))]"
},
"outputs": {
"MyClusterName": {
"type": "string",
"value": "[variables('clusterName')]"
},
"PrimaryConnectionString": {
"type": "string",
"value": "WHAT TO USE HERE PLEASE?"
},
"SecondaryConnectionString": {
"type": "string",
"value": "WHAT TO USE HERE PLEASE?"
}
},
"resources": [
{
"type": "Microsoft.EventHub/clusters",
"apiVersion": "2018-01-01-preview",
"name": "[variables('clusterName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Dedicated",
"capacity": 1
}
},
{
"type": "Microsoft.EventHub/namespaces",
"apiVersion": "2018-01-01-preview",
"name": "[variables('namespaceName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/clusters', variables('clusterName'))]"
],
"sku": {
"name": "Standard",
"tier": "Standard",
"capacity": 1
},
"properties": {
"isAutoInflateEnabled": false,
"maximumThroughputUnits": 0,
"clusterArmId": "[resourceId('Microsoft.EventHub/clusters', variables('clusterName'))]"
}
}
]
}
I have tried the following:
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/AuthorizationRules'), variables('namespaceName'), 'RootManageSharedAccessKey'),'2018-01-01-preview').primaryConnectionString]"
but get deployment error:
[error]ParentResourceNotFound: Can not perform requested operation on nested resource. Parent resource 'my-rg-namespace' not found.
UPDATE:
The following has worked for me as suggested by Jesse (thank you!):
"variables": {
"clusterName": "[concat(resourceGroup().name, '-', parameters('clusterName'))]",
"namespaceName": "[concat(resourceGroup().name, '-', parameters('namespaceName'))]",
"defaultSASKeyName": "RootManageSharedAccessKey",
"authRuleResourceId": "[resourceId('Microsoft.EventHub/namespaces/authorizationRules', variables('namespaceName'), variables('defaultSASKeyName'))]"
},
"outputs": {
"MyClusterName": {
"type": "string",
"value": "[variables('clusterName')]"
},
"PrimaryConnectionString": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), '2015-08-01').primaryConnectionString]"
},
"SecondaryConnectionString": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), '2015-08-01').secondaryConnectionString]"
}
},
UPDATE 2:
Also, Jesse has noticed that my ARM template is wrong in 2 ways, because it does not create an Event Hub, but a cluster and it is outside my namespace and provided this valuable comment:
The Event Hubs cluster is basically a way of reserving dedicated compute. It's not something that most scenarios need and it is... not cheap. Think of something on the scale of Xbox Live where you're seeing nearly 5 millions of events per second and which have higher performance needs. If you're not looking at that kind of scale or that sensitivity around timing, you probably want to rethink the need for a dedicated cluster.
Normally, you'd just provision an Event Hubs namespace which will use shared infrastructure with certain guarantees to minimize noisy neighbors and similar. This is adequate for the majority of scenarios, even those with high throughput needs. If you're not sure, this is probably the place that you want to start and then upgrade to a dedicated cluster if your needs justify the cost.
An Event Hubs namespace is the container for a set of Event Hub instances grouped together by a unique endpoint. Each Event Hub is made of a set of partitions. When you're publishing or consuming events, the partitions of an Event Hub are where the actual data is. When you're working with one of the SDKs, you'll start by telling it about the endpoint of your namespace and the Event Hub that you're interested in. You'll need a general awareness of partitions, but most of the "Getting Started" scenarios handle that detail for you, as do a fair portion of the real-world ones.... but, the concept is an important one.
It looks like you may be using an incorrect resource id, pulling from Microsoft.ServiceBus rather than Microsoft.EventHub where the failure is because there is no Service Bus namespace with the correct name.
You may want to try using a form similar to the following to identify your resource:
"variables": {
"location": "[resourceGroup().location]",
"apiVersion": "2015-08-01",
"defaultSASKeyName": "RootManageSharedAccessKey",
"authRuleResourceId": "[resourceId('Microsoft.EventHub/namespaces/authorizationRules', parameters('namespaceName'), variables('defaultSASKeyName'))]"
},
Which should allow it to be returned using listkeys as you you detailed above:
"outputs": {
"NamespaceConnectionString": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), variables('apiVersion')).primaryConnectionString]"
}
}
A full example for a simple deployment can be found in the Event Hubs sample template.

Using Azure Key vault on Azure Logic App API Connection

I have used Azure Key vault on Azure Logic App. But I couldn't access the values to Azure Logic APP API Connection. Basically I have to get the username and password for SQL connector from Azure Key vault. Apprecait if you can suggest, how we can achieve this.
As far as I know, azure logic app can't access key vault in api connection in portal. If you want to access key vault, you can use rest api to access it.
You need to enable msi in your logic app (the link below shows us we can do msi modification in "Workflow Settings" but currently it has changed we need to enable it in "Identity" blade of your logic app) and use http action to access your key vault.
You can refer to this link for further information: https://devkimchi.com/2018/10/24/accessing-key-vault-from-logic-apps-with-managed-identity/
Once created the connection API will not output any sensitive information.
Using ARM template, you can create an API connection but it won't update the connection details when you rotate the credentials, you'll have to redeploy the template.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sqlConnectionAPIName": {
"type": "string",
"metadata": {
"description": "The name of the connection api to access the service bus namepsace."
}
},
"sqlserverName": {
"type": "string",
"metadata": {
"description": "The Name of the SQL Server instance."
}
},
"databaseName": {
"type": "string",
"metadata": {
"description": "The name of the database."
}
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/connections",
"name": "[parameters('sqlConnectionAPIName')]",
"apiVersion": "2018-07-01-preview",
"location": "[resourceGroup().location]",
"scale": null,
"properties": {
"displayName": "[parameters('sqlConnectionAPIName')]",
"parameterValues": {
"server": "[reference(resourceId('Microsoft.Sql/servers', parameters('sqlserverName')), '2015-05-01-preview').fullyQualifiedDomainName]",
"database": "[parameters('databaseName')]",
"username": "[reference(resourceId('Microsoft.Sql/servers', parameters('sqlserverName')), '2015-05-01-preview').administratorLogin]",
"password": "[reference(resourceId('Microsoft.Sql/servers', parameters('sqlserverName')), '2015-05-01-preview').administratorLoginPassword]"
},
"api": {
"id": "[concat('subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/sql')]"
}
},
"dependsOn": []
}
]
}

Is it possible to create an Azure Blob Storage Connector using a ARM template or a script?

I'm creating a logic app which will do some operations on a blob storage, thus it needs a Connector to a specific blob storage. I'm able to define which Connector should be used (providing its name and other properties), however if it doesn't exist yet, the template fails to deploy. I know we can create these connectors via logic app designer, but i would very much like to automate that process. Hence the question:
Is it possible to deploy/create this connector using an ARM template or a script?
You can check this post related to Logic App connector.
Here is an ARM Template that create an API connection to blob storage:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"azureBlobConnectionAPIName": {
"type": "string",
"metadata": {
"description": "The name of the connection api to access the azure blob storage."
}
},
"storageAccountName": {
"type": "string",
"metadata": {
"description": "The Storage Account Name."
}
}
},
"variables": {
"storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
},
"resources": [
{
"type": "Microsoft.Web/connections",
"name": "[parameters('azureBlobConnectionAPIName')]",
"apiVersion": "2016-06-01",
"location": "[resourceGroup().location]",
"scale": null,
"properties": {
"displayName": "[parameters('azureBlobConnectionAPIName')]",
"parameterValues": {
"accountName": "[parameters('storageAccountName')]",
"accessKey": "[listKeys(variables('storageAccountId'),'2015-05-01-preview').key1]"
},
"api": {
"id": "[concat('subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', parameters('defaultResourceLocation'), '/managedApis/azureblob')]"
}
},
"dependsOn": []
}
]
}

ARM Deployment error Document Db cannot find instance

We are having a deployment error in working deployments since last Thursday AEST.
When we run an ARM deployment DocumentDb fails with the message:
Resource Microsoft.DocumentDB/databaseAccounts 'xxx' failed with message 'Document service name 'xxx' already exists.
{
"apiVersion": "2015-04-08",
"type": "Microsoft.DocumentDB/databaseAccounts",
"name": "[parameters('databaseAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"name": "[parameters('databaseAccountName')]",
"databaseAccountOfferType": "Standard"
}
In the snippet [parameters('databaseAccountName')] = 'xxx'
We are guessing that something underlying has happened to cause this. Can you please let us know the new properties into the ARM template that we need to include for the DocumentDb instance to be found again?
Update: We have updated our documentation to cover ARM deployment for multi-region enabled accounts. https://azure.microsoft.com/documentation/articles/documentdb-automation-resource-manager-cli/#create-multi-documentdb-account
We are in the process of enabling multi-region accoutns for all accounts. As a part of this effort, there is a change in the ARM template. A few accounts are seeing errors when using the currently published template in certain scenarios.
We will be updating our documentation very soon. In the meantime, the below template should get you going. Your old template will also start working in a couple of days.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"databaseAccountName": {
"type": "string"
},
"locationName1": {
"type": "string"
}
},
"variables": { },
"resources": [
{
"apiVersion": "2015-04-08",
“kind”: “GlobalDocumentDB”,
"type": "Microsoft.DocumentDb/databaseAccounts",
"name": "[parameters('databaseAccountName')]",
"location": "[resourceGroup().location]",
"properties": {
"databaseAccountOfferType": "Standard",
"locations": [
{
"id": "[concat(parameters('databaseAccountName'), '-', resourceGroup().location)]",
"failoverPriority": 0,
"locationName": "[parameters('locationName1')]"
}]
}
}]
}
Edit:
locationName1 should be in the format of the "Azure Regions" column on this page: https://azure.microsoft.com/en-us/regions/

Retrieve Service Bus event hub connection string

I have an existing Service Bus with one queue and event hub deployed using Azure Resource Manager.
Now I am interested to retrieve the primary key and connection string using Azure PowerShell wiithout using the ServiceBus.dll. Is it possible??
As a workaround I have created an ARM template which does not deploy anything but just query the existing resource and retrieve the information I need. The below template retrieves the connection string and primary key of an event hub/queue for a specific service bus namespace
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespace": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "The name of the service bus namespace to create."
}
},
"resourceName": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "The name of the resource to be retreived."
}
},
"resourceType": {
"type": "string",
"minLength": 1,
"allowedValues": [
"queues",
"eventhubs"
],
"metadata": {
"description": "The type of the resource"
}
},
"policy": {
"type": "string",
"minLength": 1,
"defaultValue": "ManagePolicy",
"allowedValues": [
"ManagePolicy",
"SendPolicy",
"ListenPolicy"
],
"metadata": {
"description": "The type of the resource"
}
}
},
"variables": {
},
"resources": [ ],
"outputs": {
"connectionString": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/',parameters('resourceType'),'/authorizationRules'),parameters('serviceBusNamespace'),parameters('resourceName'),parameters('policy')),'2015-08-01').primaryConnectionString]"
},
"primaryKey": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/',parameters('resourceType'),'/authorizationRules'),parameters('serviceBusNamespace'),parameters('resourceName'),parameters('policy')),'2015-08-01').primaryKey]"
}
}
}
Is it abusing to use ARM template to query for a resource and not actually deploy anything?
EDIT
To capture the output of the ARM template within PowerShell use the below code
$ep = New-AzureRmResourceGroupDeployment -Name "getEventHub" -ResourceGroupName myResourceGroup -Mode Incremental -TemplateFile getEventHub.json -TemplateParameterFile getEventHub.param.json
$RuleConnString = $ep.Outputs.connectionString.value
$RulePrimaryKey = $ep.Outputs.primaryKey.value
Note that the property names connectionString and primaryKey are same as defined in my template file
EDIT 2
If I re-run the ARM template to deploy the event hub second time I get the below error.
I din't find any option other than to use the ARM template to query the details.
I don’t see what’s wrong with what you’re doing. In my view Resource Manager templates in their nature are incremental. So you could author a template to create your existing service bus with the same resources. If the properties are the same then it will leave the existing resources intact and return you the connection string and primary key of the relevant resource.
I have a need to automate the creation of a service bus and queue and separate send/listen shared access policies. You can retrieve the connection string on the service bus itself using PowerShell natively without using the .Net ServiceBus.dll assembly by using Get-AzureSBAuthorizationRule but due to a still current bug this doesn’t work at the queue level.
I tried using the ServiceBus.dll to create the shared access policies but sometimes it would randomly fail but subsequently work if you ran it a second time immediately afterwards. I also tried Resource Manager templates but previously you had to pass in the keys you’d generated yourself. Now I see Microsoft generate those for you but you’re still left trying to get the key in an automated fashion so I like your solution.
One question though, can you capture the Resource Manager template outputs and pass them back to a PowerShell script, do you know?
Cheers
Rob
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {
"servicebusNamespace": {
"type": "string",
"metadata": {
"description": "The service bus namespace"
}
},
"notificationssmsqueue": {
"type": "string",
"metadata": {
"description": "Notifications SMS queue"
}
} }, "variables": {
"location": "[resourceGroup().location]", }, "resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('servicebusNamespace')]",
"type": "Microsoft.ServiceBus/namespaces",
"location": "[variables('location')]",
"properties": {
"messagingSku": 2
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('notificationssmsqueue')]",
"type": "Queues",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', parameters('servicebusNamespace'))]"
],
"properties": {
"path": "[parameters('notificationssmsqueue')]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[concat(parameters('notificationssmsqueue'),'.listen')]",
"type": "AuthorizationRules",
"dependsOn": [
"[parameters('notificationssmsqueue')]"
],
"properties": {
"keyName": "[concat(parameters('notificationssmsqueue'),'.listen')]",
"claimType": "SharedAccessKey",
"claimValue": "None",
"rights": [ "Listen" ],
"revision": -1
}
},
{
"apiVersion": "2015-08-01",
"name": "[concat(parameters('notificationssmsqueue'),'.send')]",
"type": "AuthorizationRules",
"dependsOn": [
"[parameters('notificationssmsqueue')]"
],
"properties": {
"keyName": "[concat(parameters('notificationssmsqueue'),'.send')]",
"claimType": "SharedAccessKey",
"claimValue": "None",
"rights": [ "Send" ],
"revision": -1
}
}
]
}
]
} ], "outputs": {
"connectionString": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/AuthorizationRules'),parameters('serviceBusNamespace'),'RootManageSharedAccessKey'),'2015-08-01').primaryConnectionString]"
},
"smsSendPrimaryKey": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/Queues/AuthorizationRules'),parameters('serviceBusNamespace'),parameters('notificationssmsqueue'),concat(parameters('notificationssmsqueue'),'.send')),'2015-08-01').PrimaryKey]"
},
"smsListenPrimaryKey": {
"type": "string",
"value": "[listKeys(resourceId(concat('Microsoft.ServiceBus/namespaces/Queues/AuthorizationRules'),parameters('serviceBusNamespace'),parameters('notificationssmsqueue'),concat(parameters('notificationssmsqueue'),'.listen')),'2015-08-01').PrimaryKey]"
} } }
But I call my templates like this:
New-AzureRMResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile "$scripts_folder$SB_create_script" -TemplateParameterObject `
#{ servicebusNamespace = $servicebusNamespace;
notificationssmsqueue = $NotificationSMSqueue }
This is the correct way to get the information you are seeking. The Resource Manager provides a common interface to interact with all the services. It is how the Portal access the services, and each of the language SDKs are just wrappers for similar requests to the one you have created.
I usually use the Python or java SDKs, but I have been told that NodeJS is a very easy way to wrap the Web APIs that ARM calls to construct similar calls like the one you made, if you are looking for a none ARM way to do this.

Resources