「Service Endpointという言葉は知っているが、Private Endpointとの具体的な違いや実際のazコマンドの書き方が分からない」
「NSGとService Endpointを同じサブネットに設定したら通信が通らなくなった」「Private Endpointを設定したのに、digがまだグローバルIPを返す」——こうした疑問は、Azure入門者から実務担当者まで幅広く聞かれます。
この記事では、AzureのVNetサービスエンドポイント(VNet Service Endpoint)の仕組みから、StorageアカウントをVNetサブネットのIPアドレスに限定するazコマンドの実践手順まで一気通貫で解説します。Private Endpointの実践構築手順(Private DNS Zone作成・VNetリンク・DNS Zone Group作成・Linux VMからdigで疎通確認の4段階)、Azure SQL DatabaseへのPrivate Endpoint適用、対応サービス一覧、NSGとの組み合わせ時の注意点も押さえ、目的に応じたネットワーク設計の判断ができるようになることを目指します。
実行環境はRHEL 9.4 / Ubuntu 24.04 LTSで動作確認済みです。
この記事のポイント
・--service-endpointsオプションでサブネット単位にService Endpointを有効化できる
・Private EndpointはVNetのサブネットに仮想NICを払い出し、サービスをプライベートIPで使う仕組み
・Private EndpointはStorageのPublic AccessをDisabledに設定しながらVNet内からのアクセスを維持できる
・Private EndpointはDNS Zone作成→VNetリンク→DNS Zone Group作成→疎通確認の4段階で構築する
・NSGとの組み合わせ時はサービスタグ(Microsoft.Storage)を使ったアウトバウンドルールが必要
・digでグローバルIPが返る場合はVNetリンク・DNSゾーングループの設定漏れとVMのDNSリゾルバ設定(168.63.129.16)を先に確認する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
AzureのVNetサービスエンドポイントとは何か
VNetサービスエンドポイント(VNet Service Endpoint)は、AzureのVNet(仮想ネットワーク)からAzureマネージドサービスへのトラフィックを、パブリックインターネットを経由せずにMicrosoftのバックボーンネットワーク上で転送する仕組みです。Service Endpointを設定していない状態では、Azure VMからStorageアカウントに接続するトラフィックはVMのパブリックIPアドレスを経由してインターネット上のStorageエンドポイントへ到達します。Service Endpointを有効にすると、このルーティングがMicrosoftの内部ネットワーク(バックボーン)に切り替わり、トラフィックがインターネットを経由しなくなります。同時に、サブネットのプライベートIPアドレスがStorageアカウント側のネットワークルールに記録され、「このサブネットからのアクセスのみ許可する」という制御が可能になります。
ただし、Service Endpointには構造上の限界があります。StorageアカウントのFQDN(例:mystorageXXXX.blob.core.windows.net)はパブリックIPに解決され続け、VNet外のネットワークからもその名前解決が可能な状態が残ります。「ファイアウォールルールで拒否するから安全」という前提に依存した設計になる点が、金融・医療系など厳格なコンプライアンス要件を持つ環境では課題になります。また、StorageのPublic AccessをDisabledに設定することはService Endpointでは実現できません。完全なPublic Access遮断が必要な場合はPrivate Endpointを選択する必要があります。
サブネット分割がService Endpointと相性が良い理由は、NSG(ネットワークセキュリティグループ)の適用粒度にあります。1つのサブネットにWebサーバーもDBサーバーも入っていると、Service Endpointのアクセス制限がVNet内の全VMに一律に適用されます。用途ごとにサブネットを分けることで「フロントエンドサブネットはStorageへのService Endpoint許可」「バックエンドサブネットはSQL DBへのService Endpoint許可」という細かい制御が実現できます。
設定のポイントを整理すると次のとおりです。
・設定箇所は2つ:①サブネットでのService Endpoint有効化、②Azureサービス側のネットワークルール追加
・FQDNは変わらない:ストレージのエンドポイント名(xxx.blob.core.windows.net)はそのまま。ルーティングだけが変わる
・追加料金なし:Service Endpoint自体の利用料はかからない(Private Endpointはエンドポイント1本あたり時間課金+データ転送課金あり)
・サポートサービス:Storage・SQL Database・Key Vault・Cosmos DB・Service Bus・Event Hubなど主要サービスをカバー
・NSGとの共存:Service Endpointを有効にしたサブネットにNSGがある場合、NSGのアウトバウンドルールがService Endpointのトラフィックに適用される(後述)
Private Endpointとの違い・使い分け基準
Service EndpointとPrivate Endpointはどちらも「VNetからAzureサービスへのアクセスを安全にする」機能ですが、設計思想が大きく異なります。現場でよく混同されるので、明確に整理しておきましょう。| 項目 | Service Endpoint | Private Endpoint |
|---|---|---|
| サービスのIPアドレス | パブリックIPのまま(ルーティングのみ変わる) | VNet内にプライベートIPが払い出される |
| DNS名前解決 | パブリックIPに解決される | プライベートIPに解決される(Private DNS Zone設定後) |
| パブリックエンドポイントの状態 | 残る(ネットワークルールで制限) | パブリックエンドポイントを完全に無効化できる |
| Public Access設定 | 「選択したVNetとIPアドレス」への制限のみ(Disabledにはできない) | 「無効(Disabled)」に設定できる |
| 追加コスト | なし | エンドポイント1本あたり月額約500円程度+データ転送課金 |
| 設定の複雑さ | 低い(サブネット+サービス側の2ステップ) | 高い(Private DNS・NSG・承認フローが必要) |
| VNetピアリング越しのアクセス | 不可(同一VNetのサブネットのみ) | 可能(ピアリング先VNet・オンプレミスからも利用可) |
| NSGとの組み合わせ | サービスタグで制御可能(アウトバウンドルール要確認) | Private EndpointサブネットのNSGは別途設計が必要 |
| Azureドキュメントの推奨度 | 旧世代(非推奨方向) | 現行推奨(ゼロトラスト設計の標準) |
| 推奨ユースケース | 同一VNet内の単純なアクセス制限 | マルチVNet・オンプレ接続・ゼロトラスト設計 |
Private Endpointの仕組み補足:Private Endpointを作成すると、指定したサブネット内にネットワークインターフェース(Private NIC)が払い出され、サブネットアドレス範囲内のプライベートIPが割り当てられます。AWSでいうInterface型VPC EndpointのENI(Elastic Network Interface)と同じ構造です。Linux VMが
myaccount.blob.core.windows.net を名前解決すると、Azure DNSのデフォルト設定ではパブリックIPが返りますが、Private DNSゾーン(privatelink.blob.core.windows.net)をVNetにリンクすることでAレコードがプライベートIPを指すよう書き換えられます。この仕組みにより、StorageのFQDNをそのまま使いながらプライベート通信が実現し、StorageのパブリックエンドポイントをDisabledにした状態でもVNet内からのアクセスだけが継続できます。Service EndpointにはこのようなプライベートIP割り当てとDNS書き換えの仕組みはなく、パブリックIPへの経路をバックボーン上で最適化するにとどまる点が根本的な違いです。実務での判断を端的にまとめると次の3点です。
・同一VNet内のVMだけが使う:Service Endpointで十分な場合が多い
・オンプレミスやピアリング先からもアクセスする:Private Endpoint必須
・StorageのPublic AccessをDisabledにしてパブリックアクセスをIPアドレスレベルで完全に閉じたい:Private Endpoint必須
Private Endpointを構築する——DNS設定から疎通確認まで
Private Endpointを選択した場合の実践構築手順を解説します。前述のとおり、肝はDNSの設定です。Private DNS ZoneをVNetにリンクしないと、VMからStorage AccountのFQDNがグローバルIPに解決されたままになり、せっかくのPrivate Endpointが機能しません。1. 事前準備——VM用とPrivate Endpoint用でサブネットを分ける
VM用サブネットとPrivate Endpoint用サブネットを分けて構成します。Storageアカウント名はグローバル一意が要件(小文字英数字のみ・3~24文字)なので、末尾にランダム数字を付けるのが命名衝突を避ける鉄則です。date +%s | tail -c 6 でエポック秒の下6桁を利用する方法が手軽です。# 変数定義 RG="pe-demo-rg" LOCATION="japaneast" VNET_NAME="pe-demo-vnet" SUBNET_VM="vm-subnet" SUBNET_PE="pe-subnet" # Storageアカウント名:末尾にエポック秒の下6桁で一意性を確保 STORAGE_ACCOUNT="pedemostr$(date +%s | tail -c 6)" PE_NAME="pe-demo-blob" # リソースグループとVNet作成 $ az group create --name $RG --location $LOCATION $ az network vnet create \ --resource-group $RG \ --name $VNET_NAME \ --address-prefix 10.10.0.0/16 # VM用サブネット(10.10.1.0/24) $ az network vnet subnet create \ --resource-group $RG \ --vnet-name $VNET_NAME \ --name $SUBNET_VM \ --address-prefix 10.10.1.0/24 # Private Endpoint用サブネット(10.10.2.0/24) $ az network vnet subnet create \ --resource-group $RG \ --vnet-name $VNET_NAME \ --name $SUBNET_PE \ --address-prefix 10.10.2.0/24
privateEndpointNetworkPoliciesの既定値がEnabled)。古い手順書で--private-endpoint-network-policies Disabledを指定している例がありますが、新規作成環境ではEnabledのままで問題ありません。既存環境の確認方法は後述のNSGセクションで解説します。疎通テスト用のLinux VMをVM用サブネットに配置する場合は次のコマンドが利用できます。
# テスト用VMをVM用サブネットに作成(Ubuntu 22.04 LTS、Standard_B1s) $ az vm create \ --resource-group $RG \ --name vm-test \ --image Ubuntu2204 \ --vnet-name $VNET_NAME \ --subnet $SUBNET_VM \ --generate-ssh-keys \ --public-ip-sku Standard \ --size Standard_B1s
2. StorageアカウントをパブリックアクセスOFFで作成する
Private Endpointを使う前提なので、作成時に--public-network-access Disabled を指定します。あわせてBlob公開アクセスの無効化(--allow-blob-public-access false)とHTTPS強制(--https-only true)もセットで設定しておくと、意図しない公開を防げます。$ az storage account create \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --sku Standard_LRS \ --kind StorageV2 \ --allow-blob-public-access false \ --https-only true \ --public-network-access Disabled # パブリックアクセスの無効状態をJSON形式で確認 $ az storage account show \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --query "{name:name, publicNetworkAccess:publicNetworkAccess}" \ -o json { "name": "pedemostr12345678", "publicNetworkAccess": "Disabled" }
az storage blobコマンドも届かなくなります。Private Endpoint経由の疎通を確認するまで操作はVNet内のVMから行うか、作業中は一時的に--public-network-access Enabledのままにして最後に閉じる運用でも構いません。詳細は後述のトラブルシュートセクション8を参照してください。3. Private Endpointを作成する
Storage AccountのリソースIDを取得してから、az network private-endpoint create を実行します。--group-id blob を指定することでBlobサービスをターゲットにします。tableやqueueのエンドポイントが必要な場合は別途作成が必要です。# Storage AccountのリソースIDを取得 STORAGE_ID=$(az storage account show \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --query id -o tsv) # Private Endpointを作成 $ az network private-endpoint create \ --resource-group $RG \ --name $PE_NAME \ --vnet-name $VNET_NAME \ --subnet $SUBNET_PE \ --private-connection-resource-id $STORAGE_ID \ --group-id blob \ --connection-name "${PE_NAME}-connection" # エンドポイントに割り当てられたプライベートIPを確認 $ az network private-endpoint show \ --resource-group $RG \ --name $PE_NAME \ --query 'customDnsConfigs[].{fqdn:fqdn,ipAddresses:ipAddresses}' \ --output table FQDN IpAddresses -------------------------------------------------- --------------- pedemostr12345678.blob.core.windows.net ['10.10.2.4'] pedemostr12345678.privatelink.blob.core.windows.net ['10.10.2.4']
10.10.2.4 がPrivate Endpoint用サブネット(10.10.2.0/24)内のプライベートIPです。この段階ではまだDNSが上書きされていないため、VMから名前解決をしてもグローバルIPが返ります。4. Private DNS ZoneをVNetにリンクして名前解決を通す
Private Endpointの肝はDNSです。AzureがStorageのFQDN(xxx.blob.core.windows.net)をプライベートIPに解決するよう、Private DNS Zoneを設定します。Azureが推奨するゾーン名は privatelink.blob.core.windows.net です。Linux DNS設定の基本でも解説しているように、名前解決の仕組みを理解しておくとトラブルシュートがスムーズになります。# Private DNS Zoneを作成 $ az network private-dns zone create \ --resource-group $RG \ --name "privatelink.blob.core.windows.net" # DNS ZoneをVNetにリンク(registration-enabled falseでVM名の自動登録を無効化) $ az network private-dns link vnet create \ --resource-group $RG \ --zone-name "privatelink.blob.core.windows.net" \ --name "pe-demo-vnet-link" \ --virtual-network $VNET_NAME \ --registration-enabled false # DNSゾーングループを作成(AレコードをPrivate DNS Zoneに自動登録) DNS_ZONE_ID=$(az network private-dns zone show \ --resource-group $RG \ --name "privatelink.blob.core.windows.net" \ --query id -o tsv) $ az network private-endpoint dns-zone-group create \ --resource-group $RG \ --endpoint-name $PE_NAME \ --name "blob-dns-group" \ --private-dns-zone $DNS_ZONE_ID \ --zone-name "privatelink.blob.core.windows.net" # AレコードがDNS Zoneに登録されたか確認 $ az network private-dns record-set a list \ --resource-group $RG \ --zone-name "privatelink.blob.core.windows.net" \ --output table Name Ttl Type AutoRegistered Metadata -------------------- ----- ------ ---------------- ---------- pedemostr12345678 3600 A False
BlobとはサービスごとにDNSゾーン名が異なります。File・Queue・Tableのエンドポイントを別途作成する場合は、それぞれ専用のZoneが必要です。サービス種別・group-id・Private DNS Zone名の対応は次のとおりです。
| サービス(--group-id) | プライベートDNSゾーン名 |
|---|---|
| blob | privatelink.blob.core.windows.net |
| file | privatelink.file.core.windows.net |
| queue | privatelink.queue.core.windows.net |
| table | privatelink.table.core.windows.net |
| sqlServer(Azure SQL Database) | privatelink.database.windows.net |
| vault(Azure Key Vault) | privatelink.vaultcore.azure.net |
| registry(Azure Container Registry) | privatelink.azurecr.io |
| Sql(Azure Cosmos DB SQL API) | privatelink.documents.azure.com |
5. Linux VMからdigとcurlで疎通を確認する
vm-subnet(10.10.1.0/24)に配置したVMにSSH接続し、Storage AccountのFQDNを名前解決します。プライベートIPが返れば設定完了です。# digでDNS解決を確認(プライベートIPが返ればOK) $ dig pedemostr12345678.blob.core.windows.net ;; ANSWER SECTION: pedemostr12345678.blob.core.windows.net. 300 IN CNAME pedemostr12345678.privatelink.blob.core.windows.net. pedemostr12345678.privatelink.blob.core.windows.net. 3600 IN A 10.10.2.4 ;; SERVER: 168.63.129.16#53(168.63.129.16)
10.10.2.4(Private EndpointのプライベートIP)が返れば成功です。168.63.129.16 はAzure提供の内部DNSリゾルバーです。グローバルIPが返る場合は、Private DNS ZoneのVNetリンクが未設定か、DNSゾーングループの設定が漏れています。また、VMのDNSサーバー設定が外部リゾルバ(8.8.8.8等)を向いている場合もPrivate DNS Zoneを参照しないため、/etc/resolv.confのnameserverが168.63.129.16になっているかも確認してください。digコマンドが入っていない環境ではnslookupでも同様に確認できます。# nslookupでDNS解決を確認(dig代替) $ nslookup pedemostr12345678.blob.core.windows.net Server: 168.63.129.16 Address: 168.63.129.16#53 Non-authoritative answer: pedemostr12345678.blob.core.windows.net canonical name = pedemostr12345678.privatelink.blob.core.windows.net. Name: pedemostr12345678.privatelink.blob.core.windows.net Address: 10.10.2.4
# nc -zvでポート443へのTCP到達確認(プライベートIPへの直接指定) $ nc -zv 10.10.2.4 443 Ncat: Version 7.80 ( https://nmap.org/ncat ) Ncat: Connected to 10.10.2.4:443. Ncat: 0 bytes sent, 0 bytes received in 0.03 seconds. # curlで未認証アクセス(400が返れば到達できている) $ curl -I https://pedemostr12345678.blob.core.windows.net/ HTTP/1.1 400 Bad Request Content-Length: 0 Server: Microsoft-HTTPAPI/2.0 # ネットワーク的に到達できない場合はConnection refusedやcurl: (6) Could not resolve host
Connectedを返し、curlが400 Bad Requestを返せばネットワーク到達性は確認できています。400はStorageがリクエストをHTTPレベルで弾いているだけで、TCPとTLSのハンドシェイクは成立しています。Linuxポート確認コマンドでサブネット間の443番ポートの疎通を確認しておくと、NSGのルールミスを早期に発見できます。ネットワーク疎通だけでなく、実際にBlobアクセスが通ることも確認しておきましょう。VNet内VMで
az loginまたはManaged Identityが設定済みであれば、以下のコマンドでコンテナー一覧の取得とBlobのアップロードを実施できます。# VNet内VMからaz CLIでBlobコンテナーの一覧を取得(実データで疎通確認) $ az storage container list \ --account-name $STORAGE_ACCOUNT \ --auth-mode login \ --output table Name Lease State Last Modified ---------- ------------- -------------------- mycontainer available 2026-09-12T04:15:32+00:00 # VNet外から同じコマンドを実行するとAuthorizationFailureまたは接続エラーになる # コンテナー作成とBlobアップロードで書き込み疎通も確認する $ az storage container create \ --account-name $STORAGE_ACCOUNT \ --name test-container \ --auth-mode login $ echo "private endpoint test" > /tmp/pe-test.txt $ az storage blob upload \ --account-name $STORAGE_ACCOUNT \ --container-name test-container \ --name pe-test.txt \ --file /tmp/pe-test.txt \ --auth-mode login $ az storage blob list \ --account-name $STORAGE_ACCOUNT \ --container-name test-container \ --auth-mode login \ --output table Name Blob Type Blob Tier Length Content Type Last Modified ----------- ----------- ----------- -------- ------------------------ ------------------------- pe-test.txt BlockBlob Hot 22 application/octet-stream 2026-09-15T04:30:00+00:00
6. Azure SQL DatabaseのPrivate Endpointを追加する(応用)
Storage Accountで手順を把握したら、Azure SQL Databaseへの適用は構造が同じです。--group-idの値と使用するDNSゾーン名が変わるだけで、手順はまったく同じです。# Azure SQL ServerのリソースIDを取得(事前にSQL Serverが作成済みの前提) SQL_SERVER_ID=$(az sql server show \ --resource-group $RG \ --name my-sql-server \ --query id -o tsv) # Azure SQL用Private Endpointを作成(group-idはsqlServer) $ az network private-endpoint create \ --resource-group $RG \ --name pe-demo-sql \ --vnet-name $VNET_NAME \ --subnet $SUBNET_PE \ --private-connection-resource-id $SQL_SERVER_ID \ --group-id sqlServer \ --connection-name "pe-demo-sql-connection" # Private DNS Zone(SQL用はprivatelink.database.windows.net) $ az network private-dns zone create \ --resource-group $RG \ --name "privatelink.database.windows.net" $ az network private-dns link vnet create \ --resource-group $RG \ --zone-name "privatelink.database.windows.net" \ --name "pe-demo-sql-vnet-link" \ --virtual-network $VNET_NAME \ --registration-enabled false # DNSゾーングループを作成 SQL_DNS_ZONE_ID=$(az network private-dns zone show \ --resource-group $RG \ --name "privatelink.database.windows.net" \ --query id -o tsv) $ az network private-endpoint dns-zone-group create \ --resource-group $RG \ --endpoint-name pe-demo-sql \ --name "sql-dns-group" \ --private-dns-zone $SQL_DNS_ZONE_ID \ --zone-name "privatelink.database.windows.net" # VMからnslookupで疎通確認(プライベートIPが返ればOK) $ nslookup my-sql-server.database.windows.net Server: 168.63.129.16 Address: 168.63.129.16#53 Non-authoritative answer: my-sql-server.database.windows.net canonical name = my-sql-server.privatelink.database.windows.net. Name: my-sql-server.privatelink.database.windows.net Address: 10.10.2.5
--public-network-access Disabledを設定するにはaz sql server updateを使います。SQL Serverのパブリックアクセスを完全に閉じるとAzure Portal上のクエリエディタも届かなくなるため、VNet内のVMか、対応するPrivate Endpoint経由の接続ツールを用意してから設定することをお勧めします。サービスエンドポイントの設定手順
実際にStorageアカウントをVNetサブネットのIPアドレスに限定する設定を行います。事前にAzure CLIをインストールし(az loginでログイン済みであること)、サブスクリプションが選択されていることを確認してください。0. az CLIのバージョンとログイン状態を確認する
作業前にaz CLIのバージョンとログイン状態を確認します。az CLIは2.50以上を推奨します。# バージョン確認(2.50以上を推奨) $ az --version azure-cli 2.61.0 # ログイン状態確認(サブスクリプション名が表示されれば認証済み) $ az account show --output table Name CloudName SubscriptionId State IsDefault ---------------- ----------- ------------------------------------ ------- ----------- MySubscription AzureCloud xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Enabled True
az login を実行してブラウザ認証を行います。CI/CD環境ではサービスプリンシパル認証を使いますが、ここでは対話型ログインを前提とします。1. 事前準備と変数の定義
コマンドを再利用しやすくするため、変数を先に定義します。# 変数の定義(環境に合わせて変更してください) RG="rg-service-endpoint-demo" LOCATION="japaneast" VNET="vnet-demo" SUBNET="snet-app" STORAGE_ACCOUNT="stsvcepdemo0923" # 小文字・3~24文字・グローバル一意 ADDRESS_PREFIX="10.0.0.0/16" SUBNET_PREFIX="10.0.1.0/24"
2. リソースグループとVNetの作成
# リソースグループを作成 $ az group create \ --name $RG \ --location $LOCATION { "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-service-endpoint-demo", "location": "japaneast", "name": "rg-service-endpoint-demo", "properties": { "provisioningState": "Succeeded" } } # VNetを作成(アドレス空間だけ先に定義) $ az network vnet create \ --resource-group $RG \ --name $VNET \ --address-prefix $ADDRESS_PREFIX { "name": "vnet-demo", "addressSpace": { "addressPrefixes": ["10.0.0.0/16"] }, "provisioningState": "Succeeded" } # アプリケーション用サブネットを追加 $ az network vnet subnet create \ --resource-group $RG \ --vnet-name $VNET \ --name $SUBNET \ --address-prefix $SUBNET_PREFIX { "name": "snet-app", "addressPrefix": "10.0.1.0/24", "provisioningState": "Succeeded" }
3. サブネットにService Endpointを有効化する
Service Endpointはサブネット単位で有効化します。az network vnet subnet updateの--service-endpointsに対象サービス名を指定します。# snet-appにStorageのService Endpointを有効化 $ az network vnet subnet update \ --resource-group $RG \ --vnet-name $VNET \ --name $SUBNET \ --service-endpoints Microsoft.Storage # 有効化されたことを確認 $ az network vnet subnet show \ --resource-group $RG \ --vnet-name $VNET \ --name $SUBNET \ --query serviceEndpoints \ --output table Service ProvisioningState Locations ------------------- ------------------- ------------------ Microsoft.Storage Succeeded japaneast, japanwest
ProvisioningStateがSucceededになれば、サブネット側の設定は完了です。この時点ではサービス側(Storage)にはまだ何も設定していないため、接続制限は発生していません。4. StorageアカウントのNetworkルールを設定する
次に、StorageアカウントをVNetサブネットのIPアドレスからのアクセスに限定します。2ステップで行います。# Storageアカウントを作成(Standard LRS) $ az storage account create \ --name $STORAGE_ACCOUNT \ --resource-group $RG \ --location $LOCATION \ --sku Standard_LRS { "name": "stsvcepdemo0806", "provisioningState": "Succeeded", "statusOfPrimary": "available" } # ステップ1: サブネットからのアクセスを許可するルールを追加 $ az storage account network-rule add \ --resource-group $RG \ --account-name $STORAGE_ACCOUNT \ --vnet-name $VNET \ --subnet $SUBNET { "action": "Allow", "state": "Succeeded", "virtualNetworkResourceId": "/subscriptions/.../snet-app" } # ステップ2: デフォルトアクションをDeny(ルールに一致しない接続を拒否)に変更 $ az storage account update \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --default-action Deny
--default-action Denyを設定する前に、必ず自分のPC(az CLIを実行している環境)のIPアドレスを許可ルールに加えるか、Azure Portalでの操作を準備してください。この設定が完了した瞬間から、ルールに一致しないすべての接続が拒否されます。設定が正しく反映されたか確認します。
$ az storage account show \ --name $STORAGE_ACCOUNT \ --resource-group $RG \ --query networkRuleSet \ --output json { "bypass": "AzureServices", "defaultAction": "Deny", "ipRules": [], "virtualNetworkRules": [ { "action": "Allow", "state": "Succeeded", "virtualNetworkResourceId": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rg-service-endpoint-demo/providers/Microsoft.Network/virtualNetworks/vnet-demo/subnets/snet-app" } ] }
defaultActionがDeny、virtualNetworkRulesにsnet-appがAllow/Succeededで登録されていれば正常です。なお、"bypass": "AzureServices"はAzure Monitor・Azure Backup等のAzure内部サービスからのアクセスを許可する設定です。サービス側の診断ログ収集が止まらないよう、デフォルトのまま維持することを推奨します。5. Azure VM上から接続を確認する
実際にsnet-appに配置したAzure VM上から、Storageへのアクセスが通ることを確認します。# snet-app上のVM(10.0.1.x)からcurlでBlobエンドポイントに疎通確認 [azureuser@vm-app ~]$ curl -s -o /dev/null -w "%{http_code}" \ "https://stsvcepdemo0806.blob.core.windows.net/?restype=account&comp=properties" \ -H "x-ms-version: 2020-10-02" \ -H "x-ms-date: $(date -u +%a,\ %d\ %b\ %Y\ %H:%M:%S\ GMT)" 400 # 400=認証エラーは「到達できた」こと。ネットワーク的にはOK # 別のVMまたは自分のPCから(ルールに含まれないIPアドレス) $ curl -s -o /dev/null -w "%{http_code}" \ "https://stsvcepdemo0806.blob.core.windows.net/?restype=account&comp=properties" \ -H "x-ms-version: 2020-10-02" 403 # 403=アクセス拒否。ネットワークルールがDenyとして機能している
Azure対応セミナーの詳細を見る >>
対応するAzureサービスと複数エンドポイントの設定
Service Endpointが対応しているサービスの一覧と、複数サービスを同一サブネットで有効化する方法を説明します。| サービス識別子 | 対象Azureサービス |
|---|---|
Microsoft.Storage |
Blob Storage・File Storage・Queue・Table |
Microsoft.Sql |
Azure SQL Database・Azure Synapse Analytics |
Microsoft.KeyVault |
Azure Key Vault |
Microsoft.AzureCosmosDB |
Azure Cosmos DB |
Microsoft.ServiceBus |
Azure Service Bus |
Microsoft.EventHub |
Azure Event Hubs |
Microsoft.ContainerRegistry |
Azure Container Registry |
Microsoft.Web |
Azure App Service(VNet Integration用途) |
# StorageとKey Vaultを同時に有効化 $ az network vnet subnet update \ --resource-group $RG \ --vnet-name $VNET \ --name $SUBNET \ --service-endpoints Microsoft.Storage Microsoft.KeyVault # 確認 $ az network vnet subnet show \ --resource-group $RG \ --vnet-name $VNET \ --name $SUBNET \ --query serviceEndpoints[].service \ --output tsv Microsoft.KeyVault Microsoft.Storage
# Key Vaultのネットワークルールにサブネットを追加 $ KEYVAULT_NAME="kv-sepdemo0806" $ az keyvault network-rule add \ --name $KEYVAULT_NAME \ --resource-group $RG \ --vnet-name $VNET \ --subnet $SUBNET # デフォルトアクションをDenyに設定 $ az keyvault update \ --name $KEYVAULT_NAME \ --resource-group $RG \ --default-action Deny
Service EndpointとNSGを組み合わせる際の注意点
Service Endpointを有効化したサブネットにNSG(ネットワークセキュリティグループ)を設定している場合、NSGのアウトバウンドルールがService Endpointのトラフィックに適用されます。これはよく見落とされる落とし穴です。NSGのデフォルトアウトバウンドルールには
AllowInternetOutBound(優先度65001)とAllowVnetOutBound(優先度65000)が含まれており、通常はService Endpointのトラフィックも通過します。しかし、セキュリティを強化するために全アウトバウンドをDenyするルールを追加した場合、Service Endpointのトラフィックも遮断されます。この場合は、Azureサービスタグ(Service Tag)を使ったアウトバウンドルールを明示的に追加します。
# NSGを作成してサブネットに紐付ける(既存NSGがある場合はスキップ) $ az network nsg create \ --resource-group $RG \ --name nsg-app $ az network vnet subnet update \ --resource-group $RG \ --vnet-name $VNET \ --name $SUBNET \ --network-security-group nsg-app # StorageへのService Endpointトラフィックを許可するアウトバウンドルール(優先度100) $ az network nsg rule create \ --resource-group $RG \ --nsg-name nsg-app \ --name allow-storage-service-endpoint \ --priority 100 \ --direction Outbound \ --access Allow \ --protocol Tcp \ --destination-address-prefixes Microsoft.Storage \ --destination-port-ranges 443 # 全アウトバウンドを拒否するルール(Service Endpoint許可より低い優先度) $ az network nsg rule create \ --resource-group $RG \ --nsg-name nsg-app \ --name deny-all-outbound \ --priority 4096 \ --direction Outbound \ --access Deny \ --protocol "*" \ --destination-address-prefixes "*" \ --destination-port-ranges "*" # ルール一覧の確認 $ az network nsg rule list \ --resource-group $RG \ --nsg-name nsg-app \ --query "[].{Name:name, Priority:priority, Direction:direction, Access:access, DestAddr:destinationAddressPrefix}" \ --output table Name Priority Direction Access DestAddr ------------------------------ -------- --------- ------ ----------------- allow-storage-service-endpoint 100 Outbound Allow Microsoft.Storage deny-all-outbound 4096 Outbound Deny *
--destination-address-prefixes Microsoft.StorageはAzureが管理するサービスタグで、Storage関連のIPレンジ全体を意味します。IPアドレスを手動でメンテナンスせずにStorageへのアウトバウンドを許可できます。Key Vaultを使う場合は同様にMicrosoft.KeyVaultのルールも追加してください。Private EndpointサブネットのNSGポリシーについて:2021年4月以降、AzureはPrivate EndpointのサブネットにもNSGが適用されるよう仕様が変更されました(
PrivateEndpointNetworkPolicies が既定で Enabled)。それ以前に構築した環境では Disabled になっている場合があり、NSGのルールが意図どおりに機能しないことがあります。Private Endpointを運用中の環境では以下のコマンドで確認してください。# Private Endpointサブネットのポリシー設定を確認 $ az network vnet subnet show \ --resource-group $RG \ --vnet-name $VNET_NAME \ --name $SUBNET_PE \ --query privateEndpointNetworkPolicies \ --output tsv # Enabled(NSGが有効)または Disabled(2021年以前の古い設定) # Disabledの場合はEnabledに変更する $ az network vnet subnet update \ --resource-group $RG \ --vnet-name $VNET_NAME \ --name $SUBNET_PE \ --private-endpoint-network-policies Enabled
# Private Endpointサブネット用NSGを作成 $ az network nsg create \ --resource-group $RG \ --name nsg-pe # アプリサブネットからのHTTPS(443)のみ許可するインバウンドルール $ az network nsg rule create \ --resource-group $RG \ --nsg-name nsg-pe \ --name allow-appsubnet-to-blob \ --priority 100 \ --direction Inbound \ --protocol Tcp \ --source-address-prefix 10.0.1.0/24 \ --destination-port-range 443 \ --access Allow # その他のインバウンドを拒否 $ az network nsg rule create \ --resource-group $RG \ --nsg-name nsg-pe \ --name deny-all-inbound \ --priority 200 \ --direction Inbound \ --protocol "*" \ --source-address-prefix "*" \ --destination-port-range "*" \ --access Deny # NSGをPrivate Endpointサブネットに適用 $ az network vnet subnet update \ --resource-group $RG \ --vnet-name $VNET_NAME \ --name $SUBNET_PE \ --network-security-group nsg-pe
よくあるトラブルと対処法
1. 「This request is not authorized to perform this operation」エラーが出る(サブネット内VMから)
Service Endpointを有効化したが、Storageアカウント側のネットワークルールが未設定、またはDefaultActionがDenyになっていない状態です。# 現在のネットワークルールを確認 $ az storage account show \ --name $STORAGE_ACCOUNT \ --resource-group $RG \ --query networkRuleSet # virtualNetworkRulesにサブネットが含まれているか確認 # 含まれていない場合はnetwork-rule addを再実行する $ az storage account network-rule add \ --resource-group $RG \ --account-name $STORAGE_ACCOUNT \ --vnet-name $VNET \ --subnet $SUBNET
2. サブネットへのService Endpoint有効化がPermission Deniedになる
サブネットを更新するにはVNet全体へのMicrosoft.Network/virtualNetworks/write権限が必要です。Contributorロールまたはカスタムロールが付与されているか確認してください。# 現在のロール割り当てを確認 $ az role assignment list \ --assignee $(az account show --query user.name -o tsv) \ --scope /subscriptions/$(az account show --query id -o tsv) \ --query "[].{Role:roleDefinitionName}" \ --output table Role ---------- Contributor
3. VNetピアリング先から接続できない
Service Endpointは、設定したサブネットと同一VNet内のみ有効です。VNetピアリング越しの別VNetからはService Endpointは使えません。ピアリング越しのアクセスが必要な場合は、Private Endpointへの切り替えを検討してください。# 接続元のIPアドレスを確認(ピアリング先VMなど) $ ip addr show eth0 | grep "inet " inet 10.1.0.4/24 # 別VNetの場合はService Endpointが適用されない # 対処方法: そのIPレンジをipRulesとして個別追加するか、Private Endpointへ移行 $ az storage account network-rule add \ --resource-group $RG \ --account-name $STORAGE_ACCOUNT \ --ip-address 10.1.0.4
4. NSGがService Endpointのトラフィックをブロックしている
NSGに全アウトバウンドDenyルールがある場合、Service Endpointのトラフィックも遮断されます。VMに適用中のNSGルールを確認し、サービスタグを使ったアウトバウンド許可ルールを追加してください。# VMのNICに適用されているNSGの有効ルールを確認 $ az network nic list-effective-nsg \ --resource-group $RG \ --name
\ --query "effectiveSecurityRules[?direction=='Outbound'].{Name:name,Priority:priority,Access:access,DestAddr:destinationAddressPrefix}" \ --output table # DenyAllが先に評価されている場合は、より低い優先度番号のAllowルールを追加する $ az network nsg rule create \ --resource-group $RG \ --nsg-name nsg-app \ --name allow-storage-service-endpoint \ --priority 100 \ --direction Outbound \ --access Allow \ --protocol Tcp \ --destination-address-prefixes Microsoft.Storage \ --destination-port-ranges 443
5. ネットワークルールの変更が即座に反映されない
az storage account network-rule addやaz storage account update --default-action Denyを実行した直後は、変更の伝播に30秒~2分程度かかる場合があります。変更後すぐに接続テストしてもエラーになる場合は、1分程度待ってから再試行してください。# ネットワークルール変更後、反映を待ってからテスト $ az storage account update \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --default-action Deny # 60秒待機してからcurlで確認 $ sleep 60 $ curl -s -o /dev/null -w "%{http_code}" \ "https://${STORAGE_ACCOUNT}.blob.core.windows.net/?restype=account&comp=properties" \ -H "x-ms-version: 2020-10-02" 403 # 403が返れば変更が反映されている
az storage account show --query networkRuleSet.virtualNetworkRules[].stateでSucceededが返っていても、バックエンドへの伝播が完了するまでに数十秒かかることがある点も覚えておいてください。6. Private Endpointを設定したのにdigでグローバルIPが返る
Private EndpointにプライベートIPが割り当てられているにもかかわらず、VMから名前解決をするとグローバルIPが返る場合、原因は以下の3点のどれかです。・Private DNS ZoneのVNetリンク未設定:DNS Zoneを作成しただけでVNetにリンクしていないと、VNet内のVMはPrivate DNS Zoneを参照しない
・DNSゾーングループの設定漏れ:ゾーングループを作成しないとAレコードがPrivate DNS Zoneに自動登録されない
・VMのDNSリゾルバが外部を向いている:
/etc/resolv.confのnameserverが168.63.129.16(AzureのプライベートDNS)でなく8.8.8.8等を指していると、Private DNS Zoneが参照されない以下のコマンドで設定状況を確認してください。
# Private DNS ZoneのVNetリンクを確認(Completedが正常) $ az network private-dns link vnet show \ --resource-group $RG \ --zone-name "privatelink.blob.core.windows.net" \ --name "pe-demo-vnet-link" \ --query virtualNetworkLinkState \ --output tsv Completed # 出力がない・エラーになる場合はVNetリンクが未設定 # VNetにリンクされているすべてのゾーンを一覧表示する場合 $ az network private-dns link vnet list \ --resource-group $RG \ --zone-name "privatelink.blob.core.windows.net" \ --output table # DNSゾーングループを確認 $ az network private-endpoint dns-zone-group list \ --resource-group $RG \ --endpoint-name $PE_NAME \ --output table # 出力がなければゾーングループが未設定 # VMのDNSリゾルバ設定を確認(168.63.129.16が正常) $ cat /etc/resolv.conf nameserver 168.63.129.16 # VNet自体のDNSサーバー設定を確認(空欄ならAzureデフォルト168.63.129.16を使用) $ az network vnet show \ --resource-group $RG \ --name $VNET_NAME \ --query "dhcpOptions.dnsServers" \ --output tsv # 出力が空なら問題なし。カスタムDNSが設定されている場合はPrivate DNS Zoneへの転送設定が必要
7. 「AuthorizationFailure」が返る(ネットワークは通っているのにアクセスできない)
Private EndpointはあくまでVNet内の「経路の制御」であり、認証・認可とは独立しています。ネットワーク的に到達できていても、VMのマネージドIDやサービスプリンシパルにStorage BlobのRBACロールが付いていない場合、AuthorizationFailureが返ります。# VMのマネージドIDのプリンシパルIDを確認 $ az vm show \ --resource-group $RG \ --name
\ --query identity.principalId \ --output tsv xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # BlobデータへのReader権限を付与 STORAGE_ID=$(az storage account show \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --query id -o tsv) $ az role assignment create \ --role "Storage Blob Data Reader" \ --assignee <上記のプリンシパルID> \ --scope $STORAGE_ID
Storage Blob Data Contributorロールを付与してください。Private Endpointはネットワーク制御のレイヤー、RBACは認証・認可のレイヤーであり、両方の設定が揃って初めてStorageにアクセスできます。8. パブリックアクセスをDisabledにした後、az storage blobコマンドが届かない
--public-network-access Disabledを設定した後は、Azure CLI実行元のPCやCloud Shellからデフォルトの操作経路(パブリックインターネット経由)でStorageにアクセスできなくなります。管理操作は同VNet内のVMから実行するか、Private Endpoint経由のネットワーク接続が確立された環境から行う必要があります。開発・テスト中に一時的にCLI操作を通したい場合は、作業時のみパブリックアクセスを再度Enabledにして作業後に戻す手順が現実的です。
# 一時的にパブリックアクセスを再開(作業後は必ず元に戻す) $ az storage account update \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --public-network-access Enabled # 操作が完了したら再度無効化 $ az storage account update \ --resource-group $RG \ --name $STORAGE_ACCOUNT \ --public-network-access Disabled
9. Private Endpointの接続が「Pending」のまま承認されない
Private Endpointを作成してもprovisioningStateがPendingのまま進まない場合、接続の手動承認が必要な状態になっています。同一テナント・同一サブスクリプション内のBlob StorageであればAzureが自動承認するため通常は発生しませんが、組織ポリシーで手動承認が有効になっている環境や、クロステナント接続の場合は承認操作が必要です。# Private Endpoint接続の承認状況を確認 $ az network private-endpoint-connection list \ --name $STORAGE_ACCOUNT \ --resource-group $RG \ --type Microsoft.Storage/storageAccounts \ --output table Name PrivateLinkServiceConnectionState ProvisioningState ----------------------------- ----------------------------------- ------------------- pe-demo-blob-connection Pending Succeeded # Pending状態の接続を承認する $ az network private-endpoint-connection approve \ --name pe-demo-blob-connection \ --resource-name $STORAGE_ACCOUNT \ --resource-group $RG \ --type Microsoft.Storage/storageAccounts \ --description "承認"
az network private-endpoint show --query provisioningStateでSucceededに変わったことを確認してください。AWSのVPC Endpointとの設計比較
AWSにも類似機能としてVPC Endpointがあります。Azure Private EndpointはAWSの「Interface型VPC Endpoint」と設計思想が対応しており、Azure Service EndpointはAWSの「Gateway型VPC Endpoint」に近い位置づけです。| 比較項目 | Azure Private Endpoint | AWS Interface VPC Endpoint |
|---|---|---|
| 仕組み | VNet内のサブネットにプライベートNICを作成 | VPCのサブネットにENI(Elastic Network Interface)を作成 |
| DNS設定 | Private DNS Zoneを作成してVNetに手動リンクが必要 | EndpointのPrivate DNS設定をEnabledにするだけで自動設定 |
| NW制御 | NSGをサブネットに適用(2021年以降、既定で有効) | Security Groupをエンドポイントに直接アタッチ |
| クロス環境アクセス | VNetピアリング・VPN・ExpressRoute経由で到達可能 | VPCピアリング・Transit Gateway経由で到達可能 |
| 承認フロー | 同一テナントは自動承認、クロステナントは手動承認 | 同一アカウントは自動承認、クロスアカウントは手動承認 |
本記事のまとめ
| やりたいこと | コマンド |
|---|---|
| サブネットにService Endpointを有効化 | az network vnet subnet update --service-endpoints Microsoft.Storage |
| Service Endpointの有効化を確認 | az network vnet subnet show --query serviceEndpoints |
| Storageのネットワークルールにサブネットを追加 | az storage account network-rule add --vnet-name vnet --subnet subnet |
| StorageのデフォルトアクションをDenyに設定 | az storage account update --default-action Deny |
| 現在のネットワークルールを確認 | az storage account show --query networkRuleSet |
| Key VaultにService Endpointを適用 | az keyvault network-rule add --vnet-name vnet --subnet subnet |
| 複数サービスを同時に有効化 | az network vnet subnet update --service-endpoints Microsoft.Storage Microsoft.KeyVault |
| NSGにサービスタグでアウトバウンド許可ルールを追加 | az network nsg rule create --destination-address-prefixes Microsoft.Storage |
| VMに適用中のNSGルールを確認 | az network nic list-effective-nsg --resource-group RG --name NIC名 |
| Private Endpointを作成(Blob) | az network private-endpoint create --group-id blob |
| Private Endpointを作成(Azure SQL) | az network private-endpoint create --group-id sqlServer |
| Private Endpointに割り当てられたIPを確認 | az network private-endpoint show --query "customDnsConfigs" -o json |
| Private DNS Zoneを作成(Blob用) | az network private-dns zone create --name privatelink.blob.core.windows.net |
| Private DNS Zoneを作成(SQL用) | az network private-dns zone create --name privatelink.database.windows.net |
| DNS ZoneをVNetにリンク | az network private-dns link vnet create --registration-enabled false |
| VNetリンク状態を確認 | az network private-dns link vnet show --query virtualNetworkLinkState |
| DNSゾーングループでAレコードを自動登録 | az network private-endpoint dns-zone-group create |
| DNSゾーンのAレコード一覧を確認 | az network private-dns record-set a list --zone-name "privatelink.blob.core.windows.net" |
| VMからDNS解決を確認(プライベートIPが返ればOK) | dig storageaccount.blob.core.windows.net |
| VMからnslookupでDNS解決を確認(dig代替) | nslookup storageaccount.blob.core.windows.net |
| Private EndpointへのTCP疎通確認 | nc -zv <Private EndpointのプライベートIP> 443 |
| VNet内VMからBlobコンテナー一覧を取得 | az storage container list --account-name NAME --auth-mode login |
| VNet内VMからBlobをアップロードして書き込み疎通を確認 | az storage blob upload --account-name NAME --container-name CONTAINER --name FILE --file PATH --auth-mode login |
| BlobデータへのRBAC権限付与 | az role assignment create --role "Storage Blob Data Reader" --assignee <プリンシパルID> --scope <ストレージID> |
| Private EndpointサブネットのNSGポリシーを確認 | az network vnet subnet show --query privateEndpointNetworkPolicies |
| VNetのDNSサーバー設定を確認 | az network vnet show --query "dhcpOptions.dnsServers" |
| Private Endpoint接続の承認状況を確認 | az network private-endpoint-connection list --type Microsoft.Storage/storageAccounts |
| Pending状態のPrivate Endpoint接続を手動承認 | az network private-endpoint-connection approve --type Microsoft.Storage/storageAccounts |
| パブリックネットワークアクセスを無効化 | az storage account update --public-network-access Disabled |
| VMのDNSリゾルバ設定を確認(168.63.129.16が正常) | cat /etc/resolv.conf |
NATゲートウェイとプライベートサブネットの組み合わせについては「AzureでNATゲートウェイとプライベートサブネットを構築する方法」で詳しく解説しています。
NSGによるサブネットのトラフィック制御は「AzureのNSGとSSH公開鍵認証でLinux VMを安全に保護する方法」を参照してください。
VNet内のDNS名前解決の設計については「AzureのPrivate DNSゾーンを設定する方法」をあわせて確認することをお勧めします。
Azure対応セミナーの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます