Executar o script de implantação do Bicep de forma privada em um ponto de extremidade privado
Com a versão 2023-08-01
da API de recursos Microsoft.Resources/deploymentScripts
, você pode executar scripts de implantação de forma privada em uma Instância de Contêiner do Azure (ACI).
Configure o ambiente
Nessa configuração, a ACI criada pelo script de implantação é executada em uma rede virtual e obtém um endereço IP privado. Em seguida, ele estabelece uma conexão com uma conta de armazenamento nova ou pré-existente por meio de um ponto de extremidade privado. A propriedade containerSettings/subnetIds
especifica a ACI que deve ser implantada em uma sub-rede da rede virtual.
Para executar scripts de implantação de forma privada, você precisa da seguinte infraestrutura, conforme visto no diagrama de arquitetura:
- Crie uma rede virtual com duas sub-redes:
- Uma sub-rede para o ponto de extremidade privado.
- Uma sub-rede para a ACI, essa sub-rede precisa de uma delegação
Microsoft.ContainerInstance/containerGroups
.
- Crie uma conta de armazenamento sem acesso à rede pública.
- Crie um ponto de extremidade privado na rede virtual configurada com o sub-recurso
file
na conta de armazenamento. - Crie uma zona DNS privada
privatelink.file.core.windows.net
e registre o endereço IP do ponto de extremidade privado como um registro A. Vincule a zona DNS privada à rede virtual criada. - Crie uma identidade gerenciada atribuída pelo usuário com permissões
Storage File Data Privileged Contributor
na conta de armazenamento e especifique-a na propriedadeidentity
no recurso de script de implantação. Para atribuir a identidade, consulte Identidade. - O recurso da ACI é criado automaticamente pelo recurso de script de implantação.
O arquivo Bicep a seguir configura a infraestrutura necessária para executar um script de implantação de forma privada:
@maxLength(10) // Required maximum length, because the storage account has a maximum of 26 characters
param namePrefix string
param location string = resourceGroup().location
param userAssignedIdentityName string = '${namePrefix}Identity'
param storageAccountName string = '${namePrefix}stg${uniqueString(resourceGroup().id)}'
param vnetName string = '${namePrefix}Vnet'
param deploymentScriptName string = '${namePrefix}ds'
var roleNameStorageFileDataPrivilegedContributor = '69566ab7-960f-475b-8e7c-b3118f30c6bd'
var vnetAddressPrefix = '192.168.4.0/23'
var subnetEndpointAddressPrefix = '192.168.4.0/24'
var subnetACIAddressPrefix = '192.168.5.0/24'
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: userAssignedIdentityName
location: location
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-04-01' = {
name: storageAccountName
kind: 'StorageV2'
location: location
sku: {
name: 'Standard_LRS'
}
properties: {
publicNetworkAccess: 'Disabled'
networkAcls: {
defaultAction: 'Deny'
bypass: 'AzureServices'
}
}
}
resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = {
name: storageAccount.name
location: location
properties: {
privateLinkServiceConnections: [
{
name: storageAccount.name
properties: {
privateLinkServiceId: storageAccount.id
groupIds: [
'file'
]
}
}
]
customNetworkInterfaceName: '${storageAccount.name}-nic'
subnet: {
id: virtualNetwork::privateEndpointSubnet.id
}
}
}
resource storageFileDataPrivilegedContributorReference 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: roleNameStorageFileDataPrivilegedContributor
scope: tenant()
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storageFileDataPrivilegedContributorReference.id, managedIdentity.id, storageAccount.id)
scope: storageAccount
properties: {
principalId: managedIdentity.properties.principalId
roleDefinitionId: storageFileDataPrivilegedContributorReference.id
principalType: 'ServicePrincipal'
}
}
resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
name: 'privatelink.file.core.windows.net'
location: 'global'
resource virtualNetworkLink 'virtualNetworkLinks' = {
name: uniqueString(virtualNetwork.name)
location: 'global'
properties: {
registrationEnabled: false
virtualNetwork: {
id: virtualNetwork.id
}
}
}
resource resRecord 'A' = {
name: storageAccount.name
properties: {
ttl: 10
aRecords: [
{
ipv4Address: first(first(privateEndpoint.properties.customDnsConfigs)!.ipAddresses)
}
]
}
}
}
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-11-01' = {
name: vnetName
location: location
properties:{
addressSpace: {
addressPrefixes: [
vnetAddressPrefix
]
}
}
resource privateEndpointSubnet 'subnets' = {
name: 'PrivateEndpointSubnet'
properties: {
addressPrefixes: [
subnetEndpointAddressPrefix
]
}
}
resource containerInstanceSubnet 'subnets' = {
name: 'ContainerInstanceSubnet'
properties: {
addressPrefix: subnetACIAddressPrefix
delegations: [
{
name: 'containerDelegation'
properties: {
serviceName: 'Microsoft.ContainerInstance/containerGroups'
}
}
]
}
}
}
resource privateDeploymentScript 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
name: deploymentScriptName
dependsOn: [
privateEndpoint
privateDnsZone::virtualNetworkLink
]
location: location
kind: 'AzurePowerShell'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}' : {}
}
}
properties: {
storageAccountSettings: {
storageAccountName: storageAccount.name
}
containerSettings: {
subnetIds: [
{
id: virtualNetwork::containerInstanceSubnet.id
}
]
}
azPowerShellVersion: '9.0'
retentionInterval: 'P1D'
scriptContent: 'Write-Host "Hello World!"'
}
}
A ACI baixa imagens de contêiner do Registro de Contêiner da Microsoft. Se você usa um firewall, inclua na lista de permitidos a URL mcr.microsoft.com para baixar a imagem. A falha ao baixar a imagem de contêiner resulta na entrada da ACI em um estado waiting
, levando a um erro de tempo limite.
Próximas etapas
Neste artigo, você aprendeu a executar scripts de implantação em um ponto de extremidade privado. Para saber mais: