Azure の Data Factory / Synapse / Data Explorer といったリソースでは、マネージド仮想ネットワーク内にプライベートエンドポイントを作成することができる、「マネージドプライベートエンドポイント」というリソースを作成することができます。
通常のプライベートエンドポイントは、仮想ネットワーク内に展開を行います。
しかし、上述のリソースは仮想ネットワーク内に展開することができないのですが、このようなリソースで、使用できるプライベートエンドポイントを作成する方法として、マネージドプライベートエンドポイントという機能が提供されています。
マネージドプライベートエンドポイントを作成することで、セキュリティで保護されている特定のリソースへのアクセスポイントを、仮想ネットワーク内に展開することができないリソースでも作成することができます。
Synapse についてはドキュメントが見つからなかったのですが、ADF と ADX については、マネージドプライベートエンドポイントをBicep で作成することが可能となっています。
- Microsoft.DataFactory factories/managedVirtualNetworks/managedPrivateEndpoints
- Microsoft.Kusto clusters/managedPrivateEndpoints
マネージドプライベートエンドポイントを作成する場合は、上述のキュメントの内容で Bicep を作成すればよいのですが、作成したエンドポイントの承認まで Bicep で実施しようとすると少し手間がかかったので、本投稿で承認をした際の内容をまとめておこうと思います。
今回はストレージアカウントの BLOB に対してプライベートエンドポイントを作成することを想定しています。
作成したサンプルについては https://github.com/MasayukiOzawa/bicep-sample/tree/main/managed-private-endpoint に置いてあります。
Contents
通常のプライベートエンドポイントを Bicep で作成する場合
マネージドプライベートエンドポイントではなく、通常のプライベートエンドポイント (仮想ネットワーク内に NIC を作成してプライベートエンドポイントを作成) を使用する場合は次のような Bicep で承認まで実施することができます。
param location string param vnetId string param subnetId string param storageAccountId string param privateEndpointName string = 'pep-myPrivateEndpoint' resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-11-01' = { name: privateEndpointName location: location properties: { subnet: { id: subnetId } privateLinkServiceConnections: [ { name: 'linkConnection-${privateEndpointName}' properties: { privateLinkServiceId: storageAccountId groupIds: [ 'blob' ] } } ] customNetworkInterfaceName: 'nic-${privateEndpointName}' } } resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { name: 'privatelink.blob.${environment().suffixes.storage}' location: 'global' } resource virtualNetworkLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { name: 'link-${privateEndpointName}' parent: privateDnsZone location: 'global' properties: { registrationEnabled: true virtualNetwork: { id: vnetId } } } resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-11-01' = { name: 'zoneGroup-${privateEndpointName}' parent: privateEndpoint properties: { privateDnsZoneConfigs: [ { name: 'zoneConfig-${privateEndpointName}' properties: { privateDnsZoneId: privateDnsZone.id } } ] } }
通常のプライベートエンドポイントを作成する際には、次のようなリソースを作成することで対応することができます。
- privateEndpoint
- privateDnsZones
- virtualNetworkLinks
- privateDnsZoneGroups
プライベートエンドポイントは、Microsoft.Network privateEndpoints で作成することができますが、上記のような Bicep でプライベートエンドポイントを作成した場合、自動承認が行われ、明示的な承認をすることなく、プライベートエンドポイントが作成されていました。
マネージドプライベートエンドポイント を Bicep で作成する
今回は、Azure Data Factory でマネージドプライベートエンドポイントを作成してみます。
Azure Data Factory とマネージドプライベートエンドポイントの作成
マネージドプライベートエンドポイントを使用するためには、Data Factory を作成する際にマネージド仮想ネットワークを使用して展開する必要があります。
マネージド仮想ネットワークを使用して展開した Data Factory であればマネージドプライベートエンドポイントを作成することが可能です。
次のような Bicep を使用することで、Data Factory の展開と、指定したストレージアカウントに対してのマネージドプライベートエンドポイントの作成を行うことができます。
param location string param adfResourceName string = 'adf-${uniqueString(resourceGroup().id)}' param storageAccountId string resource dataFactory 'Microsoft.DataFactory/factories@2018-06-01' = { name: adfResourceName location: location properties: { publicNetworkAccess: 'Enabled' } identity: { type: 'SystemAssigned' } } resource managedVirtualNetwork 'Microsoft.DataFactory/factories/managedVirtualNetworks@2018-06-01' = { parent: dataFactory name: 'default' properties: { virtualNetworkType: 'Managed' } } resource autoResolveIntegrationRuntime 'Microsoft.DataFactory/factories/integrationRuntimes@2018-06-01' = { parent: dataFactory name: 'AutoResolveIntegrationRuntime' properties: { type: 'Managed' managedVirtualNetwork: { type: 'ManagedVirtualNetworkReference' referenceName: managedVirtualNetwork.name } typeProperties: { computeProperties: { location: 'AutoResolve' } } } } resource managedPrivateEndpoint 'Microsoft.DataFactory/factories/managedVirtualNetworks/managedPrivateEndpoints@2018-06-01' = { parent: managedVirtualNetwork name: 'AzureBlobStorageEndpoint' properties: { privateLinkResourceId: storageAccountId groupId: 'blob' } }
プライベートエンドポイントでは、作成した接続は自動承認が行われていたのですが、上記の Bicep で作成したマネージドプライベートエンドポイントに対しては、「保留中」の状態となり、明示的に承認を行う必要がありました。
マネージドプライベートエンドポイントの承認を Bicep で行う
マネージドプライベートエンドポイントの承認を Bicep で実施することは可能なのですが、少し手間がかかりました。
今回は次のようなモジュールの構成としています。
module dataFactory 'dataFactory.bicep' = { name: 'dataFactory' params: { location: location storageAccountId: storage.outputs.storageAccountId } } module approvePrivateEndpointPreTask 'approvePrivateEndpointPreTask.bicep' = { name : 'approvePrivateEndpointPreTask' dependsOn: [ dataFactory ] params : { storageAccountName: storage.outputs.storageAccountName } } module approvePrivateEndpoint 'approvePrivateEndpoint.bicep' = { name : 'approvePrivateEndpoint' params : { storageAccountName: storage.outputs.storageAccountName storagePrivateEndpointConnections: approvePrivateEndpointPreTask.outputs.storagePrivateEndpointConnections } }
最初に Data Factory を作成し、Data Factory の作成が完了したら「approvePrivateEndpointPreTask」を実行しています。このモジュールの内容は次のようになっています。
param storageAccountName string resource storage 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { name: storageAccountName } output storagePrivateEndpointConnections array = filter(storage.properties.privateEndpointConnections, (item, index) => item.properties.privateLinkServiceConnectionState.status == 'Pending')
プライベートエンドポイントを作成すると、該当のストレージアカウントのプロパティには、プライベートエンドポイントの接続情報が追加されます。
これは、Data Factory でプライベートエンドポイントを作成後に追加されるプロパティとなりますので、「dependsOn」で Data Factory の設定が一通り完了した後に情報の取得を行っています。
承認対象となるものは「Pending」状態の接続のみとなりますので、フィルターですでに承認済みの接続はスキップしています。 (承認済みの接続を再承認しようとするとエラーとなったはずです)
これで、プライベートエンドポイントの接続情報が追加された状態のストレージの情報を取得することができましたので、保留中の接続の承認を「approvePrivateEndpoint」で実施します。
param storageAccountName string param storagePrivateEndpointConnections array resource storage 'Microsoft.Storage/storageAccounts@2023-04-01' existing = { name: storageAccountName } resource privateEndpointConnection 'Microsoft.Storage/storageAccounts/privateEndpointConnections@2023-04-01' = [for (resource,index) in storagePrivateEndpointConnections : { name: resource.name parent: storage properties: { privateLinkServiceConnectionState: { status: 'Approved' } } }]
これで保留中の接続を承認することができ、マネージドプライベートエンドポイントが使用できる状態となりました。
まとめ
今回は、マネージドプライベートエンドポイントの作成時に自動承認が行われていなかったので手動で承認をしました。
マネージドプライベートエンドポイント以外にも、自動承認が行われないケースがあった場合は、次のようなフローを作成することで対応できるのではないでしょうか。
- プライベートエンドポイントを作成
- プライベートエンドポイントの作成後、リソースの最新の情報を取得し、プライベートエンドポイントの接続名を取得
- プライベートエンドポイントの作成後に、対象のリソースの最新の情報を取得するとプライベートエンドポイントの情報が追加されている
- 「existing」によるリソース情報の取得は「dependsOn」を指定できないため、モジュール呼び出し時に指定して、プライベートエンドポイント作成後に情報取得が行われるように依存関係を制御
- 取得した接続名を承認
- 承認対象は「Pending」になっている状態の接続を対象としておくことで、複数回実行してもエラーが発生すること無く実行できるように制御をすることができる