Avvio rapido: Usare Bicep per creare e pubblicare una definizione di applicazione gestita di Azure

Questo avvio rapido descrive come usare Bicep per creare e pubblicare una definizione di applicazione gestita di Azure nel catalogo di servizi. Le definizioni nel catalogo di servizi sono disponibili per i membri dell'organizzazione.

Per creare e pubblicare una definizione di applicazione gestita nel catalogo di servizi, seguire questa procedura:

  • Usare Bicep per sviluppare il modello e convertirlo in un modello di Azure Resource Manager (modello ARM). Il modello definisce le risorse di Azure distribuite dall'applicazione gestita.
  • Convertire Bicep in JSON con il comando Bicep build. Dopo aver convertito il file in JSON, è consigliabile verificare l'accuratezza del codice.
  • Definire gli elementi dell'interfaccia utente per il portale quando si distribuisce l'applicazione gestita.
  • Creare un pacchetto ZIP contenente i file JSON necessari. Il file del pacchetto ZIP ha un limite di 120 MB per una definizione di applicazione gestita del catalogo di servizi.
  • Pubblicare la definizione di applicazione gestita in modo che sia disponibile nel catalogo di servizi.

Se la definizione dell'applicazione gestita è superiore a 120 MB o se si vuole usare il proprio account di archiviazione per motivi di conformità dell'organizzazione, vedere Avvio rapido: Creare e pubblicare una definizione di applicazione gestita di Azure con una risorsa di archiviazione personalizzata (BYOS, Bring Your Own Storage).

È anche possibile usare Bicep per distribuire una definizione di applicazione gestita dal catalogo di servizi. Per altre informazioni, vedere Avvio rapido: Usare Bicep per distribuire una definizione di applicazione gestita di Azure.

Prerequisiti

Per seguire la procedura descritta in questo articolo, sono necessari gli elementi seguenti:

Creare un file Bicep

Ogni definizione di applicazione gestita include un file denominato mainTemplate.json, Il modello definisce le risorse di Azure da distribuire e non è diverso da un normale modello di ARM. È possibile sviluppare il modello usando Bicep e quindi convertire il file Bicep in JSON.

Aprire Visual Studio Code, creare un file con un nome che fa distinzione tra maiuscole e minuscole mainTemplate.bicep e salvarlo.

Aggiungere il codice Bicep seguente e salvare il file. Definisce le risorse dell'applicazione gestita per distribuire un servizio app, un piano di servizio app e un account di archiviazione.

param location string = resourceGroup().location

@description('App Service plan name.')
@maxLength(40)
param appServicePlanName string

@description('App Service name prefix.')
@maxLength(47)
param appServiceNamePrefix string

@description('Storage account name prefix.')
@maxLength(11)
param storageAccountNamePrefix string

@description('Storage account type allowed values')
@allowed([
  'Premium_LRS'
  'Standard_LRS'
  'Standard_GRS'
])
param storageAccountType string

var appServicePlanSku = 'F1'
var appServicePlanCapacity = 1
var appServiceName = '${appServiceNamePrefix}${uniqueString(resourceGroup().id)}'
var storageAccountName = '${storageAccountNamePrefix}${uniqueString(resourceGroup().id)}'
var appServiceStorageConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};Key=${storageAccount.listKeys().keys[0].value}'

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: appServicePlanName
  location: location
  sku: {
    name: appServicePlanSku
    capacity: appServicePlanCapacity
  }
}

resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = {
  name: appServiceName
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
    siteConfig: {
      appSettings: [
        {
          name: 'AppServiceStorageConnectionString'
          value: appServiceStorageConnectionString
        }
      ]
    }
  }
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: storageAccountType
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

output appServicePlan string = appServicePlan.name
output appServiceApp string = appServiceApp.properties.defaultHostName
output storageAccount string = storageAccount.properties.primaryEndpoints.blob

Convertire Bicep in JSON

Usare PowerShell o l'interfaccia della riga di comando di Azure per compilare il file mainTemplate.json. Passare alla directory in cui è stato salvato il file Bicep ed eseguire il comando build.

bicep build mainTemplate.bicep

Per altre informazioni, vedere il comando Bicep build.

Dopo la conversione del file Bicep in JSON, il file mainTemplate.json corrisponderà all'esempio seguente. È possibile che siano presenti valori diversi nelle proprietà metadata per version e templateHash.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.17.1.54307",
      "templateHash": "1234567891234567890"
    }
  },
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "appServicePlanName": {
      "type": "string",
      "maxLength": 40,
      "metadata": {
        "description": "App Service plan name."
      }
    },
    "appServiceNamePrefix": {
      "type": "string",
      "maxLength": 47,
      "metadata": {
        "description": "App Service name prefix."
      }
    },
    "storageAccountNamePrefix": {
      "type": "string",
      "maxLength": 11,
      "metadata": {
        "description": "Storage account name prefix."
      }
    },
    "storageAccountType": {
      "type": "string",
      "allowedValues": [
        "Premium_LRS",
        "Standard_LRS",
        "Standard_GRS"
      ],
      "metadata": {
        "description": "Storage account type allowed values"
      }
    }
  },
  "variables": {
    "appServicePlanSku": "F1",
    "appServicePlanCapacity": 1,
    "appServiceName": "[format('{0}{1}', parameters('appServiceNamePrefix'), uniqueString(resourceGroup().id))]",
    "storageAccountName": "[format('{0}{1}', parameters('storageAccountNamePrefix'), uniqueString(resourceGroup().id))]"
  },
  "resources": [
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2022-03-01",
      "name": "[parameters('appServicePlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[variables('appServicePlanSku')]",
        "capacity": "[variables('appServicePlanCapacity')]"
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2022-03-01",
      "name": "[variables('appServiceName')]",
      "location": "[parameters('location')]",
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
        "httpsOnly": true,
        "siteConfig": {
          "appSettings": [
            {
              "name": "AppServiceStorageConnectionString",
              "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};Key={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2022-09-01').keys[0].value)]"
            }
          ]
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    },
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('storageAccountType')]"
      },
      "kind": "StorageV2",
      "properties": {
        "accessTier": "Hot"
      }
    }
  ],
  "outputs": {
    "appServicePlan": {
      "type": "string",
      "value": "[parameters('appServicePlanName')]"
    },
    "appServiceApp": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.Web/sites', variables('appServiceName')), '2022-03-01').defaultHostName]"
    },
    "storageAccount": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2022-09-01').primaryEndpoints.blob]"
    }
  }
}

Definire l'esperienza del portale

Un editore definisce l'esperienza del portale per la creazione dell'applicazione gestita. Il file createUiDefinition.json genera l'interfaccia utente del portale. È possibile definire il modo in cui gli utenti specificheranno l'input per ogni parametro usando elementi di controllo, ad esempio elenchi a discesa e caselle di testo.

In questo esempio, l'interfaccia utente richiede di immettere il prefisso del nome del servizio app, il nome del piano di servizio app, il prefisso dell'account di archiviazione e il tipo di account di archiviazione. Durante la distribuzione, le variabili in mainTemplate.json usano la funzione uniqueString per aggiungere una stringa di 13 caratteri ai prefissi dei nomi in modo che i nomi siano univoci a livello globale in Azure.

Aprire Visual Studio Code, creare un file con un nome che fa distinzione tra maiuscole e minuscole createUiDefinition.json e salvarlo.

Aggiungere il codice JSON seguente al file e salvarlo.

