Udostępnij za pośrednictwem


Uruchamianie skryptu wdrożenia Bicep prywatnie za pośrednictwem prywatnego punktu końcowego

Przy użyciu wersji 2023-08-01interfejsu Microsoft.Resources/deploymentScripts API zasobów można uruchamiać skrypty wdrażania prywatnie w usłudze Azure Container Instance (ACI).

Konfigurowanie środowiska

W tej konfiguracji usługa ACI utworzona przez skrypt wdrożenia jest uruchamiana w sieci wirtualnej i uzyskuje prywatny adres IP. Następnie ustanawia połączenie z nowym lub wstępnie istniejącym kontem magazynu za pośrednictwem prywatnego punktu końcowego. Właściwość containerSettings/subnetIds określa wartość ACI, która musi zostać wdrożona w podsieci sieci wirtualnej.

Zrzut ekranu przedstawiający architekturę wysokiego poziomu przedstawiającą sposób, w jaki infrastruktura jest połączona z prywatnym uruchamianiem skryptów wdrażania.

Aby uruchomić skrypty wdrażania prywatnie, potrzebna jest następująca infrastruktura, jak pokazano na diagramie architektury:

  • Utwórz sieć wirtualną z dwiema podsieciami:
    • Podsieć dla prywatnego punktu końcowego.
    • Podsieć dla usługi ACI— ta podsieć wymaga delegowania Microsoft.ContainerInstance/containerGroups .
  • Utwórz konto magazynu bez dostępu do sieci publicznej.
  • Utwórz prywatny punkt końcowy w sieci wirtualnej skonfigurowanej file przy użyciu zasobu podrzędnego na koncie magazynu.
  • Utwórz prywatną strefę privatelink.file.core.windows.net DNS i zarejestruj prywatny adres IP punktu końcowego jako rekord A. Połącz prywatną strefę DNS z utworzoną siecią wirtualną.
  • Utwórz tożsamość zarządzaną przypisaną przez użytkownika z uprawnieniami Storage File Data Privileged Contributor na koncie magazynu i określ ją we właściwości w identity zasobie skryptu wdrożenia. Aby przypisać tożsamość, zobacz Tożsamość.
  • Zasób ACI jest tworzony automatycznie przez zasób skryptu wdrażania.

Poniższy plik Bicep konfiguruje infrastrukturę wymaganą do prywatnego uruchamiania skryptu wdrażania:

@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!"'
  }
}

Usługa ACI pobiera obrazy kontenerów z usługi Microsoft Container Registry. Jeśli używasz zapory, dodaj adres URL dozwolony mcr.microsoft.com do pobrania obrazu. Nie można pobrać obrazu kontenera powoduje wprowadzenie waiting stanu przez interfejs ACI, co ostatecznie prowadzi do błędu przekroczenia limitu czasu.

Następne kroki

W tym artykule przedstawiono sposób uruchamiania skryptów wdrażania za pośrednictwem prywatnego punktu końcowego. Dodatkowe informacje: