Azure Blob Storage をプライベート エンドポイントで閉域化したのに、アプリから HTTPS 接続すると証明書のホスト名不一致で失敗する…この原因は URL の選び方と DNS の仕組みにあります。本記事では最短で直す方法と、DNS の裏側を具体例付きで整理します。
起きている症状:RemoteCertificateNameMismatch の正体
ストレージ アカウントに対してプライベート エンドポイントを作成し、パブリック アクセス(Public network access)を無効化した環境で、アプリやツールが次のような URL を使ってアクセスしているとします。
| アクセスに使っている URL(例) | 結果 |
|---|---|
https://<account>.privatelink.blob.core.windows.net/... | SSL/TLS でホスト名不一致(RemoteCertificateNameMismatch)になりやすい |
エラーメッセージの典型例は次のとおりです(表現はランタイムやライブラリで多少変わります)。
- SSL policy errors:
RemoteCertificateNameMismatch - 要求ホスト名:
<account>.privatelink.blob.core.windows.net - 証明書のサブジェクト:
CN=*.blob.core.windows.net
これは「暗号化(HTTPS)はできているが、相手が本当に目的のサービスかを確認するためのホスト名検証に失敗している」状態です。つまり、アプリ側が指定したホスト名と、サーバが提示する証明書の対象ホスト名が一致していないことが原因です。
結論:アプリが使うべきホスト名は public 側の FQDN
プライベート エンドポイントを使う場合でも、アプリがアクセスに使うべき URL は次の形式です。
ポイントは「privatelink を URL に書かない」ことです。Azure Storage が提示するサーバ証明書は通常 *.blob.core.windows.net に対して有効なワイルドカード証明書であり、*.privatelink.blob.core.windows.net 用の証明書を返す設計にはなっていません。したがって、クライアントが <account>.blob.core.windows.net に対して接続すれば、証明書のホスト名が一致してエラーは解消します。
| やること | 具体例 | ねらい |
|---|---|---|
| アプリの接続先 URL を修正 | https://<account>.blob.core.windows.net | 証明書の対象(*.blob.core.windows.net)と一致させる |
| DNS を正しく設定 | プライベート DNS ゾーンを VNet にリンク | 同じ FQDN のまま、VNet 内ではプライベート IP に到達させる |
なぜ privatelink を直接使うと証明書が合わないのか(TLS の基本)
HTTPS の通信では、単に暗号化するだけでなく「接続先が本当に意図した相手か」を確認します。その確認の一つが ホスト名検証です。具体的には、クライアントがアクセスした FQDN(例:<account>.privatelink.blob.core.windows.net)が、サーバ証明書の SAN(Subject Alternative Name)または CN(Common Name)に含まれているかをチェックします。
今回のケースでは、サーバが提示する証明書が CN=*.blob.core.windows.net です。ワイルドカードは「同一階層の 1 ラベルだけ」を代表するため、次のような関係になります。
| 接続先ホスト名 | CN=*.blob.core.windows.net に一致する? | 理由 |
|---|---|---|
mystorage.blob.core.windows.net | 一致 | * が mystorage に該当する |
mystorage.privatelink.blob.core.windows.net | 一致しない | * で吸収できるのは 1 ラベルだけで、mystorage.privatelink は対象外 |
そのため、URL に privatelink を入れてしまうと、暗号化そのものは成功しても「証明書がそのホスト名を保証していない」と判断され、RemoteCertificateNameMismatch になります。これはセキュリティ上とても重要なチェックなので、基本的に回避(無効化)すべきではありません。
プライベート エンドポイント時の DNS:裏側で何が起きているか
「じゃあ、なぜプライベート DNS ゾーン privatelink.blob.core.windows.net を作るのか?」という疑問が出やすいのですが、ここは DNS の流れを押さえると腑に落ちます。プライベート エンドポイントを作成したときの基本的な名前解決は、次の二段構えでできています。
public 側:CNAME が privatelink 側へ誘導する
まず public の名前解決では、次のような CNAME が存在する(または同等の誘導が行われる)イメージです。
<account>.blob.core.windows.net
CNAME <account>.privatelink.blob.core.windows.net
ここで重要なのは、クライアントは最初に <account>.blob.core.windows.net を引くという点です。クライアントが最初から privatelink を指定する必要はありません。
VNet 内:privatelink 側をプライベート IP に解決する
次に、VNet にリンクされたプライベート DNS ゾーン(privatelink.blob.core.windows.net)が、CNAME の行き先である FQDN をプライベート IP に解決します。
<account>.privatelink.blob.core.windows.net
A 10.x.x.x(プライベート エンドポイントの IP)
これにより、アプリが URL を変えなくても、VNet 内からはプライベート エンドポイントの IP に到達できるようになります。通信経路がプライベートに切り替わっても、TLS のホスト名検証は「<account>.blob.core.windows.net」で行われるため、証明書エラーも起きません。
流れを図で整理
文章だけだと混乱しやすいので、名前解決と接続先の関係を簡易図で整理します。
(アプリが指定する URL)
https://<account>.blob.core.windows.net/...
│ ① 名前解決(VNet 内)
▼
<account>.blob.core.windows.net
│ ② CNAME
▼
<account>.privatelink.blob.core.windows.net
│ ③ Private DNS Zone の A レコード
▼
10.x.x.x(Private Endpoint の NIC)
│ ④ HTTPS 接続(SNI/Host は <account>.blob.core.windows.net)
▼
Azure Storage(証明書: *.blob.core.windows.net)
結果として、アプリは常に public の FQDN を使い続けるのが正解で、DNS が「public ルートか private ルートか」を切り替えてくれます。これが Azure Private Link の狙いどころです。
「結局 .blob.core.windows.net を使うのはなぜ?」への答え
疑問の核心はここです。
- プライベート DNS ゾーンの名前は
privatelink.blob.core.windows.net - でもアプリは
<account>.blob.core.windows.netを使う
一見すると矛盾しているように見えますが、実際は役割分担が違うだけです。
| 要素 | 何のためにある? | 誰が直接使う? |
|---|---|---|
<account>.blob.core.windows.net | アプリ/SDK/ツールが「いつもの Azure Storage」として扱うための正規のエンドポイント | アプリ(開発者が設定する) |
<account>.privatelink.blob.core.windows.net | Private Link による名前解決の“受け皿”(CNAME の行き先) | DNS(裏側で参照される) |
| プライベート DNS ゾーン | VNet 内で privatelink 側 FQDN をプライベート IP に解決する | ネットワーク管理(運用が設定する) |
要するに、アプリは API の表側(public FQDN)だけを見ていればよく、閉域化は DNS とネットワーク側で吸収するという設計です。URL を変えずに「public → private」へ切り替えられるため、移行や運用が圧倒的に楽になります。
設定の確認ポイント:これだけ押さえれば迷いにくい
実務では「URL は直したのに、まだつながらない」というケースが多いです。原因の多くは DNS です。以下のチェックリストで切り分けると、復旧が速くなります。
| チェック項目 | 期待する状態 | よくある失敗 |
|---|---|---|
| アプリの URL | <account>.blob.core.windows.net を使用 | privatelink を直書きしてしまう |
| プライベート DNS ゾーン | privatelink.blob.core.windows.net が存在 | ゾーン未作成、名前を誤る、別サブスクリプションに作る |
| VNet リンク | 対象 VNet にゾーンがリンクされている | 別 VNet にリンク、リンク漏れ |
| A レコード | <account>.privatelink.blob.core.windows.net がプライベート IP を指す | 自動登録されていない、手動作成ミス |
| クライアントの DNS | VNet の DNS(Azure 提供または正しいフォワーダ)を参照 | オンプレ DNS のままで privatelink ゾーンに到達しない |
| ストレージ側のネットワーク設定 | public 無効でも、Private Endpoint 経由で到達できる | サブリソース(blob/file 等)を間違えて PE 作成 |
社内 DNS(カスタム DNS)を使っている場合は特に注意
VNet の DNS サーバを独自(オンプレや IaaS 上の DNS)にしている環境では、privatelink.blob.core.windows.net の名前解決ができず、結果として public 側に向かってしまうことがあります。public を無効化していると、ここでタイムアウトや 403、名前解決の揺れが発生しやすくなります。
典型的な対処は次のいずれかです。
- 社内 DNS に 条件付きフォワーダを設定し、
privatelink.blob.core.windows.net(必要なら他の privatelink ゾーンも)を Azure 側へ転送する - Azure 側に Azure DNS Private Resolver を立て、オンプレから privatelink ゾーンを引けるようにする
- 簡易的には、VNet 内のリソースだけ Azure 提供 DNS を参照する構成へ戻す(要件次第)
運用現場では「アプリの URL を直したのに直らない」よりも「DNS フローが想定と違う」ほうが圧倒的に多いので、まずは名前解決の結果を目で確認するのが近道です。
実際の確認方法:nslookup だけで切り分けできる
VNet 内の VM や App Service(VNet 統合)など、実際にアクセスする場所から名前解決を確認します。目的は単純で、<account>.blob.core.windows.net がプライベート IP に解決されることです。
Windows(PowerShell)
Resolve-DnsName <account>.blob.core.windows.net
# 参考:CNAME の先も確認したい場合
Resolve-DnsName .privatelink.blob.core.windows.net
Linux(nslookup / dig)
nslookup <account>.blob.core.windows.net
dig +short <account>.blob.core.windows.net
期待する結果は、10.* や 172.16.*、192.168.* といった プライベート IP が返ることです。もし public IP 側に解決されるなら、プライベート DNS ゾーンのリンクやフォワーディングが効いていません。
証明書の確認(OpenSSL)
「今つながっている先が本当に Storage か」「提示される証明書は何か」を確認したいときは、OpenSSL の SNI を明示すると分かりやすいです。
openssl s_client -connect <account>.blob.core.windows.net:443 -servername <account>.blob.core.windows.net
出力の中で subject が CN=*.blob.core.windows.net のようになっていれば、証明書は期待どおりです。ここで -servername を省略すると SNI が省かれ、環境によっては別の証明書が見えることがあるので、検証時は明示するのが安全です。
よくある落とし穴:証明書の問題に見えて DNS の問題
最後に、現場でよく遭遇する「似た症状」をまとめます。エラーメッセージが SSL でも、原因が DNS・プロキシ・接続先の作法にあることが珍しくありません。
| 症状 | ありがちな原因 | 対処 |
|---|---|---|
RemoteCertificateNameMismatch | privatelink を URL に直書き、または IP 直指定 | URL を <account>.blob.core.windows.net に戻す |
| タイムアウト/接続不可 | 名前解決が public 側へ行っている(public 無効化のため到達できない) | Private DNS ゾーン・VNet リンク・DNS フォワーダを見直す |
| 環境によってつながったりつながらなかったりする | DNS キャッシュ、複数 DNS サーバの応答差、VPN 経由の分岐 | クライアントの DNS 設定を統一し、キャッシュをクリアして再検証 |
| SDK だけ失敗する/ツールは成功する | プロキシが Host ヘッダを書き換える、SDK のカスタムエンドポイント設定が誤り | プロキシ設定と SDK の endpoint を点検(Host が変わっていないか) |
「IP アドレスで直接叩けば速い」は危険
プライベート IP を引けると、つい https://10.x.x.x/ のように IP 直指定で試したくなります。しかしこれは高確率で証明書エラーになります(証明書は IP を保証していないため)。トラブルシュートでも、基本は FQDN を使ったまま確認しましょう。
どうしても privatelink の FQDN を使いたい場合の現実解
結論から言うと、Azure Storage に「*.privatelink.blob.core.windows.net の証明書を返して」と要求して切り替えられる仕組みは基本的にありません。ですので、アプリ側で privatelink を直書きし続けたい場合は、別のコンポーネントで “証明書を合わせる” ことになります。ただし構成が複雑になり、運用コストも上がるため、強い理由がない限り推奨はしません。
| 選択肢 | 概要 | 向いているケース | 注意点 |
|---|---|---|---|
| 推奨:URL を public FQDN に戻す | DNS に任せて private に誘導 | ほとんどのケース | DNS 設計が正しく必要 |
| リバースプロキシで TLS 終端 | 社内向け FQDN の証明書をプロキシに設定し、背後で Storage に接続 | どうしても独自ドメイン/独自証明書を使いたい | プロキシ運用が必要、性能・可用性設計が増える |
| ホスト名検証を無効化 | 証明書のホスト名チェックをスキップ | 原則おすすめしない | 中間者攻撃リスクが跳ね上がる |
Private Link のメリットは「アプリの URL を変えずに閉域化できる」点にあります。無理に privatelink を URL に露出させるほど、設計の利点を削ってしまうため、基本方針としては public FQDN を維持するのが最も堅牢です。
SDK・ツールでの実践メモ(URL を迷わないために)
最後に、開発者が迷いやすいポイントを整理します。特に SDK を使う場合、設定項目の名前が “endpoint” だったり “URL” だったりして、誤って privatelink を指定してしまうことがあります。
| 対象 | 基本の指定 | 避けたい指定 |
|---|---|---|
| Azure SDK(BlobServiceClient など) | https://<account>.blob.core.windows.net | https://<account>.privatelink.blob.core.windows.net |
| 接続文字列 | AccountName / AccountKey(または MSI)中心 | EndpointSuffix を独自にいじって privatelink に寄せる |
| AzCopy / CLI | https://<account>.blob.core.windows.net の URL を入力 | privatelink を URL に含める |
閉域化の実装はネットワーク(Private Endpoint)と DNS(Private DNS zone)で実現し、アプリコードは “いつもの Azure Storage” として扱う。ここを徹底すると、環境差分(開発・検証・本番)に強い構成になります。
まとめ:解決の最短ルート
- アプリの接続先 URL は
<account>.blob.core.windows.netを使う(privatelinkを直書きしない) - VNet 内で同じ FQDN が プライベート IP に解決されるよう、Private DNS ゾーンと DNS 連携を整える
nslookup/Resolve-DnsNameで「どこに解決されているか」を最初に確認すると、原因切り分けが速い
プライベート エンドポイントは “接続先 URL を変える仕組み” ではなく、“同じ URL を安全にプライベート経路へ切り替える仕組み” です。URL と DNS の役割分担を理解しておくと、証明書エラーだけでなく、閉域化後の接続トラブル全般を短時間で解決できるようになります。

コメント