{
  "$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": "webAppSettings",
        "label": "Web App settings",
        "subLabel": {
          "preValidation": "Configure the web app settings",
          "postValidation": "Completed"
        },
        "elements": [
          {
            "name": "appServicePlanName",
            "type": "Microsoft.Common.TextBox",
            "label": "App Service plan name",
            "placeholder": "App Service plan name",
            "defaultValue": "",
            "toolTip": "Use alphanumeric characters or hyphens with a maximum of 40 characters.",
            "constraints": {
              "required": true,
              "regex": "^[a-z0-9A-Z-]{1,40}$",
              "validationMessage": "Only alphanumeric characters or hyphens are allowed, with a maximum of 40 characters."
            },
            "visible": true
          },
          {
            "name": "appServiceName",
            "type": "Microsoft.Common.TextBox",
            "label": "App Service name prefix",
            "placeholder": "App Service name prefix",
            "defaultValue": "",
            "toolTip": "Use alphanumeric characters or hyphens with minimum of 2 characters and maximum of 47 characters.",
            "constraints": {
              "required": true,
              "regex": "^[a-z0-9A-Z-]{2,47}$",
              "validationMessage": "Only alphanumeric characters or hyphens are allowed, with a minimum of 2 characters and maximum of 47 characters."
            },
            "visible": true
          }
        ]
      },
      {
        "name": "storageConfig",
        "label": "Storage settings",
        "subLabel": {
          "preValidation": "Configure the storage settings",
          "postValidation": "Completed"
        },
        "elements": [
          {
            "name": "storageAccounts",
            "type": "Microsoft.Storage.MultiStorageAccountCombo",
            "label": {
              "prefix": "Storage account name prefix",
              "type": "Storage account type"
            },
            "toolTip": {
              "prefix": "Enter maximum of 11 lowercase letters or numbers.",
              "type": "Available choices are Standard_LRS, Standard_GRS, and Premium_LRS."
            },
            "defaultValue": {
              "type": "Standard_LRS"
            },
            "constraints": {
              "allowedTypes": [
                "Premium_LRS",
                "Standard_LRS",
                "Standard_GRS"
              ]
            },
            "visible": true
          }
        ]
      }
    ],
    "outputs": {
      "location": "[location()]",
      "appServicePlanName": "[steps('webAppSettings').appServicePlanName]",
      "appServiceNamePrefix": "[steps('webAppSettings').appServiceName]",
      "storageAccountNamePrefix": "[steps('storageConfig').storageAccounts.prefix]",
      "storageAccountType": "[steps('storageConfig').storageAccounts.type]"
    }
  }
}

Per altre informazioni, vedere Introduzione a CreateUiDefinition.

Creare il pacchetto dei file

Aggiungere i due file a un file di pacchetto denominato app.zip. I due file devono trovarsi al livello radice del file con estensione zip. Se i file si trovano all'interno di una cartella, durante la creazione della definizione di applicazione gestita viene visualizzato un errore che indica che i file necessari non sono presenti.

Caricare app.zip in un account di archiviazione di Azure in modo da poterlo usare quando si distribuisce la definizione di applicazione gestita. Il nome dell'account di archiviazione deve essere univoco a livello globale in Azure, la lunghezza deve essere compresa tra 3 e 24 caratteri e deve contenere solo lettere minuscole e numeri. Nel comando sostituire il segnaposto <demostorageaccount>, incluse le parentesi acute (<>), con il nome dell'account di archiviazione univoco.

In Visual Studio Code aprire un nuovo terminale di PowerShell e accedere alla sottoscrizione di Azure.

Connect-AzAccount

Verrà aperto il browser predefinito e richiesto di eseguire l'accesso ad Azure. Per altre informazioni, vedere Accedere con Azure PowerShell.

Dopo la connessione, eseguire i comandi seguenti.

New-AzResourceGroup -Name packageStorageRG -Location westus3

$storageAccount = New-AzStorageAccount `
  -ResourceGroupName packageStorageRG `
  -Name "<demostorageaccount>" `
  -Location westus3 `
  -SkuName Standard_LRS `
  -Kind StorageV2 `
  -AllowBlobPublicAccess $true

$ctx = $storageAccount.Context

New-AzStorageContainer -Name appcontainer -Context $ctx -Permission blob

Set-AzStorageBlobContent `
  -File "app.zip" `
  -Container appcontainer `
  -Blob "app.zip" `
  -Context $ctx

Usare il comando seguente per archiviare l'URI del file di pacchetto in una variabile denominata packageuri. Quando si distribuisce la definizione di applicazione gestita, si usa il valore della variabile.

$packageuri=(Get-AzStorageBlob -Container appcontainer -Blob app.zip -Context $ctx).ICloudBlob.StorageUri.PrimaryUri.AbsoluteUri

Creare la definizione di applicazione gestita

In questa sezione si ottengono informazioni sull'identità da Microsoft Entra ID, si crea un gruppo di risorse e si distribuisce la definizione di applicazione gestita.

Ottenere l'ID gruppo e l'ID della definizione del ruolo

Nel passaggio successivo si selezionerà un gruppo di utenti, un utente o un'applicazione per gestire le risorse per il cliente. Questa identità ha le autorizzazioni per il gruppo di risorse gestite in base al ruolo assegnato. Il ruolo può essere qualsiasi ruolo predefinito di Azure, ad esempio Proprietario o Collaboratore.

Questo esempio usa un gruppo di sicurezza e l'account Microsoft Entra deve essere membro del gruppo. Per ottenere l'ID oggetto del gruppo, sostituire il segnaposto <managedAppDemo> incluse le parentesi acute (<>) con il nome del gruppo. Quando si distribuisce la definizione di applicazione gestita, si usa il valore della variabile.

Per creare un nuovo gruppo di Microsoft Entra, passare a Gestire i gruppi di Microsoft Entra e l'appartenenza a gruppi.

$principalid=(Get-AzADGroup -DisplayName <managedAppDemo>).Id

Recuperare quindi l'ID definizione del ruolo predefinito di Azure a cui concedere l'accesso all'utente, al gruppo o all'applicazione. Quando si distribuisce la definizione di applicazione gestita, si usa il valore della variabile.

$roleid=(Get-AzRoleDefinition -Name Owner).Id

Creare il modello di distribuzione delle definizioni

Usare un file Bicep per distribuire la definizione di applicazione gestita nel catalogo di servizi.

Aprire Visual Studio Code, creare un file con il nome deployDefinition.bicep e salvarlo.

Aggiungere il codice Bicep seguente e salvare il file.

param location string = resourceGroup().location

@description('Name of the managed application definition.')
param managedApplicationDefinitionName string

@description('The URI of the .zip package file.')
param packageFileUri string

@description('Publishers Principal ID that needs permissions to manage resources in the managed resource group.')
param principalId string

@description('Role ID for permissions to the managed resource group.')
param roleId string

var definitionLockLevel = 'ReadOnly'
var definitionDisplayName = 'Sample Bicep managed application'
var definitionDescription = 'Sample Bicep managed application that deploys web resources'

resource managedApplicationDefinition 'Microsoft.Solutions/applicationDefinitions@2021-07-01' = {
  name: managedApplicationDefinitionName
  location: location
  properties: {
    lockLevel: definitionLockLevel
    description: definitionDescription
    displayName: definitionDisplayName
    packageFileUri: packageFileUri
    authorizations: [
      {
        principalId: principalId
        roleDefinitionId: roleId
      }
    ]
  }
}

Per altre informazioni sulle proprietà del modello, vedere Microsoft.Solutions/applicationDefinitions.

lockLevel nel gruppo di risorse gestite impedisce al cliente di eseguire operazioni indesiderate su questo gruppo di risorse. ReadOnly è attualmente il solo livello di blocco supportato. ReadOnly specifica che il cliente è autorizzato solo alla lettura delle risorse presenti nel gruppo di risorse gestite. Le identità degli editori a cui è concesso l'accesso al gruppo di risorse gestito sono esenti dal livello di blocco.

Creare il file di parametri

Il modello di distribuzione della definizione di applicazione gestita richiede l'input per numerosi parametri. Il comando di distribuzione richiede di immettere i valori oppure è possibile creare un file di parametri per i valori. In questo esempio verrà usato un file di parametri per passare i valori dei parametri al comando di distribuzione.

In Visual Studio Code creare un nuovo file denominato deployDefinition.parameters.json e salvarlo.

Aggiungere quanto segue al file dei parametri e salvarlo. Sostituire quindi <placeholder values>, incluse le parentesi acute (<>), con i valori.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "managedApplicationDefinitionName": {
      "value": "sampleBicepManagedApplication"
    },
    "packageFileUri": {
      "value": "<placeholder for the packageFileUri>"
    },
    "principalId": {
      "value": "<placeholder for principalid value>"
    },
    "roleId": {
      "value": "<placeholder for roleid value>"
    }
  }
}

Nella tabella seguente vengono descritti i valori dei parametri per la definizione di applicazione gestita.

Parametro Valore
managedApplicationDefinitionName Nome della definizione di applicazione gestita. Per questo esempio, usare sampleBicepManagedApplication.
packageFileUri Immettere l'URI per il file di pacchetto ZIP. Usare il valore della variabile packageuri. Il formato è https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip.
principalId ID entità di sicurezza dell'editore che necessita delle autorizzazioni per gestire le risorse nel gruppo di risorse gestite. Usare il valore della variabile principalid.
roleId ID ruolo per le autorizzazioni per il gruppo di risorse gestite. Ad esempio Proprietario, Collaboratore, Lettore. Usare il valore della variabile roleid.

Per ottenere i valori delle variabili:

  • Azure PowerShell: in PowerShell digitare $variableName per visualizzare il valore di una variabile.
  • Interfaccia della riga di comando di Azure: in Bash digitare echo $variableName per visualizzare il valore di una variabile.

Distribuire la definizione

Con la distribuzione, la definizione di applicazione gestita diventa disponibile nel catalogo di servizi. Questo processo non distribuisce le risorse dell'applicazione gestita.

Creare un gruppo di risorse denominato bicepDefinitionRG e distribuire la definizione di applicazione gestita.

New-AzResourceGroup -Name bicepDefinitionRG -Location westus3

New-AzResourceGroupDeployment `
  -ResourceGroupName bicepDefinitionRG `
  -TemplateFile deployDefinition.bicep `
  -TemplateParameterFile deployDefinition.parameters.json

Verificare i risultati

Eseguire il comando seguente per verificare che la definizione sia pubblicata nel catalogo di servizi.

Get-AzManagedApplicationDefinition -ResourceGroupName bicepDefinitionRG

Get-AzManagedApplicationDefinition elenca tutte le definizioni disponibili nel gruppo di risorse specificato, ad esempio sampleBicepManagedApplication.

Assicurarsi che gli utenti possano accedere alla definizione

Si ha accesso alla definizione dell'applicazione gestita, ma si vuole assicurarsi che gli altri utenti nell'organizzazione possano accedervi. Concedere loro almeno il ruolo di Lettore per la definizione. Gli utenti potrebbero aver ereditato questo livello di accesso dalla sottoscrizione o dal gruppo di risorse. Per verificare chi può accedere alla definizione e aggiungere utenti o gruppi, passare a Assegnare ruoli di Azure usando il portale di Azure.

Pulire le risorse

Se si intende distribuire la definizione, continuare con la sezione Passaggi successivi che include un collegamento all'articolo per distribuire la definizione con Bicep.

Se la definizione di applicazione gestita è stata completata, è possibile eliminare i gruppi di risorse creati denominati packageStorageRG e bicepDefinitionRG.

Il comando chiede di confermare la rimozione del gruppo di risorse.

Remove-AzResourceGroup -Name packageStorageRG

Remove-AzResourceGroup -Name bicepDefinitionRG

Passaggi successivi

La definizione di applicazione gestita è stata pubblicata. Il passaggio successivo consiste nell'apprendere come distribuire un'istanza di tale definizione.