Como traduzir sua infraestrutura para um modelo de IaC

O Conector de Usuários ajuda os usuários a conectarem seus serviços de computação para direcionar serviços de backup em apenas alguns cliques ou comandos. Ao passar de um estágio inicial para um estágio de produção, os usuários também precisam fazer a transição do uso de configurações manuais para o uso de modelos de Infraestrutura como Código (IaC) nos seus pipelines de CI/CD. Nesta guia, mostramos como traduzir seus serviços do Azure conectados nos modelos de IaC.

Pré-requisitos

Visão geral da solução

Geralmente, a tradução da infraestrutura para os modelos de IaC envolve duas partes principais: a lógica para fornecer serviços de origem e destino, e a lógica para criar conexões. Para implementar a lógica de provisionamento dos serviços de origem e destino, há duas opções:

  • Criar um modelo do zero
  • Exportar o modelo do Azure e poli-lo

Para implementar a lógica para criar conexões, há três opções:

  • Usar o Conector de Serviço e a configuração do repositório na Configuração do Aplicativo
  • Usar o Conector de Serviço no modelo
  • Usar a lógica de modelo para configurar os serviços de origem e de destino diretamente

As combinações dessas diferentes opções podem produzir soluções diferentes. Por causa das Limitações de IaC no Conector de Serviço, recomendamos que você implemente as seguintes soluções na ordem apresentada abaixo. Para aplicar essas soluções, você deve entender as ferramentas de IaC e a gramática de criação de modelos.

Solução Provisionar a origem e o destino Conexão da compilação Cenário aplicável Vantagens Desvantagens
1 Criar do zero Usar o Conector de Serviço e a configuração do repositório na Configuração do Aplicativo Verifica a vivacidade dos recursos da nuvem antes de permitir o tráfego ativo – O modelo é simples e legível
– O Conector de Serviço traz valor adicional
- Os problemas de IaC não são introduzidos pelo Conector de Serviço
– Precisa de dependência extra para ler a configuração da Configuração do Aplicativo
– Custo para verificar a dinâmica dos recursos de nuvem
2 Criar do zero Usar o Conector de Serviço Verifica a vivacidade dos recursos da nuvem antes de permitir o tráfego ativo – O modelo é simples e legível
– O Conector de Serviço traz valor adicional
– Custo para verificar a dinâmica dos recursos de nuvem
3 Criar do zero Configurar os serviços de origem e de destino diretamente no modelo Não há verificação de vida útil nos recursos de nuvem – O modelo é simples e legível Alguns recursos do SQL Server não estão disponíveis.
4 Exportar e polir Usar o Conector de Serviço e a configuração do repositório na Configuração do Aplicativo Verifica a vivacidade dos recursos da nuvem antes de permitir o tráfego ativo - Os recursos são exatamente iguais aos da nuvem
– O Conector de Serviço traz valor adicional
- Os problemas de IaC não são introduzidos pelo Conector de Serviço
– Precisa de dependência extra para ler a configuração da Configuração do Aplicativo
– Custo para verificar a dinâmica dos recursos de nuvem
- Dá suporte apenas aos modelos do ARM
- Esforços necessários para entender e polir o modelo
5 Exportar e polir Usar o Conector de Serviço Verifica a vivacidade dos recursos da nuvem antes de permitir o tráfego ativo - Os recursos são exatamente iguais aos da nuvem
– O Conector de Serviço traz valor adicional
– Custo para verificar a dinâmica dos recursos de nuvem
- Dá suporte apenas aos modelos do ARM
- Esforços necessários para entender e polir o modelo
6 Exportar e polir Configurar os serviços de origem e de destino diretamente no modelo Não há verificação de vida útil nos recursos de nuvem - Os recursos são exatamente iguais aos da nuvem – Dar suporte apenas ao modelo do ARM
- Esforços necessários para entender e polir o modelo
Alguns recursos do SQL Server não estão disponíveis.

Criação de modelos

As seções a seguir mostram como criar um aplicativo Web e uma conta de armazenamento e conectá-los a uma identidade atribuída pelo sistema usando o Bicep. Ele mostra como fazer isso usando o Conector de Serviço e usando a lógica do modelo.

