Privátní spuštění skriptu nasazení Bicep přes privátní koncový bod

Microsoft.Resources/deploymentScripts Pomocí verze 2023-08-01rozhraní API prostředků můžete v rámci služby Azure Container Instance (ACI) spouštět skripty nasazení soukromě.

Konfigurace prostředí

V tomto nastavení se ACI vytvořené skriptem nasazení spustí ve virtuální síti a získá privátní IP adresu. Potom vytvoří připojení k novému nebo již existujícímu účtu úložiště prostřednictvím privátního koncového bodu. Vlastnost containerSettings/subnetIds určuje ACI, která musí být nasazena v podsíti virtuální sítě.

Snímek obrazovky architektury vysoké úrovně znázorňující, jak je infrastruktura připojená ke spouštění skriptů nasazení soukromě

Pokud chcete skripty nasazení spouštět soukromě, potřebujete následující infrastrukturu, jak je vidět v diagramu architektury:

  • Vytvořte virtuální síť se dvěma podsítěmi:
    • Podsíť pro privátní koncový bod.
    • Podsíť pro ACI potřebuje Microsoft.ContainerInstance/containerGroups delegování.
  • Vytvořte účet úložiště bez přístupu k veřejné síti.
  • Vytvořte privátní koncový bod ve virtuální síti nakonfigurovaný s dílčím prostředkem file v účtu úložiště.
  • Vytvořte privátní zónu privatelink.file.core.windows.net DNS a zaregistrujte IP adresu privátního koncového bodu jako záznam A. Propojte privátní zónu DNS s vytvořenou virtuální sítí.
  • Vytvořte spravovanou identitu přiřazenou uživatelem s oprávněními Storage File Data Privileged Contributor k účtu úložiště a zadejte ji ve identity vlastnosti v prostředku skriptu nasazení. Pokud chcete identitu přiřadit, přečtěte si téma Identita.
  • Prostředek ACI se vytvoří automaticky prostředkem skriptu nasazení.

Následující soubor Bicep konfiguruje infrastrukturu potřebnou pro privátní spuštění skriptu nasazení:

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

ACI stáhne image kontejneru ze služby Microsoft Container Registry. Pokud používáte bránu firewall, seznam povolených adres URL mcr.microsoft.com ke stažení obrázku. Stažení image kontejneru způsobí, že ACI zadává waiting stav, což nakonec vede k chybě časového limitu.

Další kroky

V tomto článku jste se dozvěděli, jak spouštět skripty nasazení přes privátní koncový bod. Další informace najdete v tématech: