Quickstart: Create and publish an Azure Managed Application definition
This quickstart provides an introduction to working with Azure Managed Applications. You create and publish a managed application that's stored in your service catalog and is intended for members of your organization.
To publish a managed application to your service catalog, do the following tasks:
- Create an Azure Resource Manager template (ARM template) that defines the resources to deploy with the managed application.
- Define the user interface elements for the portal when deploying the managed application.
- Create a .zip package that contains the required template files. The .zip package file has a 120-MB limit for a service catalog's managed application definition.
- Decide which user, group, or application needs access to the resource group in the user's subscription.
- Create the managed application definition that points to the .zip package and requests access for the identity.
Optional: If you want to deploy your managed application definition with an ARM template in your own storage account, see bring your own storage.
Note
Bicep files can't be used in a managed application. You must convert a Bicep file to ARM template JSON with the Bicep build command.
Prerequisites
To complete this quickstart, you need the following items:
- An Azure account with an active subscription. If you don't have an account, create a free account before you begin.
- Visual Studio Code with the latest Azure Resource Manager Tools extension.
- Install the latest version of Azure PowerShell or Azure CLI.
Create the ARM template
Every managed application definition includes a file named mainTemplate.json. The template defines the Azure resources to deploy and is no different than a regular ARM template.
Open Visual Studio Code, create a file with the case-sensitive name mainTemplate.json and save it.
Add the following JSON and save the file. It defines the parameters for creating a storage account, and specifies the properties for the storage account.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountNamePrefix": {
"type": "string",
"maxLength": 11,
"metadata": {
"description": "Storage prefix must be maximum of 11 characters with only lowercase letters or numbers."
}
},
"storageAccountType": {
"type": "string"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"storageAccountName": "[concat(parameters('storageAccountNamePrefix'), uniqueString(resourceGroup().id))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-09-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"kind": "StorageV2",
"properties": {}
}
],
"outputs": {
"storageEndpoint": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), '2021-09-01').primaryEndpoints.blob]"
}
}
}
Define your create experience
As a publisher, you define the portal experience for creating the managed application. The createUiDefinition.json file generates the portal interface. You define how users provide input for each parameter using control elements including drop-downs, text boxes, and password boxes.
Open Visual Studio Code, create a file with the case-sensitive name createUiDefinition.json and save it.
Add the following JSON to the file and save it.
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"basics": [
{}
],
"steps": [
{
"name": "storageConfig",
"label": "Storage settings",
"subLabel": {
"preValidation": "Configure the infrastructure settings",
"postValidation": "Done"
},
"bladeTitle": "Storage settings",
"elements": [
{
"name": "storageAccounts",
"type": "Microsoft.Storage.MultiStorageAccountCombo",
"label": {
"prefix": "Storage account name prefix",
"type": "Storage account type"
},
"defaultValue": {
"type": "Standard_LRS"
},
"constraints": {
"allowedTypes": [
"Premium_LRS",
"Standard_LRS",
"Standard_GRS"
]
}
}
]
}
],
"outputs": {
"storageAccountNamePrefix": "[steps('storageConfig').storageAccounts.prefix]",
"storageAccountType": "[steps('storageConfig').storageAccounts.type]",
"location": "[location()]"
}
}
}
To learn more, see Get started with CreateUiDefinition.
Package the files
Add the two files to a file named app.zip. The two files must be at the root level of the .zip file. If you put the files in a folder, you receive an error that states the required files aren't present when you create the managed application definition.
Upload the package to an accessible location from where it can be consumed. The storage account name must be globally unique across Azure and the length must be 3-24 characters with only lowercase letters and numbers. In the Name
parameter, replace the placeholder demostorageaccount
with your unique storage account name.
New-AzResourceGroup -Name storageGroup -Location eastus
$storageAccount = New-AzStorageAccount `
-ResourceGroupName storageGroup `
-Name "demostorageaccount" `
-Location eastus `
-SkuName Standard_LRS `
-Kind StorageV2
$ctx = $storageAccount.Context
New-AzStorageContainer -Name appcontainer -Context $ctx -Permission blob
Set-AzStorageBlobContent `
-File "D:\myapplications\app.zip" `
-Container appcontainer `
-Blob "app.zip" `
-Context $ctx
Create the managed application definition
In this section you'll get identity information from Azure Active Directory, create a resource group, and create the managed application definition.
Create an Azure Active Directory user group or application
The next step is to select a user group, user, or application for managing the resources for the customer. This identity has permissions on the managed resource group according to the role that's assigned. The role can be any Azure built-in role like Owner or Contributor. To create a new Active Directory user group, see Create a group and add members in Azure Active Directory.
This example uses a user group, so you need the object ID of the user group to use for managing the resources. Replace the placeholder mygroup
with your group's name.
$groupID=(Get-AzADGroup -DisplayName mygroup).Id
Get the role definition ID
Next, you need the role definition ID of the Azure built-in role you want to grant access to the user, user group, or application. Typically, you use the Owner, Contributor, or Reader role. The following command shows how to get the role definition ID for the Owner role:
$roleid=(Get-AzRoleDefinition -Name Owner).Id
Create the managed application definition
If you don't already have a resource group for storing your managed application definition, create a new resource group.
Optional: If you want to deploy your managed application definition with an ARM template in your own storage account, see bring your own storage.
New-AzResourceGroup -Name appDefinitionGroup -Location westcentralus
Create the managed application definition resource. In the Name
parameter, replace the placeholder demostorageaccount
with your unique storage account name.
The blob
command that's run from Azure PowerShell or Azure CLI creates a variable that's used to get the URL for the package .zip file. That variable is used in the command that creates the managed application definition.
$blob = Get-AzStorageBlob -Container appcontainer -Blob app.zip -Context $ctx
New-AzManagedApplicationDefinition `
-Name "ManagedStorage" `
-Location "westcentralus" `
-ResourceGroupName appDefinitionGroup `
-LockLevel ReadOnly `
-DisplayName "Managed Storage Account" `
-Description "Managed Azure Storage Account" `
-Authorization "${groupID}:$roleid" `
-PackageFileUri $blob.ICloudBlob.StorageUri.PrimaryUri.AbsoluteUri
When the command completes, you have a managed application definition in your resource group.
Some of the parameters used in the preceding example are:
resource group: The name of the resource group where the managed application definition is created.
lock level: The type of lock placed on the managed resource group. It prevents the customer from performing undesirable operations on this resource group. Currently,
ReadOnly
is the only supported lock level. WhenReadOnly
is specified, the customer can only read the resources present in the managed resource group. The publisher identities that are granted access to the managed resource group are exempt from the lock.authorizations: Describes the principal ID and the role definition ID that are used to grant permission to the managed resource group.
- Azure PowerShell:
"${groupid}:$roleid"
or you can use curly braces for each variable"${groupid}:${roleid}"
. Use a comma to separate multiple values:"${groupid1}:$roleid1", "${groupid2}:$roleid2"
. - Azure CLI:
"$groupid:$roleid"
or you can use curly braces as shown in PowerShell. Use a space to separate multiple values:"$groupid1:$roleid1" "$groupid2:$roleid2"
.
- Azure PowerShell:
package file URI: The location of a .zip package file that contains the required files.
Bring your own storage for the managed application definition
This section is optional. You can store your managed application definition in your own storage account so that its location and access can be managed by you for your regulatory needs. The .zip package file has a 120-MB limit for a service catalog's managed application definition.
Note
Bring your own storage is only supported with ARM template or REST API deployments of the managed application definition.
Create your storage account
You must create a storage account that will contain your managed application definition for use with a service catalog. The storage account name must be globally unique across Azure and the length must be 3-24 characters with only lowercase letters and numbers.
This example creates a new resource group named byosStorageRG
. In the Name
parameter, replace the placeholder definitionstorage
with your unique storage account name.
New-AzResourceGroup -Name byosStorageRG -Location eastus
New-AzStorageAccount `
-ResourceGroupName byosStorageRG `
-Name "definitionstorage" `
-Location eastus `
-SkuName Standard_LRS `
-Kind StorageV2
Use the following command to store the storage account's resource ID in a variable named storageId
. You'll use this variable when you deploy the managed application definition.
$storageId = (Get-AzStorageAccount -ResourceGroupName byosStorageRG -Name definitionstorage).Id
Set the role assignment for your storage account
Before your managed application definition can be deployed to your storage account, assign the Contributor role to the Appliance Resource Provider user at the storage account scope. This assignment lets the identity write definition files to your storage account's container.
In PowerShell, you can use variables for the role assignment. This example uses the $storageId
you created in a previous step and creates the $arpId
variable.
$arpId = (Get-AzADServicePrincipal -SearchString "Appliance Resource Provider").Id
New-AzRoleAssignment -ObjectId $arpId `
-RoleDefinitionName Contributor `
-Scope $storageId
The Appliance Resource Provider is a service principal in your Azure Active Directory's tenant. From the Azure portal, you can see if it's registered by going to Azure Active Directory > Enterprise applications and change the search filter to Microsoft Applications. Search for Appliance Resource Provider. If it's not found, register the Microsoft.Solutions
resource provider.
Deploy the managed application definition with an ARM template
Use the following ARM template to deploy your packaged managed application as a new managed application definition in your service catalog. The definition files are stored and maintained in your storage account.
Open Visual Studio Code, create a file with the name azuredeploy.json and save it.
Add the following JSON and save the file.
{
"$schema": "http://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"applicationName": {
"type": "string",
"metadata": {
"description": "Managed Application name."
}
},
"definitionStorageResourceID": {
"type": "string",
"metadata": {
"description": "Storage account's resource ID where you're storing your managed application definition."
}
},
"packageFileUri": {
"type": "string",
"metadata": {
"description": "The URI where the .zip package file is located."
}
}
},
"variables": {
"lockLevel": "None",
"description": "Sample Managed application definition",
"displayName": "Sample Managed application definition",
"managedApplicationDefinitionName": "[parameters('applicationName')]",
"packageFileUri": "[parameters('packageFileUri')]",
"defLocation": "[parameters('definitionStorageResourceID')]"
},
"resources": [
{
"type": "Microsoft.Solutions/applicationDefinitions",
"apiVersion": "2021-07-01",
"name": "[variables('managedApplicationDefinitionName')]",
"location": "[parameters('location')]",
"properties": {
"lockLevel": "[variables('lockLevel')]",
"description": "[variables('description')]",
"displayName": "[variables('displayName')]",
"packageFileUri": "[variables('packageFileUri')]",
"storageAccountId": "[variables('defLocation')]"
}
}
],
"outputs": {}
}
For more information about the ARM template's properties, see Microsoft.Solutions/applicationDefinitions. Managed applications only use ARM template JSON.
Deploy the definition
Create a resource group named byosDefinitionRG and deploy the managed application definition to your storage account.
New-AzResourceGroup -Name byosDefinitionRG -Location eastus
$storageId
New-AzResourceGroupDeployment `
-ResourceGroupName byosDefinitionRG `
-TemplateFile .\azuredeploy.json
You'll be prompted for three parameters to deploy the definition.
Parameter | Value |
---|---|
applicationName |
Choose a name for your managed application definition. For this example, use sampleManagedAppDefintion. |
definitionStorageResourceID |
Enter your storage account's resource ID. You created the storageId variable with this value in an earlier step. Don't wrap the resource ID with quotes. |
packageFileUri |
Enter the URI to your .zip package file. Use the URI for the .zip package file you created in an earlier step. The format is https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip . |
Verify definition files storage
During deployment, the template's storageAccountId
property uses your storage account's resource ID and creates a new container with the case-sensitive name applicationdefinitions
. The files from the .zip package you specified during the deployment are stored in the new container.
You can use the following commands to verify that the managed application definition files are saved in your storage account's container. In the Name
parameter, replace the placeholder definitionstorage
with your unique storage account name.
Get-AzStorageAccount -ResourceGroupName byosStorageRG -Name definitionstorage |
Get-AzStorageContainer -Name applicationdefinitions |
Get-AzStorageBlob | Select-Object -Property *
Note
For added security, you can create a managed applications definition and store it in an Azure storage account blob where encryption is enabled. The definition contents are encrypted through the storage account's encryption options. Only users with permissions to the file can see the definition in your service catalog.
Make sure users can see your definition
You have access to the managed application definition, but you want to make sure other users in your organization can access it. Grant them at least the Reader role on the definition. They may have inherited this level of access from the subscription or resource group. To check who has access to the definition and add users or groups, see Assign Azure roles using the Azure portal.
Next steps
You've published the managed application definition. Now, learn how to deploy an instance of that definition.
Feedback
Submit and view feedback for