Provisionar os serviços de origem e destino

Criar do zero

Criar o modelo do zero é a maneira preferida e recomendada de provisionar os serviços de origem e destino, pois é fácil de começar e torna o modelo simples e legível. Veja a seguir um exemplo, usando um conjunto mínimo de parâmetros para criar um aplicativo da Web e uma conta de armazenamento.

// This template creates a webapp and a storage account.
// In order to make it more readable, we use only the mininal set of parameters to create the resources.

param location string = resourceGroup().location
// App Service plan parameters
param planName string = 'plan_${uniqueString(resourceGroup().id)}'
param kind string = 'linux'
param reserved bool = true
param sku string = 'B1'
// Webapp parameters
param webAppName string = 'webapp-${uniqueString(resourceGroup().id)}'
param linuxFxVersion string = 'PYTHON|3.8'
param identityType string = 'SystemAssigned'
param appSettings array = []
// Storage account parameters
param storageAccountName string = 'account${uniqueString(resourceGroup().id)}'


// Create an app service plan 
resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = {
  name: planName
  location: location
  kind: kind
  sku: {
    name: sku
  }
  properties: {
    reserved: reserved
  }
}


// Create a web app
resource appService 'Microsoft.Web/sites@2022-09-01' = {
  name: webAppName
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      linuxFxVersion: linuxFxVersion
      appSettings: appSettings
    }
  }
  identity: {
    type: identityType
  }
}


// Create a storage account
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

Exportar e polir

Se os recursos que você está provisionando forem exatamente os mesmos que você tem na nuvem, exportar o modelo do Azure pode ser outra opção. As duas premissas dessa abordagem são: os recursos existem no Azure e você está usando os modelos do ARM para sua IaC. Geralmente, o botão Export template está na parte inferior da barra lateral no portal do Azure. O modelo do ARM exportado reflete os estados atuais do recurso, incluindo as configurações configuradas pelo Conector de Serviço. Geralmente, você precisa saber sobre as propriedades do recurso para polir o modelo exportado.

Captura de tela do portal do Azure, exportando o modelo de braço de um aplicativo Web.

Criar a lógica de conexão

Usar o Conector de Serviço e a configuração do repositório na Configuração do Aplicativo

Usar a Configuração do Aplicativo para armazenar a configuração naturalmente dá suporte aos cenários de IaC. Portanto, recomendamos que você use esse método para criar seu modelo de IaC, se possível.

Para obter instruções simples do portal, você pode consultar este tutorial de Configuração do Aplicativo. Para adicionar esse recurso a um arquivo bicep, adicione a ID da Configuração do Aplicativo no conteúdo do Conector de Serviço.

resource webApp 'Microsoft.Web/sites@2022-09-01' existing = {
  name: webAppName
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
  name: storageAccountName
}

resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = {
  name: appConfigurationName
}

resource serviceConnector 'Microsoft.ServiceLinker/linkers@2022-05-01' = {
  name: connectorName
  scope: webApp
  properties: {
    clientType: 'python'
    targetService: {
      type: 'AzureResource'
      id: storageAccount.id
    }
    authInfo: {
      authType: 'systemAssignedIdentity'
    }
    configurationInfo: {
      configurationStore: {
        appConfigurationId: appConfiguration.id
      }
    }
  }
}

Usar o Conector de Serviço

Criar conexões entre o serviço de origem e o de destino usando o Conector de ServiçoLimitação de IaC não for importante para o seu cenário. O Conector de Serviço simplifica o modelo e também fornece elementos adicionais, como a validação da integridade da conexão, que você não terá se estiver criando conexões diretamente pela lógica de modelo.

// The template builds a connection between a webapp and a storage account 
// with a system-assigned identity using Service Connector

param webAppName string = 'webapp-${uniqueString(resourceGroup().id)}'
param storageAccountName string = 'account${uniqueString(resourceGroup().id)}'
param connectorName string = 'connector_${uniqueString(resourceGroup().id)}'

// Get an existing webapp
resource webApp 'Microsoft.Web/sites@2022-09-01' existing = {
  name: webAppName
}

// Get an existig storage
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
  name: storageAccountName
}

// Create a Service Connector resource for the webapp 
// to connect to a storage account using system identity
resource serviceConnector 'Microsoft.ServiceLinker/linkers@2022-05-01' = {
  name: connectorName
  scope: webApp
  properties: {
    clientType: 'python'
    targetService: {
      type: 'AzureResource'
      id: storageAccount.id
    }
    authInfo: {
      authType: 'systemAssignedIdentity'
    }
  }
}

Para obter os formatos de propriedades e valores necessários ao criar um recurso do Conector de Serviço, verifique como fornecer parâmetros corretos. Você também pode visualizar e baixar um modelo do ARM para referência ao criar um recurso do Conector de Serviço no portal do Azure.

Captura de tela do portal do Azure, exportando o modelo de braço de um recurso do conector de serviço.

Usando a lógica de modelo

Quanto aos cenários em que o Conector de Serviço Limitação de IaC é importante, considere criar conexões usando diretamente a lógica de modelo. O modelo a seguir é um exemplo mostrando como conectar uma conta de armazenamento a um aplicativo Web usando uma identidade atribuída pelo sistema.

// The template builds a connection between a webapp and a storage account 
// with a system-assigned identity without using Service Connector

param webAppName string = 'webapp-${uniqueString(resourceGroup().id)}'
param storageAccountName string = 'account${uniqueString(resourceGroup().id)}'
param storageBlobDataContributorRole string  = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'

// Get an existing webapp
resource webApp 'Microsoft.Web/sites@2022-09-01' existing = {
  name: webAppName
}

// Get an existing storage account
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
  name: storageAccountName
}

// Operation: Enable system-assigned identity on the source service
// No action needed as this is enabled when creating the webapp

// Operation: Configure the target service's endpoint on the source service's app settings
resource appSettings 'Microsoft.Web/sites/config@2022-09-01' = {
  name: 'appsettings'
  parent: webApp
  properties: {
    AZURE_STORAGEBLOB_RESOURCEENDPOINT: storageAccount.properties.primaryEndpoints.blob
  }
}

// Operation: Configure firewall on the target service to allow the source service's outbound IPs
// No action needed as storage account allows all IPs by default

// Operation: Create role assignment for the source service's identity on the target service
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  scope: storageAccount
  name: guid(resourceGroup().id, storageBlobDataContributorRole)
  properties: {
    roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataContributorRole)
    principalId: webApp.identity.principalId
  }
}

Ao criar conexões usando diretamente a lógica de modelo, é fundamental entender o que o Conector de Serviço faz para cada tipo de autenticação, pois a lógica de modelo é equivalente às operações de back-end do Conector de Serviço. A tabela a seguir mostra os detalhes da operação que você precisa traduzir para a lógica de modelo de cada tipo de autenticação.

Tipo de autenticação Operações do Conector de Serviço
Segredo/cadeia de conexão - Definir a cadeia de conexão do serviço de destino nas configurações do aplicativo do serviço de origem
– Configurar o firewall no serviço de destino para permitir os IPs de saída do serviço de origem
Identidade gerenciada atribuída pelo sistema - Definir o ponto de extremidade do serviço de destino nas configurações do aplicativo do serviço de origem
– Configurar o firewall no serviço de destino para permitir os IPs de saída do serviço de origem
- Habilitar a identidade atribuída pelo sistema no serviço de origem
- Criar a atribuição de função para a identidade do serviço de origem no serviço de destino
Identidade gerenciada atribuída pelo usuário - Definir o ponto de extremidade do serviço de destino nas configurações do aplicativo do serviço de origem
– Configurar o firewall no serviço de destino para permitir os IPs de saída do serviço de origem
- Vincular a identidade atribuída pelo usuário ao serviço de origem
- Criar a atribuição de função para a identidade atribuída ao usuário no serviço de destino
Entidade de serviço - Definir o ponto de extremidade do serviço de destino nas configurações do aplicativo do serviço de origem
- Configurar o appId e o segredo da entidade de serviço nas configurações do aplicativo do serviço de origem
– Configurar o firewall no serviço de destino para permitir os IPs de saída do serviço de origem
- Criar a atribuição de função para a entidade de serviço no serviço de destino