Partager via


Exécuter un script de déploiement Bicep en privé sur un point de terminaison privé

Avec l’API de ressource Microsoft.Resources/deploymentScripts version 2023-08-01, vous pouvez exécuter des scripts de déploiement en privé dans une instance ACI (Azure Container Instance).

Configurer l’environnement

Dans cette configuration, l’instance ACI créée par le script de déploiement s’exécute dans un réseau virtuel et obtient une adresse IP privée. Elle établit ensuite une connexion à un compte de stockage nouveau ou préexistant via un point de terminaison privé. La propriété containerSettings/subnetIds spécifie l’instance ACI qui doit être déployée dans un sous-réseau du réseau virtuel.

Capture d’écran de l’architecture générale montrant comment l’infrastructure est connectée pour exécuter des scripts de déploiement en privé.

Pour exécuter des scripts de déploiement en privé, vous avez besoin de l’infrastructure suivante, comme indiqué dans le diagramme d’architecture :

  • Créer un réseau virtuel avec deux sous-réseaux :
    • Un sous-réseau pour le point de terminaison privé.
    • Un sous-réseau pour l’instance ACI. Ce sous-réseau a besoin d’une délégation Microsoft.ContainerInstance/containerGroups.
  • Créez un compte de stockage sans accès réseau public.
  • Créez un point de terminaison privé au sein du réseau virtuel configuré avec la sous-ressource file sur le compte de stockage.
  • Créez une zone DNS privée privatelink.file.core.windows.net et inscrivez l’adresse IP du point de terminaison privé en tant qu’enregistrement A. Liez la zone DNS privée au réseau virtuel créé.
  • Créez une identité managée affectée par l’utilisateur avec des autorisations Storage File Data Privileged Contributor sur le compte de stockage, et spécifiez-la dans la propriété identity dans la ressource de script de déploiement. Pour affecter l’identité, consultez Identité.
  • La ressource ACI est créée automatiquement par la ressource de script de déploiement.

Le fichier Bicep suivant configure l’infrastructure requise pour exécuter un script de déploiement en privé :

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

L’instance ACI télécharge des images conteneur à partir de Microsoft Container Registry. Si vous utilisez un pare-feu, placez l’URL mcr.microsoft.com en liste verte pour télécharger l’image. Si le téléchargement de l’image conteneur échoue, l’instance ACI bascule à l’état waiting, ce qui aboutit à une erreur de délai d’expiration.

Étapes suivantes

Dans cet article, vous avez appris à exécuter des scripts de déploiement sur un point de terminaison privé. Pour en savoir plus :