Início Rápido: Usar o Bicep para criar e publicar uma definição de Aplicativo Gerenciado do Azure

Esse início rápido descreve como usar o Bicep para criar e publicar uma definição de Aplicativo Gerenciado do Azure no seu catálogo de serviços. As definições no seu catálogo de serviços estão disponíveis para os membros da sua organização.

Para criar e publicar uma definição de aplicativo gerenciado no seu catálogo de serviços, execute as seguintes tarefas:

  • Use o Bicep para desenvolver seu modelo e convertê-lo em um modelo do Azure Resource Manager (modelo do ARM). O modelo define os recursos do Azure implantados pelo aplicativo gerenciado.
  • Converta o Bicep em JSON com o comando build do Bicep. Após o arquivo ter sido convertido em JSON, é recomendável verificar o código quanto à precisão.
  • Defina os elementos da interface do usuário para o portal ao implantar o aplicativo gerenciado.
  • Crie um pacote .zip que contenha os arquivos JSON necessários. O arquivo do pacote .zip tem um limite de 120 MB para uma definição de aplicativo gerenciado do catálogo de serviços.
  • Publique a definição de aplicativo gerenciado para que ela esteja disponível no catálogo de serviços.

Se a definição do aplicativo gerenciado for superior a 120 MB ou se você quiser usar sua própria conta de armazenamento por motivos de conformidade da sua organização, acesse Início Rápido: Traga seu próprio armazenamento para criar e publicar uma definição de Aplicativo Gerenciado do Azure.

Você também pode usar o Bicep para implantar uma definição de aplicativo gerenciado do catálogo de serviços. Para obter mais informações, vá para Início Rápido: Usar o Bicep para implantar uma definição de Aplicativo Gerenciado do Azure.

Pré-requisitos

Para executar as tarefas incluídas neste artigo, você precisará dos seguintes itens:

Criar um arquivo Bicep

Cada definição de aplicativo gerenciado contém um arquivo chamado mainTemplate.json. O modelo define os recursos do Azure a serem implantados e não é diferente de um modelo normal do ARM. Você pode desenvolver o modelo usando o Bicep e, a seguir, converter o arquivo Bicep em JSON.

Abra o Visual Studio Code, crie um arquivo com o nome mainTemplate.bicep diferenciando maiúsculas de minúsculas e salve-o.

Adicione o seguinte código do Bicep e salve o arquivo. Ela define os recursos do aplicativo gerenciado para implantar um plano de Serviço de Aplicativo, Serviço de Aplicativo e uma conta de armazenamento.

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

Converter de Bicep para JSON

Use o PowerShell ou a CLI do Azure para compilar o arquivo mainTemplate.json . Vá para o diretório no qual você salvou seu arquivo Bicep e execute o comando build.

bicep build mainTemplate.bicep

Para saber mais, vá para a compilação do Bicep.

Após o arquivo Bicep ter sido convertido em JSON, seu arquivo mainTemplate.json deverá corresponder ao exemplo a seguir. Você poderá ter valores diferentes nas propriedades de metadata para 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]"
    }
  }
}

Definir a sua experiência do portal

Como publicador, você define a experiência do portal para criar o aplicativo gerenciado. O arquivo createUiDefinition.json gera a interface do usuário do portal. Você define como os usuários fornecem a entrada para cada parâmetro usando elementos de controle, incluindo menus suspensos e caixas de texto.

Nesse exemplo, a interface do usuário solicita que você insira o prefixo do nome do Serviço de Aplicativo, o nome do plano do Serviço de Aplicativo, o prefixo da conta de armazenamento e o tipo de conta de armazenamento. Durante a implantação, as variáveis em mainTemplate.json usam a uniqueString função para acrescentar uma cadeia de caracteres de 13 caracteres aos prefixos de nome para que os nomes sejam globalmente exclusivos no Azure.

Abra o Visual Studio Code, crie um arquivo com o nome createUiDefinition.json diferenciando maiúsculas de minúsculas e salve-o.

Adicione ao arquivo o código JSON a seguir e salve-o.

{
  "$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]"
    }
  }
}

Para saber mais, consulte Introdução a CreateUiDefinition.

Empacote os arquivos

Adicione os dois arquivos a um arquivo de pacote chamado app.zip. Os dois arquivos precisam estar no nível raiz do arquivo .zip. Se você colocar os arquivos em uma pasta, receberá um erro indicando que os arquivos necessários não estão presentes ao criar a definição de aplicativo gerenciado.

Carregue o arquivo app.zip em uma conta de armazenamento do Azure para que você possa usá-la ao implantar a definição do aplicativo gerenciado. O nome da conta de armazenamento deve ser globalmente exclusivo no Azure e o comprimento deve ser de 3 a 24 caracteres com apenas letras minúsculas e números. No comando, substitua o espaço reservado <demostorageaccount>, incluindo os colchetes angulares (<>), pelo nome exclusivo da conta de armazenamento.

No Visual Studio Code, abra um novo terminal do PowerShell e entre em sua assinatura do Azure.

Connect-AzAccount

O comando abre o navegador padrão e solicita que você entre no Azure. Para obter mais informações, vá para Entrar com o Azure PowerShell.

Após se conectar, execute os comandos a seguir.

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

Use o comando a seguir para armazenar o URI do arquivo de pacote em uma variável chamada packageuri. Você usará o valor dessa variável ao implantar a definição de aplicativo gerenciado.

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

Criar a definição de aplicativo gerenciado

Nesta seção, você obtém informações de identidade da ID do Microsoft Entra, cria um grupo de recursos e implanta a definição de aplicativo gerenciado.

Obter ID do grupo e ID de definição de função

A próxima etapa é selecionar um grupo de segurança, um usuário ou um aplicativo para gerenciar os recursos para o cliente. Essa identidade tem permissões no grupo de recursos gerenciados de acordo com a função atribuída. A função pode ser qualquer função interna do Azure, como Proprietário ou Colaborador.

Este exemplo usa um grupo de segurança e sua conta do Microsoft Entra deve ser um membro do grupo. Para obter a ID do objeto do grupo, substitua o espaço reservado <managedAppDemo>, incluindo os colchetes angulares (<>), pelo nome do grupo. Você usará o valor dessa variável ao implantar a definição de aplicativo gerenciado.

Para criar um novo grupo do Microsoft Entra, acesse Gerenciar grupos do Microsoft Entra e associação de grupo.

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

Em seguida, você precisará da ID de definição de função da função interna do Azure para conceder acesso ao usuário, grupo ou aplicativo. Você usará o valor dessa variável ao implantar a definição de aplicativo gerenciado.

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

Criar o modelo de implantação de definição

Use um arquivo Bicep para implantar a definição de aplicativo gerenciado em seu catálogo de serviços.

Abra o Visual Studio Code, crie um arquivo com o nome deployDefinition.bicep e salve-o.

Adicione o seguinte código do Bicep e salve o arquivo.

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
      }
    ]
  }
}

Para obter mais informações sobre as propriedades do modelo, confira Microsoft.Solutions/applicationDefinitions.

O lockLevel no grupo de recursos gerenciados impede que o cliente execute operações indesejáveis nesse grupo de recursos. Atualmente, ReadOnly é o único nível de bloqueio com suporte. ReadOnly especifica que o cliente pode ler somente os recursos presentes no grupo de recursos gerenciados. As identidades do publicador que concedem acesso ao grupo de recursos gerenciado são isentas de bloqueio.

Criar o arquivo de parâmetros

O modelo de implantação da definição de aplicativo gerenciado precisa de entrada para vários parâmetros. O comando de implantação solicita os valores ou você pode criar um arquivo de parâmetros para os valores. Neste exemplo, usamos um arquivo de parâmetros para passar os valores de parâmetro para o comando de implantação.

No Visual Studio Code, crie um novo arquivo chamado deployDefinition.parameters.json e salve-o.

Adicione o seguinte ao arquivo de parâmetro e salve-o. Em seguida, substitua o <placeholder values>, incluindo os colchetes angulares (<>), por seus valores.

{
  "$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>"
    }
  }
}

A tabela a seguir descreve os valores de parâmetros para a definição do aplicativo gerenciado.

Parâmetro Valor
managedApplicationDefinitionName Nome da definição de aplicativo gerenciado. Para esse exemplo, use sampleBicepManagedApplication.
packageFileUri Insira o URI no arquivo de pacote .zip. Use o valor da variável packageuri. O formato é https://yourStorageAccountName.blob.core.windows.net/appcontainer/app.zip.
principalId A ID da entidade de segurança do editor que precisa de permissões para gerenciar recursos no grupo de recursos gerenciados. Use o valor da variável principalid.
roleId ID da função para permissões para o grupo de recursos gerenciados. Por exemplo, Proprietário, Colaborador, Leitor. Use o valor da variável roleid.

Para obter seus valores variáveis:

  • Azure PowerShell: No PowerShell, digite $variableName para exibir o valor de uma variável.
  • CLI do Azure: no Bash, digite echo $variableName para exibir o valor de uma variável.

Implantar a definição

Quando você implanta a definição de aplicativo gerenciado, ela fica disponível no catálogo de serviços. Esse processo não implanta os recursos do aplicativo gerenciado.

Crie um grupo de recursos chamado bicepDefinitionRG e implante a definição do aplicativo gerenciado.

New-AzResourceGroup -Name bicepDefinitionRG -Location westus3

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

Verifique os resultados

Execute o comando a seguir para verificar se a definição foi publicada no seu catálogo de serviços.

Get-AzManagedApplicationDefinition -ResourceGroupName bicepDefinitionRG

Get-AzManagedApplicationDefinition lista todas as definições disponíveis no grupo de recursos especificado, como sampleBicepManagedApplication.

Verifique se os usuários podem ver sua definição

Você tem acesso à definição de aplicativo gerenciado, mas você deve certificar-se de que outros usuários na sua organização podem acessá-lo. Conceda a eles pelo menos a função de Leitor para a definição. Eles podem ter herdado esse nível de acesso da assinatura ou grupo de recursos. Para verificar quem tem acesso à definição e adicionar usuários ou grupos, confira Atribuir funções do Azure usando o portal do Azure.

Limpar recursos

Se estiver planejando implantar a definição, prossiga para a seção Próximas etapas, que inclui um link para o artigo com instruções para implantar a definição com o Bicep.

Se tiver terminado a definição do aplicativo gerenciado, você pode excluir os grupos de recursos que criou com os nomes packageStorageRG e bicepDefinitionRG.

O comando solicita que você confirme se deseja remover o grupo de recursos.

Remove-AzResourceGroup -Name packageStorageRG

Remove-AzResourceGroup -Name bicepDefinitionRG

Próximas etapas

Você publicou a definição de aplicativo gerenciado. A próxima etapa é aprender a implantar uma instância dessa definição.